Correlate signals
Sometimes you genuinely need a high-cardinality value, like a request ID, when you’re debugging. The answer isn’t to delete it, and it isn’t to put it on a metric label. It’s to put the value on the signal designed to hold it, and correlate across signals when you investigate.
The pattern
When a high-cardinality value is attached to a metric label, every unique value multiplies your active series. The same value attached to a log costs a fraction of that, because Loki doesn’t index log content. Here’s how to use structured metadata to keep your metrics low-cardinality and by leveraging logs:
- Keep the metric low-cardinality. The metric answers “how many” and “how fast” per bounded dimension, such as
serviceandstatus. - Put the high-cardinality detail on the correlated log. Attach it as structured metadata, or leave it in the log line. The log answers “which exact request”.
- Correlate at query time. Shared bounded labels, such as
serviceandenv, connect the metric that alerted you to the logs that explain it.
A working example
Suppose you track request latency and want to find slow requests for specific users.
- Instead of
http_request_duration_seconds{user_id="u-48221", ...}, which creates a series per user per label combination, - keep the metric as
http_request_duration_seconds{service="checkout", env="prod"}, - and log each request with
user_idandrequest_idattached as structured metadata.
When latency spikes, the metric tells you where and when. Then you query the logs for that service and window, filtering by structured metadata: {app="checkout"} | user_id="u-48221". You keep full debugging detail without paying for it on every series.
Take it further with traces
If you also collect traces, the same pattern extends to a third signal using exemplars. An exemplar is a trace ID attached alongside a metric sample, not as a label, so the metric stays low-cardinality while a latency spike becomes one click away from the exact slow trace.
- Attach the trace ID to the metric as an exemplar, not a label.
- Keep the trace ID on logs as structured metadata, so logs link to the same trace.
Exemplars require a tracing backend such as Tempo, and exemplar support enabled on your metrics data source.
Why this works
Each signal is priced and indexed for a different job. Metrics are cheap per series but multiply by label combinations. Logs carry arbitrary detail, and structured metadata makes high-cardinality fields queryable without indexing them. Traces hold per-request detail natively, and exemplars link them to your metrics without adding labels. Putting each value where it belongs is what a labeling strategy actually is; not fewer data points, just the right home for each one.
You now have the complete strategy across both signals. The last milestone recaps the frameworks and suggests more topics to explore.
More to explore (optional)
At this point in your journey, you can explore the following topics: