Skip to content

stdoutmetric: use non-OTLP attributes and export non-finite values - #9308

Open
pellared wants to merge 12 commits into
open-telemetry:mainfrom
pellared:fix/stdoutmetric-nonfinite-9304
Open

pellared wants to merge 12 commits into
open-telemetry:mainfrom
pellared:fix/stdoutmetric-nonfinite-9304

Conversation

@pellared

@pellared pellared commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

NaN and infinities in metric values or attributes currently stop the default JSON encoder and leave the entire metric collection unwritten. Share the attribute package's non-OTLP formatting, following merged #9150, and encode non-finite metric numbers as JSON strings.

Attribute values use native JSON types: strings, booleans, finite numbers, arrays, objects, and null for empty values. Bytes use Base64 strings; special floats become "NaN", "Infinity", and "-Infinity". JSON-looking strings stay strings, and user map entries named Type or Value remain ordinary data. Numeric adapters cover measurements, extrema, bounds, summaries, and exemplars while preserving integer precision and signed zero.

Resource, instrumentation scope, and data-point attribute sets become JSON objects. Exemplar attributes remain ordered arrays of single-attribute objects. Empty sets are {}, nil resources remain null, and scope metadata is retained.

Use exporter-local wrappers with json.RawMessage attribute fields so finite and non-finite collections follow the same encoding path. Concrete wrapper slices avoid per-record interface boxing. Custom WithEncoder implementations, including caller-supplied *json.Encoder values, receive the original metric data. Shared attribute marshaling and other exporters are unaffected; caller-owned input and ordinary export errors are preserved. Focused race tests and make precommit pass.

Fixes #9304.

Six-sample benchmarks below compare against main dfb660c5e using the same fixtures on both versions. The existing exporter fixtures use about 57% fewer bytes, increase from 66 to 106 allocations, and measured 12–15% slower. The mixed aggregation fixture measured 42% faster, used 67% fewer bytes, and reduced allocations from 373 to 281. Timings are directional measurements from a shared host. This is a formatting change with performance tradeoffs; non-finite rejection paths are excluded because they do not provide a comparable successful-export baseline.

Benchmark commands: GOMAXPROCS=2 make benchmark/./exporters/stdout/stdoutmetric ARGS='-bench=BenchmarkExporterExport -benchmem -count=6 -benchtime=100ms' and GOMAXPROCS=2 make benchmark/./exporters/stdout/stdoutmetric ARGS='-bench=BenchmarkJSONExport -benchmem -count=6 -benchtime=100ms'.

goos: linux
goarch: amd64
pkg: go.opentelemetry.io/otel/exporters/stdout/stdoutmetric
cpu: AMD EPYC 7571
                                 │ main-dfb660c5e.txt │             updated.txt             │
                                 │       sec/op       │    sec/op     vs base               │
ExporterExport/Observability-2            68.91µ ± 1%   78.99µ ± 23%  +14.63% (p=0.002 n=6)
ExporterExport/NoObservability-2          67.93µ ± 2%   76.38µ ±  8%  +12.44% (p=0.002 n=6)
JSONExport/Finite-2                       261.0µ ± 3%   151.6µ ±  7%  -41.93% (p=0.002 n=6)
geomean                                   106.9µ        97.06µ         -9.20%

                                 │ main-dfb660c5e.txt │             updated.txt             │
                                 │        B/op        │     B/op      vs base               │
ExporterExport/Observability-2          18.150Ki ± 0%   7.862Ki ± 1%  -56.68% (p=0.002 n=6)
ExporterExport/NoObservability-2        18.155Ki ± 0%   7.865Ki ± 0%  -56.68% (p=0.002 n=6)
JSONExport/Finite-2                      45.91Ki ± 1%   14.93Ki ± 2%  -67.47% (p=0.002 n=6)
geomean                                  24.73Ki        9.738Ki       -60.63%

                                 │ main-dfb660c5e.txt │            updated.txt             │
                                 │     allocs/op      │  allocs/op   vs base               │
ExporterExport/Observability-2             66.00 ± 0%   106.00 ± 1%  +60.61% (p=0.002 n=6)
ExporterExport/NoObservability-2           66.00 ± 0%   106.00 ± 0%  +60.61% (p=0.002 n=6)
JSONExport/Finite-2                        373.0 ± 1%    281.0 ± 1%  -24.66% (p=0.002 n=6)
geomean                                    117.6         146.7       +24.79%

@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Pull request dashboard status

Waiting on reviewers · refreshed 2026-11-09 19:55 UTC

Review the latest changes.

Also blocked by: Merge conflicts.

Status above doesn't look right?
  • Just replied or pushed? Anything around or after the refresh time above may not be picked up yet — give it a few minutes.
  • Anything look wrong? Report it with what you expected; it helps us improve the dashboard.

@codecov

codecov Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.09091% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 89.9%. Comparing base (dfb660c) to head (fb1aa3c).

Files with missing lines Patch % Lines
exporters/stdout/stdoutmetric/config.go 83.3% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@          Coverage Diff           @@
##            main   #9308    +/-   ##
======================================
  Coverage   89.8%   89.9%            
======================================
  Files        357     358     +1     
  Lines      23987   24094   +107     
======================================
+ Hits       21562   21665   +103     
- Misses      2425    2429     +4     
Files with missing lines Coverage Δ
exporters/stdout/stdoutmetric/json.go 100.0% <100.0%> (ø)
exporters/stdout/stdoutmetric/config.go 94.5% <83.3%> (+0.4%) ⬆️

... and 6 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@pellared pellared changed the title fix(stdoutmetric): export non-finite metric values and attributes stdoutmetric: use non-OTLP attributes and export non-finite values Nov 9, 2026
@pellared
pellared marked this pull request as ready for review November 9, 2026 13:52
@opentelemetry-pr-dashboard
opentelemetry-pr-dashboard Bot requested a balanced review from Copilot November 9, 2026 13:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues were identified for the stdoutmetric JSON formatting and non-finite number support changes.

No open issues 🎉

What changed in this PR

Updates stdoutmetric’s default JSON output to use non-OTLP attribute formatting and export non-finite numbers instead of rejecting entire metric collections, following the stdoutlog changes in #9150.

Changes:

  • Adds exporter-local JSON wrappers for attributes and non-finite numeric fields while preserving custom encoders’ original input.
  • Adds regression tests and benchmarks covering numeric precision, attribute formatting, empty collections, SDK integration, and error propagation.
  • Documents the formatting changes in package documentation and the changelog.
File Description
exporters/​stdout/​stdoutmetric/​json.go Implements attribute and numeric JSON conversion.
exporters/​stdout/​stdoutmetric/​json_test.go Adds regression coverage and export benchmarks.
exporters/​stdout/​stdoutmetric/​doc.go Documents non-OTLP attribute formatting and custom encoder behavior.
exporters/​stdout/​stdoutmetric/​config.go Uses the new default encoder and preserves pretty-print support.
CHANGELOG.md Records attribute formatting changes and non-finite value support.

Review effort: Balanced

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.

stdoutmetric: export NaN and infinity values instead of rejecting metric collections

2 participants