termiwatch
v1.0.1
Published
Zero-config, one-line terminal dashboard for Node.js apps. Real-time CPU, memory, event loop, HTTP metrics, and logs.
Maintainers
Readme
Why termiwatch?
Most Node.js monitoring tools are either dead, heavy, or require external services:
| Tool | Status | Dependencies | Setup | |------|--------|-------------|-------| | nodejs-dashboard | Archived (2022) | blessed, socket.io | Global install + wrapper | | clinic.js | Dead (3 years) | Native compilation | CLI profiling sessions | | appmetrics-dash | Dead (6 years) | C++ native addon | Code changes + browser | | PM2 monit | Active | Entire PM2 ecosystem | Full process manager | | termiwatch | Active | Zero | One line |
termiwatch gives you Datadog-level metrics in your terminal with zero setup:
- One line —
import "termiwatch/auto"and you're done - Zero dependencies — custom ANSI renderer, no native addons, nothing to break
- 14 metric categories — CPU, memory, event loop, GC pauses, heap spaces, HTTP, network I/O, DNS, worker threads, and more
- 5 dashboard views — Tab to cycle between Overview, Memory, HTTP, Network, and Logs
- Production safe — unref'd timers, TTY detection, alt-screen buffer
- 428 KB total package size
Quick Start
Install
npm install termiwatchUse (pick one)
Option 1 — One line (recommended)
import "termiwatch/auto"
// ... your app code below. That's it.Option 2 — CLI wrapper (zero code changes)
npx termiwatch server.jsOption 3 — Manual API
import { startTermiwatch, stopTermiwatch } from "termiwatch"
const nw = startTermiwatch({ refreshInterval: 500 })
// Later...
const metrics = nw.collectMetrics()
stopTermiwatch()Dashboard Views
Press Tab to cycle between views, Shift+Tab to go back.
1. Overview
Everything at a glance — CPU and memory with braille-resolution sparklines, event loop delay + ELU, GC pause tracking, HTTP req/s, handle leak detection, and live logs.
2. Memory & GC
Deep-dive into memory — full-width braille chart, per-heap-space breakdown (new/old/code/large object), GC pause detail by kind (minor/major/incremental), and a handle leak monitor with trend detection.
3. HTTP
Request throughput — large braille chart of req/s over time, per-status-code breakdown with bars, event loop health, and CPU usage.
4. Network & Workers
Network I/O — active TCP sockets with bytes read/written, DNS lookup timing, worker thread monitoring (per-thread ELU and heap), and async activity levels.
5. Logs
Full-screen log viewer — all captured stdout/stderr/errors with timestamps, color-coded by type, with stats bar.
What It Tracks
| Category | Metrics | Source |
|----------|---------|--------|
| CPU | Usage %, user/system split, history | process.cpuUsage() |
| Memory | RSS, heap used/total, external, array buffers | process.memoryUsage() |
| Event Loop | Mean delay, p99, min, max | perf_hooks.monitorEventLoopDelay() |
| ELU | Event loop utilization (0-100%) | performance.eventLoopUtilization() |
| GC | Pause count, avg/max duration, frequency, kind | PerformanceObserver({ entryTypes: ['gc'] }) |
| Heap Spaces | Per-space size/used/available (new, old, code...) | v8.getHeapSpaceStatistics() |
| Handles | Active count, by type, leak trend | process._getActiveHandles() |
| HTTP | Req/s, total, active, avg latency, status codes | Monkey-patches http.createServer |
| Network | Active sockets, bytes read/written, socket table | Socket stats from active handles |
| DNS | Lookup timing, average resolution time | PerformanceObserver({ entryTypes: ['dns'] }) |
| Workers | Per-thread ELU, heap used/total, status | worker.performance.eventLoopUtilization() |
| Async | Active handles count, pending I/O requests | process._getActiveHandles/Requests() |
| Framework | Auto-detect Express, Fastify, Koa, Hapi, NestJS, Next | require.cache inspection |
| Runtime | Detect nodemon, PM2, tsx, ts-node, --watch, Bun, Deno | Environment variable checks |
Auto-Detection
termiwatch automatically detects your framework and runtime environment — no config needed.
Frameworks: Express, Fastify, Koa, Hapi, NestJS, Next.js
Runtimes: nodemon, PM2 (with instance ID and cluster mode), tsx, ts-node, node --watch, Bun, Deno
Detected framework and runtime are shown as badges in the dashboard header:
⚡ termiwatch │ ● RUNNING │ PID 1234 │ v20.10.0 │ ↑ 2h │ express 4.21.0 │ nodemonAPI Reference
startTermiwatch(config?)
Start monitoring and return the Termiwatch instance.
const nw = startTermiwatch({
refreshInterval: 1000, // ms between updates (default: 1000)
historySize: 60, // data points for sparklines (default: 60)
patchHttp: true, // track HTTP requests (default: true)
patchConsole: true, // capture console output (default: true)
showDashboard: true, // render terminal UI (default: true)
})stopTermiwatch()
Stop monitoring, restore console, clean up.
stopTermiwatch()getTermiwatch()
Get the singleton instance (useful when using termiwatch/auto).
import "termiwatch/auto"
import { getTermiwatch } from "termiwatch"
const nw = getTermiwatch()
const metrics = nw.collectMetrics()nw.collectMetrics()
Returns a complete Metrics snapshot:
const m = nw.collectMetrics()
console.log(m.cpu.usage) // 12.4
console.log(m.memory.heapUsed) // 29360128
console.log(m.eventLoop.p99) // 2.31
console.log(m.eventLoop.utilization) // 0.08
console.log(m.gc.maxPauseMs) // 12.1
console.log(m.http.requestsPerSecond) // 847
console.log(m.network.activeSockets) // 3
console.log(m.workers.count) // 2
console.log(m.handles.trend) // 'stable'
console.log(m.process.framework) // 'express'nw.getLogs()
Returns captured log entries:
const logs = nw.getLogs()
// [{ timestamp: 1711234567890, message: 'Server started', type: 'stdout' }, ...]CLI Usage
# Run any Node.js script with the dashboard
npx termiwatch server.js
# Pass arguments through
npx termiwatch app.js --port 3000 --env production
# Help
npx termiwatch --helpThe CLI wrapper uses --require to preload termiwatch before your code runs — zero modifications needed.
Headless Mode
Use termiwatch for metrics collection without the dashboard:
import { startTermiwatch } from "termiwatch"
const nw = startTermiwatch({ showDashboard: false })
setInterval(() => {
const m = nw.collectMetrics()
// Send to your own monitoring, logging, or alerting system
myLogger.info('metrics', {
cpu: m.cpu.usage,
memory: m.memory.heapUsed,
eventLoopP99: m.eventLoop.p99,
gcMaxPause: m.gc.maxPauseMs,
rps: m.http.requestsPerSecond,
})
}, 5000)termiwatch also skips the dashboard automatically in non-TTY environments (CI, piped output, Docker logs).
How It Works
termiwatch uses only Node.js built-in APIs — no native addons, no external processes:
- Terminal UI: Custom ANSI escape code renderer with Unicode box-drawing characters and braille sparklines (U+2800-U+28FF) for 8x resolution charts
- HTTP tracking: Monkey-patches
http.createServerusing the same APM technique as Datadog and New Relic - Console capture: Wraps
process.stdout.write(notconsole.log) to preserve stack traces - Worker monitoring: Intercepts the
Workerconstructor viaModule._load+Proxyto track threads from the main thread - Production safety: All timers call
.unref(), dashboard renders in alt-screen buffer, TTY detection prevents rendering in CI
Requirements
- Node.js >= 16.0.0
- A terminal with Unicode support (virtually all modern terminals)
FAQ
Minimal impact. Metrics collection uses Node.js built-in APIs (process.cpuUsage(), perf_hooks, v8 module) which are designed for production use. The HTTP monkey-patch adds ~0.01ms per request. The dashboard renders in an alt-screen buffer on a 1s interval with change detection to avoid unnecessary writes. All timers are .unref()'d so termiwatch never keeps your process alive.
Yes. Use showDashboard: false in production to collect metrics without the terminal UI. The dashboard auto-disables in non-TTY environments (Docker, CI, piped output).
No. termiwatch wraps process.stdout.write (not console.log directly), so stack traces, source locations, and debugger integration are preserved. When the dashboard is visible, console output is captured and shown in the Logs panel. When the dashboard exits, original behavior is restored.
Yes. termiwatch auto-detects your framework and patches http.createServer at the Node.js level, so it works with any framework that uses Node's built-in HTTP server — which is all of them.
Yes. termiwatch intercepts the Worker constructor and monitors each thread's event loop utilization and heap usage from the main thread — no code changes in your workers needed. Just make sure termiwatch is imported before worker_threads.
Yes. termiwatch detects these runtimes automatically and shows them in the dashboard header. For PM2, it shows the instance ID and cluster mode.
