npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

node-eventloop-watchdog

v1.0.0

Published

Lightweight Node.js event loop blocking detector with automatic code identification, blocking heatmaps, and production-safe diagnostics

Readme

node-eventloop-watchdog

Detect when the Node.js event loop is blocked and identify the code causing it.

  • ✔ Detect event loop lag
  • ✔ Capture blocking stack traces
  • ✔ Identify blocking hotspots
  • ✔ Correlate with HTTP requests
  • ✔ Production safe
⚠ Event Loop Blocked

  Duration: 142ms
  Route: POST /checkout

  Suspected Blocking Operation
  JSON.stringify large object

  Location
  checkoutService.js:84

Blocking Hotspots

Find which files repeatedly block the event loop — ranked by frequency.

Top Blocking Files

1. reportService.js:142
   Blocks: 18
   Max Lag: 221ms

2. orderController.js:51
   Blocks: 7
   Max Lag: 94ms
watchdog.getBlockingHotspots();
// [
//   { file: "reportService.js", line: 142, blocks: 18, maxLag: 221 },
//   { file: "orderController.js", line: 51, blocks: 7, maxLag: 94 }
// ]

Install

npm install node-eventloop-watchdog

Quick Start

const watchdog = require('node-eventloop-watchdog');

watchdog.start();

That's it. Warnings are logged automatically when the event loop is blocked.

Configuration

watchdog.start({
  warningThreshold: 40,         // ms — warn when lag exceeds this
  criticalThreshold: 100,       // ms — error when lag exceeds this
  captureStackTrace: true,      // capture stack traces on block
  historySize: 50,              // recent blocks to keep
  enableMetrics: true,          // collect lag + memory metrics
  detectBlockingPatterns: true, // detect JSON, sync fs, crypto, etc.
  checkInterval: 20,            // ms — poll interval
  logLevel: 'warn',             // debug | info | warn | error | silent
  jsonLogs: false,              // structured JSON output
  logger: null,                 // custom logger(level, message, data)
  onBlock: null                 // callback(event) on every block
});

| Option | Type | Default | Description | |---|---|---|---| | warningThreshold | number | 50 | Lag (ms) before warning | | criticalThreshold | number | 100 | Lag (ms) before critical alert | | captureStackTrace | boolean | true | Capture stack traces | | historySize | number | 50 | Max blocking events retained | | enableMetrics | boolean | true | Collect lag metrics and memory snapshots | | detectBlockingPatterns | boolean | true | Detect known blocking patterns | | checkInterval | number | 20 | Poll interval (ms) | | logLevel | string | 'warn' | Min log level | | jsonLogs | boolean | false | JSON log output | | logger | function | null | Custom logger function | | onBlock | function | null | Block event callback |

API

watchdog.start(config?)

Start monitoring. Returns the watchdog instance for chaining.

watchdog.stop()

Stop monitoring.

watchdog.getStats()

watchdog.getStats();
// {
//   avgLag: 12, maxLag: 121, minLag: 1,
//   totalBlocks: 14, blocksLastMinute: 6,
//   uptime: 3600, running: true,
//   memory: { heapUsed: 412, heapTotal: 512, rss: 580, external: 12, arrayBuffers: 2 }
// }

watchdog.getRecentBlocks(count?)

watchdog.getRecentBlocks(5);
// [
//   {
//     duration: 84,
//     severity: 'warning',
//     location: 'checkoutService.js:84',
//     suspectedOperation: 'JSON.stringify',
//     request: { route: 'POST /checkout', requestId: 'req_92KxS' },
//     memory: { heapUsed: 412, heapTotal: 512, rss: 580 }
//   }
// ]

watchdog.getBlockingHotspots(limit?)

watchdog.getBlockingHotspots();
// [
//   { file: 'reportService.js', line: 142, blocks: 18, maxLag: 221, avgLag: 145 },
//   { file: 'orderController.js', line: 51, blocks: 7, maxLag: 94, avgLag: 62 }
// ]

watchdog.getHistory()

Full blocking event history.

watchdog.reset()

Clear all history, hotspots, and metrics.

watchdog.middleware()

Express/Fastify-compatible middleware for request correlation.

watchdog.on(event, listener) / watchdog.off(event, listener)

Subscribe/unsubscribe to 'block' events.

watchdog.on('block', (event) => {
  alerting.notify('event-loop-block', event);
});

watchdog.createInspector()

Create an independent instance (not the singleton).

const custom = watchdog.createInspector();
custom.start({ warningThreshold: 100 });

Automatic Blocking Detection

Identifies what caused the block:

| Pattern | Category | |---|---| | JSON.stringify / JSON.parse | Serialization | | fs.readFileSync, fs.writeFileSync, etc. | Sync FS | | crypto.pbkdf2Sync, crypto.scryptSync | Sync Crypto | | zlib.*Sync | Sync Compression | | child_process.execSync, spawnSync | Sync Exec | | RegExp.exec | Regex Backtracking |

Express / Fastify Middleware

const express = require('express');
const watchdog = require('node-eventloop-watchdog');

const app = express();
watchdog.start();
app.use(watchdog.middleware());

app.post('/checkout', (req, res) => {
  // Block events will include: { route: 'POST /checkout', requestId: '...' }
  res.json({ ok: true });
});

Works with Express, Fastify, and any Connect-compatible framework. Koa requires an adapter.

Integration with node-request-trace

If node-request-trace is installed, blocking events are automatically correlated with the active request — no setup needed.

// Blocking events include:
// {
//   request: {
//     requestId: 'req_92KxS',
//     route: 'GET /users',
//     method: 'GET',
//     userId: '83921'
//   }
// }

Integration with node-actuator-lite

If node-actuator-lite is installed, endpoints are registered automatically:

| Endpoint | Description | |---|---| | GET /actuator/eventloop | Status, metrics, top hotspots | | GET /actuator/eventloop/history | Recent blocking events | | GET /actuator/eventloop/hotspots | Hotspot ranking | | GET /actuator/eventloop/metrics | Lag and memory metrics |

JSON Logging

watchdog.start({ jsonLogs: true });
{
  "level": "warn",
  "message": "⚠ Event Loop Blocked\n  Duration: 92ms\n  Severity: warning",
  "timestamp": 1710002231,
  "type": "event-loop-block",
  "duration": 92,
  "route": "/orders"
}

Custom Logger

watchdog.start({
  logger: (level, message, data) => {
    myLogger[level](message, data);
  }
});

Event Listener

watchdog.on('block', (event) => {
  if (event.severity === 'critical') {
    pagerDuty.alert({
      summary: `Event loop blocked ${event.duration}ms`,
      source: event.location,
      route: event.request?.route
    });
  }
});

Production Config

watchdog.start({
  warningThreshold: 100,
  criticalThreshold: 500,
  captureStackTrace: false,
  historySize: 20,
  enableMetrics: true,
  detectBlockingPatterns: false,
  checkInterval: 50,
  logLevel: 'error'
});

Performance:

  • < 1% CPU — timer-based polling, no monkey-patching
  • < 5MB memory — bounded history and sample buffers
  • Zero dependencies — only Node.js built-ins
  • Unref'd timers — won't keep the process alive

Compatibility

  • Node.js >= 16.0.0
  • Frameworks: Express, Fastify, Koa, native http
  • OS: Linux, macOS, Windows

License

MIT