import client from 'prom-client';
import type { RequestHandler } from 'express';
export const httpDuration = new client.Histogram({
name: 'http_request_duration_seconds',
help: 'HTTP request duration in seconds',
labelNames: ['method', 'route', 'status'] as const,
buckets: [0.01, 0.05, 0.1, 0.25, 0.5, 1, 2, 5]
});
export const metricsMiddleware: RequestHandler = (req, res, next) => {
const end = httpDuration.startTimer();
res.on('finish', () => {
const route = (req.route && req.route.path) ? String(req.route.path) : req.path;
end({ method: req.method, route, status: String(res.statusCode) });
});
next();
};
export async function metricsHandler(_req: any, res: any) {
res.setHeader('Content-Type', client.register.contentType);
res.send(await client.register.metrics());
}
During an incident, the first question is usually ‘is it getting worse?’, and log lines don’t answer that well. Prometheus-style metrics make it easy to track rates and percentiles over time. I instrument request duration as a histogram and label by method, route, and status class. The trick is controlling label cardinality—don’t label by user id or raw URL, or your metrics backend will hate you. I also expose a /metrics endpoint that’s protected (or internal-only) so I’m not handing out operational data publicly. With a small amount of code, you get dashboards and alerts that make on-call much less stressful and performance work much more measurable.