Connect bounded RED metrics and SLOs to one question
Observability answers incident questions; it is not a contest to store the most data. Collect Rate, Errors, and Duration by route template, then connect logs and asynchronous work with request context.
Table of contents
Observability answers incident questions; it is not a contest to store the most data. Collect Rate, Errors, and Duration by route template, then connect logs and asynchronous work with request context.
Never use the raw 404 path as a metric label: bots can create unbounded time series. Python backend folds unmatched routes into /_not_found. User IDs, filenames, and search terms must not become labels either.
Collection path and cost
Java services expose Actuator Prometheus endpoints and Python services expose standard /metrics. Compose Prometheus scrapes them only in the optional profile. Grafana and a Next.js-specific exporter remain optional until runtimes and deployment platforms share an operations contract; Next.js can use logs, Sentry, and Web Vitals.
When to promise an SLO
Define an SLO from a user path and baseline. If there is no measurement, do not promise an arbitrary 99.9%; agree on error-budget, deployment-pause, and rollback actions after collecting the baseline.
Label budget
| Value | Metric label | Structured log | Reason |
|---|---|---|---|
| Route template | Allowed | Allowed | Finite route set |
| Method/status class | Allowed | Allowed | Bounded cardinality |
| Request ID | Forbidden | Allowed | Unique per attempt |
| User ID, query, filename | Forbidden | Minimum only | Privacy and unbounded cardinality |
| Exception class | Allowlist | Allowed | Failure type without raw text |
Rate ─┐
Error ├─▶ user-path baseline ─▶ SLO candidate ─▶ error budget ─▶ release decision
Duration┘
Time-series count grows as the product of label value counts. Routes 50 × statuses 5 × methods 4 can be bounded; adding request IDs makes storage and query cost grow with request volume.
Related course: RED, correlation, and SLOs