No release in over 3 years
Background per-core CPU monitoring for Ruby/Rails applications. Reads /proc/stat on Linux (Heroku) or top on macOS. Writes a rotating 1 MB JSON-lines log per dyno. On single dynos the file backend is used; on multi-dyno Heroku deployments the Redis backend aggregates all dynos into a single CpuInspectCore.status view. Ships with a Rails Railtie for zero-config boot and a CLI executable for bash usage.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme

CpuInspectCore

A Ruby gem that monitors CPU usage per core in the background and displays results as ASCII progress bars — designed for profiling Heroku dynos.

Runs a lightweight background thread, writes a rotating 1 MB JSON log, and exposes a single method you can call from a Rails console or bash at any time. On multi-dyno Heroku deployments the optional Redis backend aggregates all dynos into one view.


Contents

  • How it works
  • Installation
  • Quick start
  • Rails integration
  • Multi-dyno on Heroku (Redis backend)
  • CLI
  • Configuration reference
  • Development

How it works

A background thread samples /proc/stat on Linux (Heroku) or top on macOS at a configurable interval (default 2 s). Each sample is:

  • stored in an in-process ring buffer for instant status reads
  • appended as a JSON line to a rotating local log (1 MB cap, keeps newest 50%)
  • optionally written to Redis tagged with the Heroku $DYNO identifier

CpuInspectCore.status reads the ring buffer and prints one progress bar per core:

=== web.1 @ 2026-04-15T10:00:02.341Z ===
cpu0  ||||||||||||||||||||||||                            48.2%
cpu1  idle
cpu2  ||||||||||||||||||||||||||||||||||||||||||||||||    95.4%
cpu3  |||                                                 6.1%

On a scaled Heroku deployment with the Redis backend enabled, calling status shows every live dyno in one shot — no SSH needed.


Installation

Add to your Gemfile:

gem "cpu-inspect-core"

For multi-dyno Redis support also add:

gem "redis", "~> 5.0"

Then:

bundle install

Or install globally:

gem install cpu-inspect-core

Requires Ruby 3.1 or higher. No other runtime dependencies.


Quick start

require "cpu_inspect_core"

CpuInspectCore.start          # launches background thread

sleep 5                       # let it collect a few samples

CpuInspectCore.status         # print progress bars
CpuInspectCore.tail(lines: 10) # print last 10 raw JSON log lines

CpuInspectCore.stop

From a Rails console:

CpuInspectCore.status

The gem auto-starts via its Railtie when Rails boots, so status is ready as soon as your app is up.


Rails integration

Drop a file at config/initializers/cpu_inspect_core.rb:

CpuInspectCore.configure do |c|
  c.interval       = 2.0    # seconds between samples
  c.idle_threshold = 2.0    # cores below this % are shown as "idle"
  c.bar_width      = 50     # character width of the progress bar
end

The Railtie calls CpuInspectCore.start automatically after the Rails logger is ready. Set CPU_INSPECT_CORE_DISABLED=1 to opt out (useful in test environments or during asset precompilation).

Puma with preload_app!

Threads do not survive fork. If you use preload_app! in config/puma.rb, add:

on_worker_boot do
  CpuInspectCore.start
end

Multi-dyno on Heroku (Redis backend)

By default each dyno writes only to its local /tmp file. To see all dynos in one status call, enable the Redis backend:

# config/initializers/cpu_inspect_core.rb
CpuInspectCore.configure do |c|
  c.backend = :redis
  # c.redis_url defaults to ENV["REDIS_URL"] — set automatically by Heroku Redis add-on
end

Each dyno writes its latest sample to a Redis key named cpu_inspect_core:<dyno> (e.g. cpu_inspect_core:web.1) with a 30-second TTL. When a dyno scales down or restarts its key expires automatically.

Viewing all dynos

From a one-off dyno or any Rails console session:

CpuInspectCore.status

Output on a 5-dyno deployment:

=== web.1 @ 2026-04-15T10:00:02.341Z ===
cpu0  ||||||||||||||||||||||||                            48.2%
cpu1  idle

=== web.2 @ 2026-04-15T10:00:02.198Z ===
cpu0  ||||||||||||||||||||||||||||||||||||||||||||||||    95.4%
cpu1  |||||||||||||||||||||||||||||||                     61.8%

=== web.3 @ 2026-04-15T10:00:02.512Z ===
cpu0  idle
cpu1  idle

=== web.4 @ 2026-04-15T10:00:02.089Z ===
cpu0  |||||||||||||||||||                                 38.7%
cpu1  ||||||||||||                                        24.1%

=== web.5 @ 2026-04-15T10:00:02.763Z ===
cpu0  |||||||||||||||||||||||||||||||||||||               73.0%
cpu1  |||||||||||||||||||||||||||||||||||||||||||||||     93.2%

This tells you how many physical vCPU cores each dyno has and how hard they are working — useful for choosing the right dyno type and size.

Redis configuration options

Option Default Description
redis_url ENV["REDIS_URL"] Redis connection URL
redis_key_prefix "cpu_inspect_core" Namespace for all Redis keys
redis_ttl 30 Seconds before a dead dyno's key expires

CLI

The cpu-inspect-core executable is available after installation.

bundle exec cpu-inspect-core [options]
Flag Description
--once Print status once and exit
--watch Refresh status continuously (clears screen each cycle)
--tail [N] Print last N lines from the local log file (default 20)
--interval SECS Override the sample interval
--log PATH Override the log file path

Examples:

# Print current CPU snapshot
bundle exec cpu-inspect-core --once

# Live dashboard that refreshes every 2 seconds
bundle exec cpu-inspect-core --watch

# Inspect the raw JSON log
bundle exec cpu-inspect-core --tail 30

# Run at a faster rate
bundle exec cpu-inspect-core --watch --interval 0.5

Configuration reference

All options are set via CpuInspectCore.configure:

CpuInspectCore.configure do |c|
  c.interval         = 2.0                         # sample interval in seconds
  c.log_path         = "/tmp/cpu_inspect_core.log"  # local log file (per dyno)
  c.log_max_bytes    = 1_048_576                   # rotate when log exceeds this (1 MB)
  c.idle_threshold   = 2.0                         # % below which a core shows as "idle"
  c.bar_width        = 50                          # progress bar width in characters
  c.backend          = :file                       # :file or :redis
  c.redis_url        = ENV["REDIS_URL"]            # Redis connection URL
  c.redis_key_prefix = "cpu_inspect_core"           # Redis key namespace
  c.redis_ttl        = 30                          # seconds before dyno key expires
end

The log path can also be set via environment variable: CPU_INSPECT_CORE_LOG=/path/to/log.


Development

git clone https://github.com/mykbren/cpu-inspect-core
cd cpu-inspect-core
bundle install
bundle exec rake test

Run a single test file:

bundle exec ruby -Ilib -Itest test/test_renderer.rb

Run a single test by name:

bundle exec ruby -Ilib -Itest test/test_renderer.rb -n test_cores_are_sorted_numerically_not_lexicographically

The test suite targets 100% line and branch coverage (verified by SimpleCov on every run).


License

MIT — Copyright (c) 2026 Mykyta Bren