Uh oh!
There was an error while loading. Please reload this page.
feat: move suffix handling to scrape time - #1955
Conversation
i accidentally commented on this one because it has a lot of the same changes as #1956 , is this separate? edit: just noticed the "blocked by" on the other PR, so I guess i did them out of order |
Move metric name suffix handling (_total, _info, unit suffixes) from creation time to scrape time. Each format writer now owns its suffix conventions: - OM1: smart-appends suffixes (skip if already present) - Registry detects cross-format name collisions at registration time Key changes: - Remove all reserved metric name suffixes from PrometheusNaming - Store original user-provided name separately from exposition base name in MetricMetadata (originalName vs expositionBaseName) - Smart-append logic in OM1/protobuf writers for _total and _info - Two-layer collision detection in PrometheusRegistry Closes#1941 Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
e63ef43 to
0787661Comparezeitlinger
commented
Mar 18, 2026
no worries - I'll apply the feedback to the correct pr |
- Fix race condition: use putIfAbsent for atomic exposition name claiming with proper rollback on failure - Extract claimExpositionNames/releaseExpositionNames for single rollback path - Rename Info test methods to reflect that _info suffix is now allowed Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
zeitlinger
commented
Mar 18, 2026
did that now |
Uh oh!
There was an error while loading. Please reload this page.
## Summary Adds `preserve_names` configuration to the OpenTelemetry exporter. When enabled, metric names are passed through exactly as the user wrote them instead of stripping `_total` and unit suffixes. Part of #1942. ### Key changes - Add `preserve_names` to `ExporterOpenTelemetryProperties` - `MetricDataFactory` uses `originalName` + `preserve_names` to decide naming - `OtelAutoConfig` wires the new property ### Key table | User provides | OTel | OTel preserve_names | |---|---|---| | `Counter("events")` | `events` | `events` | | `Counter("events_total")` | `events` | `events_total` | | `Counter("req").unit(BYTES)` | name `req`, unit `By` | name `req`, unit `By` | | `Counter("req_bytes").unit(BYTES)` | name `req`, unit `By` | name `req_bytes`, unit `By` | | `Gauge("events_total")` | `events_total` | `events_total` | ### PR stack 1. Core model + OM1/protobuf writers (#1955) 2. **This PR** — OTel `preserve_names` 3. OM2 writer no-suffix (independent) ## Test plan - [x] `mise run compile` passes - [x] Tests for `preserve_names=true` with units, unit already in name, and without unit - [x] `OtelAutoConfigTest` covers new property wiring Part of #1912. --------- Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
## Summary The OM2 writer now uses `expositionBaseName` directly instead of appending `_total` (counters) or unit suffixes. The `_info` suffix is enforced per the OM2 spec (MUST). Part of #1942. ### Key table | User provides | OM1 | OM2 | |---|---|---| | `Counter("events")` | `events_total` | `events` | | `Counter("events_total")` | `events_total` | `events_total` | | `Counter("req").unit(BYTES)` | `req_bytes_total` | `req_bytes` | | `Counter("req_bytes").unit(BYTES)` | `req_bytes_total` | `req_bytes` | | `Gauge("events_total")` | `events_total` | `events_total` | | `Info("target")` | `target_info` | `target_info` | ### PR stack 1. Core model + OM1/protobuf writers (#1955) 2. OTel `preserve_names` (independent) 3. **This PR** — OM2 writer no-suffix ## Test plan - [x] `mise run compile` passes - [x] OM2-specific tests verify no `_total`/unit suffix appending - [x] `_info` suffix enforcement tested Part of #1912. --------- Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
🤖 I have created a release *beep* *boop* --- ## [1.6.0](v1.5.1...v1.6.0) (2026-04-25) ### Features * Add logic for handling content negotation flag with OM2 ([#1986](#1986)) ([0fa1ad7](0fa1ad7)) * Add OM2 native histogram text output ([#2042](#2042)) ([dec8e5b](dec8e5b)) * add OTel preserve_names for scrape-time suffix handling ([#1956](#1956)) ([f794288](f794288)) * compositeValues and exemplarCompliance flags for OM2 writer ([#1991](#1991)) ([ff48ae8](ff48ae8)) * move suffix handling to scrape time ([#1955](#1955)) ([5a5106c](5a5106c)) * OM2 writer outputs names as provided, no suffix appending ([#1957](#1957)) ([5ce2b57](5ce2b57)) ### Bug Fixes * **deps:** update dependency com.google.guava:guava to v33.6.0-jre ([#2021](#2021)) ([1382693](1382693)) * **deps:** update dependency commons-io:commons-io to v2.22.0 ([#2044](#2044)) ([9e05c1d](9e05c1d)) * **deps:** update dependency io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha to v2.27.0-alpha ([#2022](#2022)) ([30ac534](30ac534)) * **deps:** update dependency io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha to v2.27.0-alpha ([#2023](#2023)) ([2d51a32](2d51a32)) * **deps:** update dependency io.prometheus:prometheus-metrics-bom to v1.5.1 ([#2004](#2004)) ([650ce4b](650ce4b)) * **deps:** update dependency org.apache.tomcat.embed:tomcat-embed-core to v11.0.21 ([#2005](#2005)) ([7a36df7](7a36df7)) * **deps:** update dependency org.springframework.boot:spring-boot-starter-parent to v4.0.5 ([#2006](#2006)) ([0106c18](0106c18)) * **deps:** update dependency org.springframework.boot:spring-boot-starter-parent to v4.0.6 ([#2046](#2046)) ([40a9db8](40a9db8)) * **deps:** update jetty monorepo to v12.1.8 ([#2007](#2007)) ([acab5b2](acab5b2)) * **deps:** update protobuf ([#2024](#2024)) ([8e2214e](8e2214e)) * pass release tag as input to deploy workflow ([#1982](#1982)) ([165c921](165c921)) * pin grafana/otel-lgtm to 0.7.2 in OATs acceptance test ([#1992](#1992)) ([f17ad9a](f17ad9a)) * Relax metric name validation in Dropwizard5 ([#1985](#1985)) ([deb782f](deb782f)) * stabilize flaky timer and thread count tests ([#1973](#1973)) ([ce5867b](ce5867b)) * Tighten OM2 summary and start timestamp output ([#2041](#2041)) ([5699469](5699469)) * trigger Maven deploy from release-please via workflow_dispatch ([#1981](#1981)) ([698f956](698f956)) --- > [!IMPORTANT] > Close and reopen this PR to trigger CI checks. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Fixes#2095 ## Summary Restores OM1/protobuf compatibility for dotted gauge names after `feat: move suffix handling to scrape time (#1955)`. The bug was that non-OpenMetrics exposition changed visible output for gauge names that merely ended in suffix-like dotted strings such as `.created` and `.total`. Examples: - `Gauge("test3.created")` regressed from `test3` to `test3_created` - `Gauge("test6.total")` regressed from `test6` to `test6_total` This PR restores the legacy OM1/protobuf behavior while keeping OpenMetrics on literal-name handling. This is the extracted prom-side fix from #2093. The Micrometer workflow and related downstream testing were split into a stacked follow-up PR so this can merge independently. ## What changed - Fix OM1 text exposition for dotted gauge names ending in `.created` and `.total` - Fix protobuf exposition for the same compatibility cases - Add regression tests that cover the restored OM1/protobuf behavior and the preserved OpenMetrics behavior - Clean up protobuf family-name resolution so legacy gauge handling lives in one path instead of pre-rewriting metadata objects ## Follow-up stacked PR - Micrometer workflow/task split: zeitlinger#1 ## Related - Replaces: #2093 - Issue: #2095 ## Testing - `mise run build` - `mise run lint` - `./mvnw test -pl prometheus-metrics-exposition-textformats,prometheus-metrics-exposition-formats -Dtest=ExpositionFormatsTest,ProtobufExpositionFormatsTest,DuplicateNamesProtobufTest -Dcoverage.skip=true -Dcheckstyle.skip=true`
Fixes#2095 ## Summary Restores OM1/protobuf compatibility for dotted gauge names after `feat: move suffix handling to scrape time (#1955)`. The bug was that non-OpenMetrics exposition changed visible output for gauge names that merely ended in suffix-like dotted strings such as `.created` and `.total`. Examples: - `Gauge("test3.created")` regressed from `test3` to `test3_created` - `Gauge("test6.total")` regressed from `test6` to `test6_total` This PR restores the legacy OM1/protobuf behavior while keeping OpenMetrics on literal-name handling. This is the extracted prom-side fix from #2093. The Micrometer workflow and related downstream testing were split into a stacked follow-up PR so this can merge independently. ## What changed - Fix OM1 text exposition for dotted gauge names ending in `.created` and `.total` - Fix protobuf exposition for the same compatibility cases - Add regression tests that cover the restored OM1/protobuf behavior and the preserved OpenMetrics behavior - Clean up protobuf family-name resolution so legacy gauge handling lives in one path instead of pre-rewriting metadata objects ## Follow-up stacked PR - Micrometer workflow/task split: zeitlinger#1 ## Related - Replaces: #2093 - Issue: #2095 ## Testing - `mise run build` - `mise run lint` - `./mvnw test -pl prometheus-metrics-exposition-textformats,prometheus-metrics-exposition-formats -Dtest=ExpositionFormatsTest,ProtobufExpositionFormatsTest,DuplicateNamesProtobufTest -Dcoverage.skip=true -Dcheckstyle.skip=true` Signed-off-by: Jay DeLuca <jaydeluca4@gmail.com>
Summary
Moves metric name suffix handling (
_total,_info, unit suffixes)from creation time to scrape time. Closes#1941, part of #1942.
time
Key changes
PrometheusNamingname in
MetricMetadata(originalNamevsexpositionBaseName)_totaland_infoPrometheusRegistry(base name + exposition names)
Key table
Counter("events")events_totalCounter("events_total")events_totalCounter("req").unit(BYTES)req_bytes_totalCounter("req_bytes").unit(BYTES)req_bytes_totalGauge("events_total")events_totalPR stack
preserve_names(stacked on this)Test plan
mise run compilepassesMetricMetadata5-arg constructor andfield accessors
PrometheusRegistryTestcovers collision detectionPart of #1912.