-
Notifications
You must be signed in to change notification settings - Fork 832
Description
The OpenMetrics 2.0 spec is nearing completion. We should start implementing experimental support to validate the design and provide early feedback to the spec authors.
All features are behind opt-in flags (off by default) so there's no risk to existing users. The spec is still in draft, so the API is explicitly experimental and subject to change.
Flag design
Top-level gate + individual feature flags. The top-level gate (enableOpenMetrics2())
sets enabled=true implicitly and enables the sub-flags. Each sub-flag
independently controls one OM2 feature.
Java builder API:
PrometheusProperties config = PrometheusProperties.builder()
.enableOpenMetrics2(om2 -> om2
.contentNegotiation(true) // version=2.0.0 content type
.compositeValues(true) // single-line histogram/summary + st@
.exemplarCompliance(true) // mandatory timestamps, no size limit
.nativeHistograms(true) // exponential buckets
)
.build();
// Or enable everything at once
PrometheusProperties config = PrometheusProperties.builder()
.enableOpenMetrics2(om2 -> om2.enableAll())
.build();Properties equivalent:
io.prometheus.openmetrics2.enabled=true
io.prometheus.openmetrics2.content_negotiation=true
io.prometheus.openmetrics2.composite_values=true
io.prometheus.openmetrics2.exemplar_compliance=true
io.prometheus.openmetrics2.native_histograms=trueFor the minimal OM2 experience (names as provided, no suffix appending):
io.prometheus.openmetrics2.enabled=true| Flag | Description | Spec reference |
|---|---|---|
enabled |
Activate the OM2 writer. Required — feature flags below have no effect without it. Set implicitly by enableOpenMetrics2() |
— |
contentNegotiation |
Gate OM2 features behind content negotiation: only apply them when the scraper requests version=2.0.0, and return OM1 format when the scraper requests OM1. Without this flag, OM2 features are applied even if the scraper requests OM1 |
Content Type |
compositeValues |
Single-line Histogram/Summary/GaugeHistogram with inline st@ start timestamp. Also: reserved label prefix __, Histogram Count/Sum always present, bucket values may be float |
CompositeValue, Overall Structure |
exemplarCompliance |
Exemplar timestamps always emitted (MUST in OM2), 128-char LabelSet hard limit removed | Exemplar |
nativeHistograms |
Exponential buckets with schema, zero threshold/count, pos/neg spans | Native Buckets |
All flags default to false.
Suffix handling (_total, unit suffixes) is not an OM2 config flag — it is handled
at scrape time by each format writer. See #1941 for the design.
PR structure
PR 1: Flag infrastructure (#1939) ✅
│
└── PR 2: OM2 writer skeleton (#1951) ✅
│
├── PR 3: enabled flag (#1953)
│ │
│ ├── PR 4: Suffix handling (split from #1947):
│ │ ├── PR 4a: Core + OM1 writers (#1955)
│ │ ├── PR 4b: OTel preserve_names (#1956)
│ │ └── PR 4c: OM2 writer no-suffix (#1957)
│ │
│ └── PR 8: Documentation (#1954)
│
├── PR 5: contentNegotiation
│
├── PR 6: compositeValues + exemplarCompliance
│
└── PR 7: nativeHistograms
PR 1: Flag infrastructure (#1939) ✅
- Add
enableOpenMetrics2()toPrometheusProperties.Builder - Add
OpenMetrics2Propertiesclass with all flag fields (defaulting tofalse) - Wire up properties parsing for
io.prometheus.openmetrics2.* - No behavioral changes — just the config plumbing
PR 2: OM2 writer skeleton (#1951) ✅
OpenMetrics2TextFormatWriterimplementingExpositionFormatWriter- Wired into
ExpositionFormats: when OM2 is enabled, selected for OpenMetrics requests (masquerades as OM1 for testability with current Prometheus) - Takes
OpenMetrics2Propertiesfrom feat: Add OpenMetrics2 configuration support #1939 in builder
PR 3: enabled flag (#1953)
- Add
io.prometheus.openmetrics2.enabledas the explicit gate for OM2 writer selection - Feature flags alone no longer activate OM2 —
enabled=trueis required enableOpenMetrics2()programmatic configurator setsenabled=trueimplicitly
PR 4a: Core + OM1 writers (#1955)
- Move suffix handling to scrape time — OM1 smart-appends
_total/_info/unit suffixes (skips if already present) MetricMetadatastoresoriginalNameandexpositionBaseName- Counter/Info builders no longer strip
_total/_infoat creation time - Remove all reserved metric name suffixes from
PrometheusNaming - Cross-format collision detection in
PrometheusRegistry - See Move suffix handling from creation time to scrape time #1942 for design
PR 4b: OTel preserve_names (#1956)
- Add
preserve_namesconfig toExporterOpenTelemetryProperties - Legacy path (default): strips
_total+ unit suffix preserve_names=true: passes names through exactly as the user wrote them- Stacked on feat: move suffix handling to scrape time #1955
PR 4c: OM2 writer no-suffix (#1957)
- OM2 writer uses
expositionBaseNamedirectly — no_totalor unit suffix appending _infosuffix enforced per OM2 spec (MUST)- Stacked on feat: move suffix handling to scrape time #1955
PR 8: Documentation (#1954)
- Document OM2 preview features and configuration
- Document OTel
preserve_namesflag
PR 5: Content negotiation
contentNegotiation: only return OM2 format when the scraper explicitly requestsversion=2.0.0. Without this flag, OM2 features are applied even if the scraper requests OM1- Spec: Content Type
PR 6: CompositeValue + start timestamp + exemplar compliance
compositeValues:- Histogram as single line:
foo {count:17,sum:324789.3,bucket:[0.1:8,0.25:10,0.5:11,1.0:14,+Inf:17]} 1.0 st@0.5 - Summary as single line:
bar {count:17,sum:324789.3,quantile:[0.95:123.7,0.99:150.0]} - GaugeHistogram as single line with
count/sum(notgcount/gsum) _createdlines replaced by inlinest@start timestamp_count,_sum,_bucketsuffixed lines no longer emitted for these types- Reserved label prefix changed from
_to__ - Histogram/GaugeHistogram Count and Sum always present (MUST, was SHOULD for Sum)
- Histogram bucket values may be float (SHOULD be integer, was MUST)
- Spec: CompositeValue, Histogram, Summary
- Histogram as single line:
exemplarCompliance:- Exemplar timestamps always emitted (OM2: MUST, was MAY in OM1)
- 128-char LabelSet hard limit removed
PR 7: Native histograms
nativeHistograms:- Exponential bucket model: schema (-4 to 8), zero threshold/count, positive/negative spans and buckets
- Text serialization:
{count:X,sum:X,schema:N,zero_threshold:F,zero_count:X,positive_spans:[...],positive_buckets:[...]} - Can coexist with classic buckets on separate lines (native line MUST come first)
- GaugeHistogram also supports native buckets (same syntax)
- Multiple exemplars per native histogram sample
- Spec: Native Buckets, Histogram
- No known blockers:
- NHCB federation (#312) — still open but WG decided it won't change the spec (solution is a Prometheus scraping config, not an OM change)
- Exemplar timestamps (#308) — closed, resolved as MUST. We're aligned
Notes
- UTF-8 metric/label names are already supported (shipped in a previous release)
- The OM2 spec is still draft — some details may change, but no known blockers for the features covered here
- See also: OM 2.0 upgrade guide for SDK maintainers