mig

module
v0.4.0-rc2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 5, 2026 License: MIT

README

mig — message inspector general

A live TUI for inspecting NATS message flow. Point it at a subject (Core or JetStream), see rates, volumes, last-message timing, top subjects, JSON health, and an inferred schema sketch with numeric histograms. The layout adapts: paginated in small terminals, a tiled grid in large ones.

   ╭─ Total ─╮ ╭─ Rate ──────────╮ ╭─ Last seen ─────────────╮
   │  1,234  │ │ ↑ 12.5 msg/s    │ │ 0.3s ago  evt.foo  18B  │
   │ 56.7KB  │ │ 60s avg 8.4     │ │ {"id":1,"v":42}         │
   ╰─────────╯ ╰─────────────────╯ ╰─────────────────────────╯
   ╭─ Msgs/s ─────────────────────────────────────────────────╮
   │ ▁▂▂▃▄▄▆▇█▇▇▇▆▅▅▆▇▇█▇▆▆▅▄▄▃▃▂▁▁▁▁▁▂▃▄▄▅▆▆▇█▇▆▅            │
   │ peak 47/s · window 120s                                  │
   ╰──────────────────────────────────────────────────────────╯

Install

Pre-built, signed binaries (Linux/macOS/Windows × x86_64/arm64) are on the releases page. Each release ships SBOMs and a cosign-signed checksums.txt.bundle; verification recipe is in CONTRIBUTING.md.

If you have module access (this repository is private), go install also works:

