Skip to content

fix(collector): apply the cardinality guardrail to metric data points, not just spans (#172) - #201

Merged
radra23 merged 1 commit into
mainfrom
fix/collector-cardinality-all-signals
Oct 3, 2026
Merged

radra23 merged 1 commit into
mainfrom
fix/collector-cardinality-all-signals

Conversation

@radra23

@radra23 radra23 commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Summary

The agent config's cardinality guardrail cleaned span attributes only, while semconv-discipline ranks a metric dimension as the worst position for an identifier. Fixes the metric half of #172; log records are deliberately left unguarded (below).

What changed

  • collector-topology template and the three agent goldens: a metric_statements list (context: datapoint) with the same drop-list, and transform in the metrics pipeline between memory_limiter and batch. A comment notes that dropping a dimension merges the series that differed only by it
  • /otel-collector adds each derived.highCardinalityAttributes key to both lists
  • semconv-discipline said the Collector guardrail "operates on spans only" and "cannot reach a metric dimension"; corrected to spans and metric data points, as a backstop for the listed keys
  • collector-cardinality-contract.test.sh: 17 new checks. Bumps to 0.8.20

Departs from the issue: log records are NOT guarded. semconv-discipline ranks a log-record attribute as the prescribed home for a per-request identifier, and a log record is not a time series, so deleting user.id there would remove debugging data with no cardinality benefit. The template explains when a log_statements list would be justified.

Test plan

  • All hook, snapshot, drift and e2e unit tests pass locally; claude plugin validate . --strict passes; tests/collector-validate.sh passes against otelcol-contrib 0.161.0

  • Runtime, with the golden's own processor block on Collector 0.161.0: a metric data point and a span carrying user.id lose it and keep http.route; a log record keeps both

  • Teeth: removing one key from the metric list fails the contract test; 3 checks fail against the previous skill and command text

  • Vendor, SDK and semantic-convention facts were verified against the source, not recalled — linked where it isn't obvious.

  • Nothing hardcoded that has a single source of truth (SEMCONV_VERSION, backends.txt, hooks/otel-paths.sh).

…, not just spans (#172)

The agent config's transform processor dropped user.id / session.id / request.id / order.id
from span attributes only. semconv-discipline ranks a metric dimension as the worst position
for an identifier (one retained series per value, untouched by sampling, persisting in the
backend after the code is fixed), so the guardrail covered the least damaging case and missed
the most damaging one. The repo-specific keys from derived.highCardinalityAttributes (#37) had
the same gap: they were only ever emitted as trace_statements.

- collector-topology template and the three agent goldens: a metric_statements list
  (context: datapoint) with the same drop-list, and transform in the metrics pipeline between
  memory_limiter and batch. The generated file says that dropping a dimension merges the series
  that differed only by it.
- /otel-collector adds each derived.highCardinalityAttributes key to both lists.
- semconv-discipline said the Collector guardrail "operates on spans only" and "cannot reach a
  metric dimension", and every subagent that reads the skill was told the case must be fixed in
  code. Corrected: it covers spans and metric data points for the keys on its list, as a
  backstop that does not replace fixing the instrumentation.

Log records are deliberately NOT guarded, which departs from the issue's proposal.
semconv-discipline ranks a log-record attribute as the prescribed home for a per-request
identifier, a log record is not a time series, and deleting user.id there would remove
debugging data with no cardinality benefit. The template says so and when a log_statements
list would be justified.

Verified at runtime against otelcol-contrib 0.161.0 using the golden's own processor block: a
metric data point and a span carrying user.id lose it and keep http.route, while a log record
keeps both. The goldens still validate (tests/collector-validate.sh).
collector-cardinality-contract.test.sh gains 17 checks: per golden, the two drop-lists are
identical, the datapoint context is used, and traces and metrics run
memory_limiter, transform, batch while logs stay unguarded. Bumps to 0.8.20.
@radra23
radra23 merged commit 7fdcf85 into main Oct 3, 2026
11 checks passed
@radra23
radra23 deleted the fix/collector-cardinality-all-signals branch October 3, 2026 14:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant