Skip to main content
Low risk Metric tags with unbounded or highly variable values. User IDs, request IDs, timestamps, IP addresses as tags. Each unique value creates a new time series, and your metric storage explodes.

Why it happens

A developer adds a tag to help with debugging. user_id on a latency metric seems useful: you could see latency per user. But you have a million users. Now you have a million time series for one metric. Metrics are meant to be aggregated. Tags with high cardinality defeat the purpose. You end up with millions of sparse time series that nobody queries and cost a fortune to store.

Example

A request latency metric with user_id as a tag:
http_request_duration_seconds{service="api", endpoint="/users", user_id="usr_abc123"} 0.045
http_request_duration_seconds{service="api", endpoint="/users", user_id="usr_def456"} 0.052
http_request_duration_seconds{service="api", endpoint="/users", user_id="usr_ghi789"} 0.038
One metric × one endpoint × one million users = one million time series.
Tero generates a policy to remove the high-cardinality tag:
id: remove-user-id-tag
name: Remove user_id tag from all metrics
description: Drop high-cardinality user_id tag. Creates millions of sparse time series.
metric:
  match:
    - tag: user_id
      exists: true
  transform:
    remove_tags:
      - user_id
You can scope this to specific metrics if some legitimately need user-level granularity. But most teams apply it globally. If user_id is high cardinality, it’s high cardinality everywhere.
The best fix is to remove the tag from instrumentation. If that’s not possible, strip it at the edge before it reaches your metrics provider.

How it works

Tero analyzes tag cardinality across your context graph. Tags with thousands of unique values (user IDs, request IDs, session tokens) are flagged as high cardinality. Tero also checks whether these high-cardinality tags are ever used in queries or dashboards. A tag with 100,000 unique values that nobody filters by is a clear candidate for removal.