--- name: metrics-exposition description: >- Use when adding or reviewing a /metrics endpoint, choosing metric labels, or diagnosing a monitoring system that is growing without bound: which labels are cardinality decisions, capping high-cardinality views, exporting the fact that you truncated, and provisioning dashboards from the repository. --- # Metrics exposition: bounded cardinality, and truncation you can see **Read [`references/METRICS-EXPOSITION.md`](references/METRICS-EXPOSITION.md) before applying any of this.** That file is the standard; everything below it is a summary to help you decide whether this skill applies and to check your work afterwards. Reference-architecture principles: P15. ## What this standard covers - Every label is a cardinality decision - High-cardinality dimensions are opt-in and capped - Export the fact that you truncated - Emit sums and counts, not averages - The endpoint is a surface; it can be closed - Dashboards are provisioned, not clicked ## Failure modes | Symptom | Cause | |---|---| | Prometheus memory climbs steadily and never recovers | A label carrying ids from your data — session, user, request, a path with an id in it. Each distinct value is a permanent series (§1) | | Monitoring costs more than the service it monitors | The same, discovered on a bill rather than in a graph | | A panel's numbers are confidently wrong, and nothing looks broken | The exporter truncated and never said so, so the dashboard is rendering a capped view as if it were complete (§3) | | A rollup across instances disagrees with the per-instance panels | Pre-averaged gauges being averaged again — an average of averages (§4) | | Cardinality is fine in staging and explodes in production | The high-cardinality view is default-on; staging simply never had enough distinct values to show it (§2) | | An error-type label grows without bound | `type` sourced from an exception name or a remote error string: bounded by what dependencies say, which is not a bound you hold (§1) | | Nobody can rebuild the dashboard after the monitoring stack is recreated | It was clicked together in a UI and never provisioned from the repository (§6) | ## Checklist - [ ] Every label answers "what bounds its distinct values, and who enforces that bound?" — a label bounded only by your data does not ship as it stands - [ ] High-cardinality views are off by default, with the reason written at the switch - [ ] Each such view has a configured ceiling and a stated rule for which entries win when it is reached - [ ] Open-ended label values (error types, and anything sourced from a dependency's strings) are top-N capped by volume - [ ] The exporter emits its own ceiling **and** its own drop count as series, so a truncated view is visible on the dashboard built from it - [ ] Scores and latencies are exported as `_sum`/`_count` pairs rather than pre-averaged gauges - [ ] Serving `/metrics` is a configuration decision with an off switch - [ ] Datasource, dashboard JSON and scrape config are provisioned from the repository, not assembled in a UI --- Generated from [`docs/guides/METRICS-EXPOSITION.md`](https://github.com/konradcinkusz/architecture-standards/blob/main/docs/guides/METRICS-EXPOSITION.md) by `scripts/build-marketplace.mjs`. Do not edit this file: change the source document, or its entry in `catalog/marketplace.catalog.json`, and re-run the generator.