Apply labeling strategy to logs
Loki, which powers Grafana Cloud Logs, takes the fewest labels principle further than metrics by indexing only your labels, not the log content, so every label combination splits your logs into another stream to index and store. This milestone gives you the decision framework for what belongs in a label, what belongs in structured metadata, and what stays in the log line.
Labels tell you where
Good log labels describe the origin or context of the log: application, namespace, environment, cluster, region. These are static, bounded, and what you actually filter by when you start a search. Loki performs best with few labels, and the fewer streams you create, the smaller the index and the faster your queries.
Use dynamic labels sparingly
A dynamic label takes its value from the log content, such as level. Use them rarely, and only when all of the following are true:
- The value set is low-cardinality, ideally tens of values.
- The values are long lived, such as the first segment of an HTTP path, not ephemeral IDs.
- Users actually query by the label frequently.
Otherwise, don’t index it. Loki’s filter expressions are fast. {app="api"} |= "level=error" performs comparably to a level label for many workloads, without splitting your streams. Don’t add a label until you know you need it.
The decision framework
For any piece of log data, ask where it belongs.
- If you filter by it in almost every query, and it’s bounded, make it a label. Example:
env,app. - It’s high-cardinality but you query it often, attach it as structured metadata. It’s queryable with a label filter expression, such as
{job="example"} | pod="myservice-abc1234-56789", without being indexed or creating streams. Examples: pod names, process IDs, trace IDs. - Everything else, leave it in the log line and extract it at query time with parsers like
jsonorlogfmt, or search it with filter expressions.
Audit what your clients send
Collectors and agents can attach dynamic labels you didn’t choose. Use the fewest labels test on whatever Alloy, Fluentd, or your Docker driver is applying. To see your streams and find high-cardinality labels, run:
logcli series '{}' --since=1h --analyze-labelsA label with thousands of unique values found in nearly every stream, such as a requestId, should be removed from labels and queried with a filter expression instead.
If many teams send logs and you can’t audit or change every client, apply the same approach you learned for metrics: route logs through gateway collectors your admin team owns, enforce label policy at that layer, and manage those gateway configurations centrally with Fleet Management.
You now have the logs framework. This includes static origin labels, dynamic labels only when bounded and queried, structured metadata for high-cardinality fields, and filter expressions for the rest.
More to explore (optional)
At this point in your journey, you can explore the following topics: