High cardinality

A field with a huge number of distinct values, like user_id or a raw URL. Usually workable in traces, ruinous as a metric label.

tagging by user blows up the billtoo many unique valueshigh cardinaltiycardinality explosionwhy did my metrics bill go up 10xadding user_id as a labeltoo many label combinationsunique values per field

See it

Live demo coming soon

What it is

Cardinality is just the count of distinct values a field can take. Status code is low cardinality (about a dozen values). user_id, session_id, request URL, and email are high cardinality (millions). The word is most dangerous in metrics, because a time-series database stores one separate series per unique combination of label values. Add user_id to a metric that already has 100 routes and 5 status codes and you did not create one chart, you created millions of series, each with its own memory, index entry, and line item on the invoice.

The fix is not 'avoid high cardinality', it is 'put it in the right store'. Metrics want low-cardinality labels: route template, status class, region. Traces, logs, and wide events are built for the high stuff, and columnar backends (Honeycomb, ClickHouse, most trace storage) will happily let you filter by user_id, which is exactly the question you actually have during an incident: not 'is the error rate up' but 'which customers are hitting this'. That is a difference of degree rather than a free pass. Indexed trace and log attributes still cost storage and can slow queries down in backends that build an index per attribute or per field, so how much a new high-cardinality field actually costs you depends on the specific store, and it is worth checking yours before spraying one everywhere.

Gotcha: the explosion usually sneaks in, it is rarely someone typing user_id on purpose. Raw paths like /orders/8821, error messages with a timestamp inside, Kubernetes pod names that change every deploy, and full user agent strings are the usual culprits. Normalize paths to route templates, strip variable text out of labels, and set whatever series or label limit your particular metrics backend supports, since there is no single portable cap, so one bad deploy cannot take the metrics store down with it.

Ask AI for it

Audit this service's metric labels for cardinality problems and fix them. Define an explicit allow-list of permitted metric label keys and treat anything outside it as prohibited. Normalize raw request paths to route templates (/orders/:id), collapse status codes to status classes (2xx, 4xx, 5xx), and drop user_id, session_id, email, full URL, and user agent from all metric labels. Enforce the allow-list in an OpenTelemetry Collector transform or filter processor so a call site cannot reintroduce a banned label. Move that high-cardinality context onto spans and structured log events instead, where it can still be filtered during an incident. Then, as a separate step, configure whichever series or label limits my metrics backend actually supports, and give me the backend-specific commands for inspecting current cardinality and listing the highest-cardinality label keys, so regressions get caught early.

You might have meant

metriccardinality explosionwide eventsamplingtime series database