애플리케이션 메트릭 노출 및 RED 방법
Prometheus 형식으로 요청률, 오류 및 지속 시간 메트릭을 게시하고 의미 있는 SLI를 정의합니다.
애플리케이션 메트릭 노출 및 RED 방법은(는) CoddyKit의 무료 Node.js Backend Development Bootcamp 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Node.js Backend Development Bootcamp 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Node.js Backend Development Bootcamp 강의에는 총 4개의 강의가 포함되어 있습니다.
이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.
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);Introducing the RED Method
The RED method is a focused recipe for monitoring request-driven services. For every service you track three signals:
- R — Rate: requests per second the service is handling.
- E — Errors: rate of failed requests (typically HTTP 5xx, sometimes 4xx).
- D — Duration: distribution of how long requests take (latency).
RED is the request-side complement to USE (Utilization, Saturation, Errors) which targets resources like CPU and disk. For an HTTP API, RED maps almost perfectly onto user-facing experience: throughput, failure rate, and latency.
The elegant part: all three derive from instrumenting just one thing — the request lifecycle.
Installing prom-client
In Node.js the de-facto library is prom-client. It manages a registry of metrics and renders them in Prometheus format. It also ships default metrics (event loop lag, heap usage, GC) that you enable with one call.
Create a single shared registry so every part of your app registers into the same place.
const client = require('prom-client');
const register = new client.Registry();
register.setDefaultLabels({ app: 'orders-api' });
// Node.js runtime metrics: event loop lag, heap, GC, fd count...
client.collectDefaultMetrics({ register });
module.exports = { client, register };R — A Counter for Request Rate
Rate is not stored directly. You store a monotonic counter of total requests, and Prometheus computes the per-second rate at query time with rate(http_requests_total[1m]).
Give the counter labels for method, route, and status_code. Crucially, use the route template (/users/:id) and not the raw URL (/users/42) — otherwise every id becomes a new time series and your cardinality explodes.
const client = require('prom-client');
const httpRequestsTotal = new client.Counter({
name: 'http_requests_total',
help: 'Total number of HTTP requests',
labelNames: ['method', 'route', 'status_code'],
});
// On each finished request:
httpRequestsTotal.inc({
method: 'GET',
route: '/users/:id', // template, NOT /users/42
status_code: '200',
});D — A Histogram for Duration
Duration needs a histogram so you can compute percentiles (p50, p95, p99). A histogram counts observations into predefined buckets (upper bounds in seconds). Choose buckets that span your expected latency range.
A histogram automatically exposes three series per label set: _bucket, _sum, and _count. From _sum and _count you also get the average; from _bucket you estimate quantiles with histogram_quantile().
const client = require('prom-client');
const httpRequestDuration = new client.Histogram({
name: 'http_request_duration_seconds',
help: 'HTTP request duration in seconds',
labelNames: ['method', 'route', 'status_code'],
// Tuned for a typical web API (5ms .. 5s)
buckets: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5],
});
// Observe a completed request that took 0.137s
httpRequestDuration.observe(
{ method: 'GET', route: '/users/:id', status_code: '200' },
0.137
);One Middleware to Capture R, E, and D
The whole point of RED is that a single piece of instrumentation feeds all three signals. An Express-style middleware starts a timer, lets the request run, then on res.finish records the count and duration with the status code as a label.
Errors need no separate metric — they are just the counter filtered by status_code=~"5.." at query time. This is framework code (Express), so treat it as a reference pattern rather than a standalone program.
function metricsMiddleware(req, res, next) {
const end = httpRequestDuration.startTimer({ method: req.method });
res.on('finish', () => {
// req.route?.path gives the template, e.g. '/users/:id'
const route = (req.route && req.route.path) || req.path;
const labels = {
method: req.method,
route,
status_code: String(res.statusCode),
};
httpRequestsTotal.inc(labels);
end(labels); // stops timer and records duration with these labels
});
next();
}
app.use(metricsMiddleware);Exposing the /metrics Endpoint
Prometheus pulls metrics, so you must expose them over HTTP. Add a GET /metrics route that returns register.metrics() with the correct content type. This is the endpoint you list as a scrape target in prometheus.yml.
Keep this endpoint internal (bind to a private interface or protect it) — it can leak operational detail and is a tempting DoS target.
const { register } = require('./metrics');
app.get('/metrics', async (req, res) => {
res.set('Content-Type', register.contentType);
res.end(await register.metrics());
});
// prometheus.yml scrape config:
// scrape_configs:
// - job_name: 'orders-api'
// scrape_interval: 15s
// static_configs:
// - targets: ['orders-api:3000']Querying RED with PromQL
Once data is flowing, you express each RED signal as a PromQL query for dashboards and alerts:
- Rate:
sum(rate(http_requests_total[5m])) by (route) - Errors (ratio):
sum(rate(http_requests_total{status_code=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) - Duration (p95):
histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
Note the error ratio is a fraction of total requests, not a raw count. An error rate of 0.02 means 2% of requests failed — far more meaningful than "40 errors" with no denominator.
From Metrics to SLIs and SLOs
A Service Level Indicator (SLI) is a precisely defined measure of service health, usually expressed as good events / valid events. RED metrics are exactly the raw material for SLIs:
- Availability SLI: non-5xx responses / total responses.
- Latency SLI: requests faster than 300ms / total requests.
A Service Level Objective (SLO) is a target for an SLI over a window, e.g. "99.9% of requests succeed over 30 days." The complement of the SLO is your error budget (0.1%), which tells you how much failure you can tolerate before you must stop shipping features and fix reliability.
Computing a Latency SLI From Buckets
A latency SLI like "fraction of requests under 300ms" comes straight from histogram bucket counts: take the cumulative count in the le="0.3" bucket and divide by the total count. Here is a standalone simulation of that computation over two scrape samples.
// Cumulative bucket counts from a histogram, le = upper bound (seconds)
const sample = {
total: 10000,
buckets: {
'0.1': 6000,
'0.3': 9700, // 9700 requests finished within 300ms
'1.0': 9990,
'+Inf': 10000,
},
};
function latencySLI(s, thresholdLabel) {
const good = s.buckets[thresholdLabel];
return good / s.total;
}
const sli = latencySLI(sample, '0.3');
console.log('Latency SLI (<300ms): ' + (sli * 100).toFixed(2) + '%');
console.log('Meets 99% SLO? ' + (sli >= 0.99));Quick Check
Test your understanding of cardinality and the RED method.
Recap
You can now expose meaningful application metrics in Prometheus format and reason about them with the RED method.
- Counter, Gauge, Histogram are the core metric types;
prom-clientmanages a registry and renders the exposition format. - RED = Rate, Errors, Duration — all three fall out of instrumenting the request lifecycle once, in a single middleware.
- Rate comes from a counter via
rate(); Errors are that counter filtered bystatus_code=~"5.."; Duration comes from a histogram viahistogram_quantile(). - Always label by route template, never raw URLs, to control cardinality.
- Expose metrics at
/metricsand let Prometheus scrape it; keep the endpoint internal. - Turn RED metrics into SLIs (good/valid events), set SLOs, and track your error budget.
자주 묻는 질문
“애플리케이션 메트릭 노출 및 RED 방법” 강의는 무료인가요?
네 — “애플리케이션 메트릭 노출 및 RED 방법” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Node.js Backend Development Bootcamp 강의 전체를 잠금 해제할 수 있습니다. Node.js Backend Development Bootcamp 강의에는 총 4개의 강의가 포함되어 있습니다.
“애플리케이션 메트릭 노출 및 RED 방법”에서 뭘 배우나요?
Prometheus 형식으로 요청률, 오류 및 지속 시간 메트릭을 게시하고 의미 있는 SLI를 정의합니다. 브라우저에서 직접 실행하는 실습 코드로 Node.js Backend Development Bootcamp을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Node.js Backend Development Bootcamp을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Node.js Backend Development Bootcamp은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.
“애플리케이션 메트릭 노출 및 RED 방법” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Node.js Backend Development Bootcamp 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Node.js Backend Development Bootcamp 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 상관관계 ID를 활용한 구조화된 로깅
- OpenTelemetry 스팬을 활용한 분산 추적
- 애플리케이션 메트릭 노출 및 RED 방법
- AsyncLocalStorage를 활용한 컨텍스트 전파