Skip to content

fix: restore reserved suffix stripping in PrometheusNaming.sanitizeMetricName()#2094

Draft
Copilot wants to merge 3 commits intomainfrom
copilot/fix-inference-issue-untyped-metrics
Draft

fix: restore reserved suffix stripping in PrometheusNaming.sanitizeMetricName()#2094
Copilot wants to merge 3 commits intomainfrom
copilot/fix-inference-issue-untyped-metrics

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 4, 2026

sanitizeMetricName() was simplified in 1.6.0 to return its input unchanged (since any non-empty UTF-8 string is now a valid metric name). This silently broke downstream tools — notably the JMX Exporter and the simpleclient bridge — that call sanitizeMetricName to normalize external names before passing them to snapshot builders.

The missing stripping means a JMX attribute that produces kafka_consumer_request_total as a raw name is no longer sanitized to kafka_consumer_request. With inferCounterTypeFromName: true this triggers unintended counter-type inference; with it false the metric is stored under the wrong name, breaking exact-name registry lookups.

Changes

  • PrometheusNaming.java — restore RESERVED_METRIC_NAME_SUFFIXES constant and the iterative suffix-stripping loop in sanitizeMetricName(). The exact-match case (where the entire input is a reserved suffix, e.g. "_total""total") is handled in a dedicated pre-pass before the stripping loop, and the inner loop now breaks immediately after a match to restart cleanly.

  • PrometheusNamingTest.java — update expectations to match restored behaviour; add a regression test for the JMX Exporter scenario and the dot-variant corner case (.total).

  • MetricMetadataTest.java — update expectations accordingly.

// Before fix (1.6.x): suffix preserved → metric stored as "kafka_consumer_request_total"
PrometheusNaming.sanitizeMetricName("kafka_consumer_request_total");
// → "kafka_consumer_request_total"  ← breaks name-based lookups, triggers counter inference

// After fix: suffix stripped → metric stored as "kafka_consumer_request"
PrometheusNaming.sanitizeMetricName("kafka_consumer_request_total");
// → "kafka_consumer_request"

Note: Counter.builder().name("events_total") is unaffected — the builder API does not go through sanitizeMetricName.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • checkstyle.org
    • Triggering command: /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/tools/linux64/java/bin/java /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/tools/linux64/java/bin/java -jar /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/xml/tools/xml-extractor.jar --fileList=/tmp/codeql-scratch-e3b4dfaf923d334a/dbs/java/working/files-to-index15700371373528140634.list --sourceArchiveDir=/tmp/codeql-scratch-e3b4dfaf923d334a/dbs/java/src --outputDir=/tmp/codeql-scratch-e3b4dfaf923d334a/dbs/java/trap/java --local sh =fetch (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI and others added 2 commits May 4, 2026 12:41
In client_java 1.6.0, `PrometheusNaming.sanitizeMetricName()` was changed
to return the input string unchanged (since all non-empty valid UTF-8
strings are now valid metric names). This was a regression for downstream
tools like the JMX Exporter and the simpleclient bridge, which relied on
`sanitizeMetricName` to strip reserved Prometheus metric name suffixes
(`_total`, `_created`, `_info`, `_bucket` and their dot variants) before
passing names to snapshot builders.

Without the stripping:
- A JMX attribute "Total" could produce a metric named
  `kafka_consumer_request_total` instead of `kafka_consumer_request`
- With `inferCounterTypeFromName: true`, this triggers unintended
  counter-type inference because the name ends with `_total`
- With `inferCounterTypeFromName: false`, the metric is still discoverable
  under the wrong name, breaking downstream registry lookups

The fix restores the stripping behaviour. Note that users who create
metrics directly via `Counter.builder().name("events_total")` are not
affected: the builder API bypasses `sanitizeMetricName` entirely.

Agent-Logs-Url: https://github.com/prometheus/client_java/sessions/7c842dd0-c793-4e16-815f-d3b5e03c3ba8

Co-authored-by: jaydeluca <7630696+jaydeluca@users.noreply.github.com>
- Separate the equals-only check (where name IS the suffix) into its own
  loop before the endsWith stripping loop, to avoid re-checking it on
  every outer iteration
- Add break after stripping a suffix so the inner loop restarts
  immediately rather than completing all remaining suffix checks
- Add test for dot-variant corner case: sanitizeMetricName(".total")
  returns "total"

Agent-Logs-Url: https://github.com/prometheus/client_java/sessions/7c842dd0-c793-4e16-815f-d3b5e03c3ba8

Co-authored-by: jaydeluca <7630696+jaydeluca@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix counter name/type inference for untyped metrics fix: restore reserved suffix stripping in PrometheusNaming.sanitizeMetricName() May 4, 2026
Copilot AI requested a review from jaydeluca May 4, 2026 12: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.

Counter name/type inference changed in 1.6.1 for untyped metrics, breaking downstream expectation of UNKNOWN

2 participants