Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions apps/api/src/lib/metrics/event-loop-metrics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { performance } from "node:perf_hooks";
import { Gauge } from "prom-client";

import { metricsRegistry } from "./registry";

/*
* Event Loop Utilization (ELU).
*
* Matteo Collina's argument (and the wider Node.js community's): event
* loop lag is *the* leading indicator of a Node service's health,
* because CPU and memory don't tell you whether the loop can actually
* dispatch callbacks. Lag (already collected by `collectDefaultMetrics`
* as `nodejs_eventloop_lag_*_seconds`) measures *how late* callbacks
* run. ELU goes one step further: it measures *how saturated* the loop
* is, on a 0.0–1.0 scale.
*
* - 0.0 → loop idle (no JS executing, only waiting on I/O)
* - 0.5 → loop is busy half the time
* - 1.0 → loop is fully saturated, no headroom
*
* Sustained >0.9 means the next burst will tip you into queueing
* requests. Use as a paging signal alongside lag p99.
*
* `eventLoopUtilization()` is cumulative since process start; we diff
* against the previous sample on each scrape so the gauge reflects
* the *interval* utilisation, not the all-time average.
*/
let previousElu = performance.eventLoopUtilization();

export const nodejsEventLoopUtilization = new Gauge({
name: "nodejs_eventloop_utilization",
help: "Event loop utilization since the previous scrape (0.0–1.0). >0.9 sustained = no headroom.",
registers: [metricsRegistry],
collect() {
const next = performance.eventLoopUtilization(previousElu);

this.set(next.utilization);

previousElu = performance.eventLoopUtilization();
},
});
1 change: 1 addition & 0 deletions apps/api/src/lib/metrics/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { nodejsEventLoopUtilization } from "./event-loop-metrics";
export { httpRequestDurationSeconds, httpRequestsTotal } from "./http-metrics";
export { metricsRegistry } from "./registry";
Loading
Loading