GOPRIVATE=github.com/panevain/* go install github.com/panevain/mig/cmd/mig@latest

Or build from source:

git clone https://github.com/panevain/mig
cd mig
make build
./mig --help

Usage

Point at a subject; mig auto-detects whether the server has JetStream and which stream covers your filter:

# Local NATS, all subjects
mig

# Specific subject filter
mig -S 'evt.>'

# Multiple filters, explicit server
mig -s nats://nats.example:4222 -S 'orders.*' -S 'payments.*'

# Force Core NATS (no JetStream)
mig --core -S '>'

# Pin to a specific stream and replay everything
mig --stream EVENTS -S 'evt.>' --all

# Replay last 5 minutes
mig --stream EVENTS --since 5m

# Pipe-friendly mode: no TUI, one JSON message per line on stdout
mig --no-tui -S 'evt.>' | jq .
Benching locally

End-to-end bench against real NATS in two commands:

docker compose --profile bench up -d --build   # NATS + BENCH stream + publisher
./mig                                          # consume, watch the tiles light up

The bench profile starts three services: nats (JetStream-enabled server), nats-init (one-shot stream creator), and nats-pub (the cmd/migbench publisher, built in-tree via cmd/migbench/Dockerfile). It emits realistic JSON with rotating event types, randomized user/region/currency/tags, and incrementing ids — so JSON Health tile shows ~100% parseable, the schema sketch fills out, and Top subjects spreads across bench.x.0..bench.x.9. Tune with env vars before bringing the stack up:

BENCH_RATE=10000 BENCH_SUBJECTS=50 docker compose --profile bench up -d --build

For a faster dev loop without rebuilding the container on every code change, run the publisher natively against a NATS-only stack:

docker compose up -d                  # NATS only (no init, no pub)
make bench-pub                        # ./cmd/migbench against localhost:4222

Tear down with docker compose --profile bench down -v (the -v wipes JS state). Monitoring is on localhost:8222 (e.g., curl localhost:8222/varz).

On Linux hosts where Docker's bridge networking is flaky (Fedora / nftables / firewalld in particular), copy compose.override.yaml.example to compose.override.yaml to switch every bench service to host networking. Linux-only — leave it as .example on macOS/Windows.

Auth
# JWT + nkey
mig --creds ~/.nats/user.creds

# nkey only
mig --nkey ~/.nats/user.nk

# Username + password (also picks up NATS_PASSWORD env)
mig --user observer --password $TOKEN

# TLS
mig --tlscert client.crt --tlskey client.key --tlsca ca.crt

# Existing nats CLI context (opt-in)
mig --context production

Tiles

Tile What you see
Header Connection status dot, server URL, source kind (core/jetstream + stream), uptime, drop count, recent error count
Total Lifetime message count + total bytes
Rate Current msg/s (5s EMA) + 60s EMA + jitter stddev. Up/down/flat trend arrow
Msgs/s sparkline 120-second history of msg/s with peak marker
Bytes Bytes/s (5s EMA) + 60s avg + small inline byte sparkline
Last seen Age of last message (red when older than --stale), subject, JSON-pretty preview
Top subjects Up to 10 busiest subjects with counts and last-seen ages
JSON health % parseable, ok/bad counts, count of valid-but-non-object payloads
Schema sketch Inferred JSON paths with types, numeric range/μ/p50 + histogram, string distinct count + example
Drops Red banner only visible when slow-consumer drops have occurred

Layout

mig adapts to terminal size automatically:

Width × Height Layout
< 40 × 10 "resize me" message
< 60 wide or < 16 tall One tile per page; tab / arrows cycle
60–119 × 16–29 2-column grid, 2 pages
120–179 × ≥ 30 3-column grid, all tiles visible
≥ 180 4-column grid, big sparkline, expanded subjects/schema

Keys

Key Action
q, Ctrl-C Quit
tab, , l Next page (paginated layouts)
shift-tab, , h Previous page
r Reset all stats and schema (uptime preserved)
p Pause UI rendering (data still recorded)
s Open the settings overlay (color scheme picker)
? Toggle the keyboard help overlay

Settings & themes

mig ships three color schemes — default, solarized-dark, high-contrast — and remembers your choice and a few behavior knobs across runs.

# List available themes
mig --theme=?

# Pick at startup
mig --theme solarized-dark

# Adjust the rate sparkline window (in seconds, default 120, range 8..600)
mig --spark-seconds 300

# Widen the histogram reservoir (per-path numeric samples, default 256, range 16..4096)
mig --hist-samples 1024

Inside the TUI, press s to open the settings overlay. The overlay has two sections:

  • Theme/ moves between themes, enter applies the highlighted one. Live update.
  • Behavior — refresh interval, stale threshold (red marker on the Last seen tile), rate sparkline window, and histogram reservoir size (per-path numeric samples feeding min/max/p50/p95/p99 and the histogram). / cycles each value through preset steps; enter advances forward. Refresh and stale take effect immediately; the spark window and histogram reservoir apply on restart (their per-path rings are sized at construction).

Every change writes the full settings file to disk immediately; close the overlay with s or esc.

The persisted file is JSON; resolution order:

  1. --config PATH (CLI flag)
  2. $MIG_CONFIG (environment)
  3. $XDG_CONFIG_HOME/mig/config.json (or ~/.config/mig/config.json if XDG_CONFIG_HOME is unset)

Precedence at startup is flag > config file > built-in default, so any flag on the command line always wins over whatever was last saved. The on-disk schema is intentionally small and additive — new settings appear as new keys without breaking existing files. Stale or invalid file values are warned and ignored rather than blocking startup.

Example config.json:

{
  "theme": "solarized-dark",
  "refresh": "200ms",
  "stale": "5s",
  "spark_seconds": 120,
  "hist_samples": 256
}

Reliability

  • Cold-start with NATS down: mig exits immediately with cannot reach NATS at <url> instead of hanging or surfacing an opaque buffer error. Mid-session drops reconnect forever; header turns red until the connection is back.
  • JetStream auto-detect: if the stream is missing, mig surfaces the available stream list and suggests --core or an explicit --stream. JS-disabled servers fall back to Core silently.
  • Slow-consumer drops increment a counter and pop the Drops tile/banner.
  • Malformed JSON is counted (bad=N) but never crashes anything; the LastSeen tile still renders the raw bytes.
  • Subject and schema-path tracking are bounded (--max-subjects, --max-paths) with eviction so high-cardinality streams don't OOM mig.

Flag reference

mig --help

All flags: see mig --help. Highlights:

  • --refresh DURATION (default 200ms, min 50ms) — UI tick interval
  • --stale DURATION (default 5s) — red threshold on last-seen
  • --max-subjects N (default 256) — bounded top-N subject map
  • --max-paths N (default 512) — bounded schema path tracker
  • --schema-sample F (default 1.0) — fraction of valid JSON fed into the schema engine
  • --no-tui — flat one-line-per-message stdout for piping/grepping
  • --json-pretty — pretty-print JSON in --no-tui mode
  • --theme NAME — color scheme; --theme=? lists names (default: default)
  • --config PATH — user config file path; defaults to $MIG_CONFIG or $XDG_CONFIG_HOME/mig/config.json
  • --spark-seconds N (default 120, range 8..600) — width of the rate sparkline ring
  • --hist-samples N (default 256, range 16..4096) — per-path numeric reservoir feeding min/max/quantiles and the histogram. Larger = more recent history retained at the cost of memory (~N × 8B × max-paths)

Contributing

Contributions welcome — see CONTRIBUTING.md. For security issues, please use private reporting per SECURITY.md.

License

MIT

Directories

Path Synopsis
cmd
mig command
Command mig — message inspector general — is a live NATS message-flow TUI.
Command mig — message inspector general — is a live NATS message-flow TUI.
migbench command
Command migbench publishes synthetic, varying JSON traffic into NATS to drive mig during local benchmarking.
Command migbench publishes synthetic, varying JSON traffic into NATS to drive mig during local benchmarking.
internal
config
Package config holds the CLI surface for mig: flag parsing, environment fallbacks, and the Config struct passed into the source/metrics/tui layers.
Package config holds the CLI surface for mig: flag parsing, environment fallbacks, and the Config struct passed into the source/metrics/tui layers.
metrics
Package metrics records mig's per-message observations and produces snapshots for the TUI to render.
Package metrics records mig's per-message observations and produces snapshots for the TUI to render.
schema
Package schema infers a sketch schema (paths, types, numeric histograms, string cardinality) from JSON-valid messages flowing through mig.
Package schema infers a sketch schema (paths, types, numeric histograms, string cardinality) from JSON-valid messages flowing through mig.
source
Package source bridges NATS (Core or JetStream) into mig's Sink interface.
Package source bridges NATS (Core or JetStream) into mig's Sink interface.
tui
Package tui hosts the Bubble Tea root model, theme, message types, and the tile renderers that draw mig's live dashboard.
Package tui hosts the Bubble Tea root model, theme, message types, and the tile renderers that draw mig's live dashboard.
tui/theme
Package theme defines the lipgloss styles used by all mig tiles.
Package theme defines the lipgloss styles used by all mig tiles.
tui/tiles
Package tiles holds the per-panel renderers used by the mig TUI.
Package tiles holds the per-panel renderers used by the mig TUI.
userconf
Package userconf is mig's on-disk user config: a small JSON file that persists settings the user has chosen interactively (e.g.
Package userconf is mig's on-disk user config: a small JSON file that persists settings the user has chosen interactively (e.g.
version
Package version exposes build identifiers populated via -ldflags at link time.
Package version exposes build identifiers populated via -ldflags at link time.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL