the-tip-top-backend/node_modules/prom-client/lib/metrics/eventLoopLag.js
2025-10-22 20:40:47 +00:00

144 lines
3.9 KiB
JavaScript

'use strict';
const Gauge = require('../gauge');
// Check if perf_hooks module is available
let perf_hooks;
try {
perf_hooks = require('perf_hooks');
} catch {
// node version is too old
}
// Reported always.
const NODEJS_EVENTLOOP_LAG = 'nodejs_eventloop_lag_seconds';
// Reported only when perf_hooks is available.
const NODEJS_EVENTLOOP_LAG_MIN = 'nodejs_eventloop_lag_min_seconds';
const NODEJS_EVENTLOOP_LAG_MAX = 'nodejs_eventloop_lag_max_seconds';
const NODEJS_EVENTLOOP_LAG_MEAN = 'nodejs_eventloop_lag_mean_seconds';
const NODEJS_EVENTLOOP_LAG_STDDEV = 'nodejs_eventloop_lag_stddev_seconds';
const NODEJS_EVENTLOOP_LAG_P50 = 'nodejs_eventloop_lag_p50_seconds';
const NODEJS_EVENTLOOP_LAG_P90 = 'nodejs_eventloop_lag_p90_seconds';
const NODEJS_EVENTLOOP_LAG_P99 = 'nodejs_eventloop_lag_p99_seconds';
function reportEventloopLag(start, gauge, labels) {
const delta = process.hrtime(start);
const nanosec = delta[0] * 1e9 + delta[1];
const seconds = nanosec / 1e9;
gauge.set(labels, seconds);
}
module.exports = (registry, config = {}) => {
const namePrefix = config.prefix ? config.prefix : '';
const labels = config.labels ? config.labels : {};
const labelNames = Object.keys(labels);
const registers = registry ? [registry] : undefined;
let collect = () => {
const start = process.hrtime();
setImmediate(reportEventloopLag, start, lag, labels);
};
if (perf_hooks && perf_hooks.monitorEventLoopDelay) {
try {
const histogram = perf_hooks.monitorEventLoopDelay({
resolution: config.eventLoopMonitoringPrecision,
});
histogram.enable();
collect = () => {
const start = process.hrtime();
setImmediate(reportEventloopLag, start, lag, labels);
lagMin.set(labels, histogram.min / 1e9);
lagMax.set(labels, histogram.max / 1e9);
lagMean.set(labels, histogram.mean / 1e9);
lagStddev.set(labels, histogram.stddev / 1e9);
lagP50.set(labels, histogram.percentile(50) / 1e9);
lagP90.set(labels, histogram.percentile(90) / 1e9);
lagP99.set(labels, histogram.percentile(99) / 1e9);
histogram.reset();
};
} catch (e) {
if (e.code === 'ERR_NOT_IMPLEMENTED') {
return; // Bun
}
throw e;
}
}
const lag = new Gauge({
name: namePrefix + NODEJS_EVENTLOOP_LAG,
help: 'Lag of event loop in seconds.',
registers,
labelNames,
aggregator: 'average',
// Use this one metric's `collect` to set all metrics' values.
collect,
});
const lagMin = new Gauge({
name: namePrefix + NODEJS_EVENTLOOP_LAG_MIN,
help: 'The minimum recorded event loop delay.',
registers,
labelNames,
aggregator: 'min',
});
const lagMax = new Gauge({
name: namePrefix + NODEJS_EVENTLOOP_LAG_MAX,
help: 'The maximum recorded event loop delay.',
registers,
labelNames,
aggregator: 'max',
});
const lagMean = new Gauge({
name: namePrefix + NODEJS_EVENTLOOP_LAG_MEAN,
help: 'The mean of the recorded event loop delays.',
registers,
labelNames,
aggregator: 'average',
});
const lagStddev = new Gauge({
name: namePrefix + NODEJS_EVENTLOOP_LAG_STDDEV,
help: 'The standard deviation of the recorded event loop delays.',
registers,
labelNames,
aggregator: 'average',
});
const lagP50 = new Gauge({
name: namePrefix + NODEJS_EVENTLOOP_LAG_P50,
help: 'The 50th percentile of the recorded event loop delays.',
registers,
labelNames,
aggregator: 'average',
});
const lagP90 = new Gauge({
name: namePrefix + NODEJS_EVENTLOOP_LAG_P90,
help: 'The 90th percentile of the recorded event loop delays.',
registers,
labelNames,
aggregator: 'average',
});
const lagP99 = new Gauge({
name: namePrefix + NODEJS_EVENTLOOP_LAG_P99,
help: 'The 99th percentile of the recorded event loop delays.',
registers,
labelNames,
aggregator: 'average',
});
};
module.exports.metricNames = [
NODEJS_EVENTLOOP_LAG,
NODEJS_EVENTLOOP_LAG_MIN,
NODEJS_EVENTLOOP_LAG_MAX,
NODEJS_EVENTLOOP_LAG_MEAN,
NODEJS_EVENTLOOP_LAG_STDDEV,
NODEJS_EVENTLOOP_LAG_P50,
NODEJS_EVENTLOOP_LAG_P90,
NODEJS_EVENTLOOP_LAG_P99,
];