Class LabelCardinalityGuard

java.lang.Object
com.tnsai.quality.observability.LabelCardinalityGuard

public final class LabelCardinalityGuard extends Object
Bounds the number of distinct values a Prometheus label can take.

Prometheus creates one time series per unique label combination. If any label accepts unbounded strings (user-supplied model names, error messages folded into error_type, trace snippets), series cardinality explodes: the scrape endpoint grows multi-MB, the TSDB exhausts memory, and dashboards time out trying to enumerate options. This is a well-documented operational hazard — do not overuse labels.

Strategy

  1. Null / empty → "unknown". Consistent bucket for missing data.
  2. Allowlisted value → pass through unchanged. Stable known values.
  3. Novel value below the cap → recorded and passed through. Tolerates organic growth (new provider, new error type).
  4. Novel value at/above the cap → collapsed into OVERFLOW_BUCKET. The metric still records the event; it just shares a bucket with other rare values. Logged once per bucketed value at WARN.

Common configurations


 LabelCardinalityGuard providers = LabelCardinalityGuard.builder("llm.provider")
     .maxDistinct(32)
     .allow("anthropic", "openai", "google", "azure", "ollama",
            "huggingface", "bedrock", "mistral", "groq", "cohere",
            "openrouter", "deepseek")
     .build();

 LabelCardinalityGuard models = LabelCardinalityGuard.builder("llm.model")
     .maxDistinct(256)        // models legitimately expand; buffer is larger
     .build();                // no allowlist — just the cap

 LabelCardinalityGuard errors = LabelCardinalityGuard.builder("llm.error_type")
     .maxDistinct(16)
     .allow("timeout", "rate_limit", "auth", "invalid_request",
            "server_error", "parse_error", "network")
     .build();
 

Thread-safe.

Since:
0.3.0
  • Field Details

    • UNKNOWN_BUCKET

      public static final String UNKNOWN_BUCKET
      Label value used when an input is null / empty.
      See Also:
    • OVERFLOW_BUCKET

      public static final String OVERFLOW_BUCKET
      Label value used when the distinct-count cap has been hit.
      See Also:
  • Method Details

    • builder

      public static LabelCardinalityGuard.Builder builder(String name)
      Starts a new builder for a label named name.
    • normalise

      public String normalise(String raw)
      Returns a safe label value for raw.
      Parameters:
      raw - caller-supplied value; may be null or unbounded
      Returns:
      the original value if allowed or under the cap; UNKNOWN_BUCKET for null/empty; OVERFLOW_BUCKET otherwise
    • admittedCount

      public int admittedCount()
      Count of distinct admitted (non-allowlisted, non-bucket) values currently tracked.
    • reset

      public void reset()
      Resets the admitted-values memory. Intended for tests.