Open-Source Wikis

/

Node.js

/

Systems

/

Diagnostics

nodejs/node

Diagnostics

Purpose

Give operators and APM authors observability into a running Node process: async-resource lifecycle (async_hooks, AsyncLocalStorage), library-level events (diagnostics_channel), V8/system performance counters (perf_hooks), categorical traces (trace_events), JSON crash dumps (process.report), and the V8 Inspector (--inspect).

Surfaces

API JS C++
async_hooks lib/async_hooks.js, lib/internal/async_hooks.js src/async_wrap.cc
AsyncLocalStorage lib/internal/async_local_storage/ src/async_context_frame.{cc,h}
diagnostics_channel lib/diagnostics_channel.js src/node_diagnostics_channel.{cc,h}
perf_hooks lib/perf_hooks.js, lib/internal/perf/ src/node_perf.{cc,h}
trace_events lib/trace_events.js src/tracing/, src/node_trace_events.cc
process.report exposed via lib/internal/process/report.js src/node_report.cc, src/node_report_module.cc
inspector module lib/inspector.js, lib/internal/inspector/ src/inspector/, src/inspector_*.{cc,h}
histograms lib/internal/histogram.js src/histogram.{cc,h}
v8.startupSnapshot.* lib/v8.js src/node_snapshotable.cc

async_hooks and AsyncWrap

Every async resource in Node — sockets, FS requests, timers, fs watchers, HTTP parsers — descends from AsyncWrap in C++. AsyncWrap assigns each resource an asyncId and a triggerAsyncId, and threads them through MakeCallback so JS callbacks always run with the correct context.

sequenceDiagram
    participant Wrap as AsyncWrap (e.g. TCPWrap)
    participant Hooks as async_hooks dispatch
    participant Listener as user hook (init/before/after/destroy)

    Wrap-->>Hooks: emitInit(asyncId, type, triggerAsyncId, resource)
    Hooks->>Listener: init(asyncId, type, ...)
    Wrap->>Wrap: produces I/O event
    Wrap-->>Hooks: emitBefore(asyncId)
    Hooks->>Listener: before(asyncId)
    Wrap-->>Hooks: run JS callback
    Wrap-->>Hooks: emitAfter(asyncId)
    Hooks->>Listener: after(asyncId)
    Wrap-->>Hooks: emitDestroy(asyncId) at GC or close
    Hooks->>Listener: destroy(asyncId)

User-facing API: async_hooks.createHook({ init, before, after, destroy, promiseResolve }). Hooks installed at startup are essentially free; hooks that run init on every async resource have measurable cost, so most APMs only enable a subset.

AsyncLocalStorage is the modern public API and prefers the V8 AsyncContextFrame mechanism (src/async_context_frame.cc) when available; the legacy implementation falls back to async_hooks. Implementation detail: --no-async-context-frame toggles between them.

diagnostics_channel

diagnostics_channel (lib/diagnostics_channel.js) is a publish/subscribe API tailored for "library events". A channel name is a string; the 'tracing' subscriber pattern lets subscribers see five lifecycle events (start/end/asyncStart/asyncEnd/error) for an operation.

Built-in channels published by core (see doc/api/diagnostics_channel.md for the full list):

  • dgram.socket
  • net.client.socket / net.server.socket
  • udp.socket.bind
  • child_process lifecycle
  • http.client.request.*, http.server.request.*, http.server.response.*
  • node:worker_threads:create, :exit
  • tracing:net.client.connect, tracing:net.server.listen

undici publishes undici:* channels (request created, headers, error, completion), and the SQLite binding publishes node:sqlite.*.

perf_hooks

lib/perf_hooks.js exposes the WHATWG Performance API plus Node-specific marks (gc, dns, http, function, eventloop). The C++ side (src/node_perf.cc) collects the data; the histograms (src/histogram.cc) back the eventloop-delay and request-rate measurements.

Highlights:

  • performance.eventLoopUtilization() (alias loopUtilization) — measured by sampling the libuv loop.
  • monitorEventLoopDelay({ resolution }) — a sliding histogram backed by node::Histogram.
  • PerformanceObserver — observes entries by type.

trace_events

trace_events (lib/trace_events.js) emits structured trace events in the Chrome trace format. When NODE_USE_V8_PLATFORM is on, the implementation uses the V8 TracingController and writes through src/tracing/ (which is built on perfetto when enabled). Categories include node, v8, node.fs.sync, node.http, node.console, node.async_hooks. Output goes to a JSON file (set via --trace-event-file-pattern).

process.report

--report-on-fatalerror, --report-on-signal, --report-uncaught-exception, and process.report.writeReport() all funnel through src/node_report.cc. The report is a single JSON document with: header (timestamp, pid, command line, OS, node version), JS stack, native stack, libuv handles, environment, resource usage, OS open handles, system errors, user-provided context. Use it as the post-mortem trail when crashes don't reproduce locally.

Inspector

lib/inspector.js exposes Session — a programmatic V8 inspector channel — and open, close, url, waitForDebugger. The C++ side is in src/inspector/:

  • inspector_agent.cc — owns the V8 inspector channel and lifecycle.
  • inspector_io.cc, inspector_socket.cc, inspector_socket_server.cc — WebSocket/TCP transport.
  • inspector_profiler.cc — CPU + heap profiler integration.
  • inspector_js_api.cc — bindings for the JS inspector.Session.
  • inspector_protocol/ — generated protocol stubs (tools/inspector_protocol/ runs the codegen).

Workers share the inspector router (worker_inspector.h) so DevTools can attach to a worker via the same root WebSocket URL.

Integration points

  • Streams publish tracing: channels for connect/data/error events.
  • fs has a tracing:fs channel and trace-events category.
  • HTTP publishes the most channels; both http and undici are well covered.
  • AsyncLocalStorage combines with diagnostics_channel.tracingChannel(...).traceCallback to build per-operation context propagation that survives across awaits.

Entry points for modification

  • New diagnostics_channel? Pick a stable channel name, publish events, document at doc/api/diagnostics_channel.md.
  • New process.report field? Edit src/node_report.cc (the writer is hand-rolled JSON) and doc/api/report.md.
  • Async-hook integration for a new C++ resource? Make sure it inherits from AsyncWrap and calls MakeCallback (src/async_wrap.cc).

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Diagnostics – Node.js wiki | Factory