Exposing Application Metrics and the RED Method
Publish rate, errors, and duration metrics in Prometheus format and define meaningful SLIs.
Why Metrics Matter
Logs tell you what happened in a single request. Metrics tell you how your whole service is behaving right now and over time. They are cheap to store, aggregate well, and power dashboards and alerts.
A metric is a numeric measurement sampled over time. In a Node.js backend you typically export metrics in Prometheus text format over an HTTP endpoint (conventionally /metrics). Prometheus scrapes that endpoint every few seconds and stores the time series.
- Counter — only goes up (total requests, total errors).
- Gauge — goes up and down (active connections, queue depth).
- Histogram — buckets observations (request durations) to compute quantiles.
The Prometheus Text Format
Before wiring up libraries, it helps to see what the /metrics endpoint actually returns. Each line is metric_name{label="value"} number. The # HELP and # TYPE comment lines describe each metric.
Labels let one metric name carry many dimensions (per route, per status code). Below is a tiny generator that builds this exposition format by hand so you can see exactly what Prometheus parses.
function renderMetrics(samples) {
const lines = [
'# HELP http_requests_total Total HTTP requests',
'# TYPE http_requests_total counter',
];
for (const s of samples) {
const labels = Object.entries(s.labels)
.map(([k, v]) => k + '="' + v + '"')
.join(',');
lines.push('http_requests_total{' + labels + '} ' + s.value);
}
return lines.join('\n');
}
const out = renderMetrics([
{ labels: { method: 'GET', route: '/users', status: '200' }, value: 1024 },
{ labels: { method: 'GET', route: '/users', status: '500' }, value: 7 },
]);
console.log(out);All lessons in this course
- Structured Logging with Correlation IDs
- Distributed Tracing with OpenTelemetry Spans
- Exposing Application Metrics and the RED Method
- Context Propagation with AsyncLocalStorage