Skip to content

[Exporter.Prometheus] Export _created series for OpenMetrics#7223

Open
martincostello wants to merge 17 commits into
open-telemetry:mainfrom
martincostello:emit-created-series
Open

[Exporter.Prometheus] Export _created series for OpenMetrics#7223
martincostello wants to merge 17 commits into
open-telemetry:mainfrom
martincostello:emit-created-series

Conversation

@martincostello
Copy link
Copy Markdown
Member

Changes

Export {name}_created series for counters and histograms when start time is available when using OpenMetrics.

Merge requirement checklist

  • CONTRIBUTING guidelines followed (license requirements, nullable enabled, static analysis, etc.)
  • Unit tests added/updated
  • Appropriate CHANGELOG.md files updated for non-trivial changes
  • Changes in public API reviewed (if applicable)

Export `{name}_created` series for counters and histograms when start time is available when using OpenMetrics.
@github-actions github-actions Bot added pkg:OpenTelemetry.Exporter.Prometheus.AspNetCore Issues related to OpenTelemetry.Exporter.Prometheus.AspNetCore NuGet package pkg:OpenTelemetry.Exporter.Prometheus.HttpListener Issues related to OpenTelemetry.Exporter.Prometheus.HttpListener NuGet package labels Apr 29, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 29, 2026

Codecov Report

❌ Patch coverage is 97.22222% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 89.94%. Comparing base (f3e872f) to head (91de284).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...s.HttpListener/Internal/PrometheusSerializerExt.cs 96.96% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #7223      +/-   ##
==========================================
+ Coverage   89.86%   89.94%   +0.07%     
==========================================
  Files         276      276              
  Lines       14007    14043      +36     
==========================================
+ Hits        12588    12631      +43     
+ Misses       1419     1412       -7     
Flag Coverage Δ
unittests-Project-Experimental 89.82% <97.22%> (-0.02%) ⬇️
unittests-Project-Stable 89.78% <97.22%> (-0.07%) ⬇️
unittests-UnstableCoreLibraries-Experimental 47.33% <97.22%> (+0.16%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...heus.HttpListener/Internal/PrometheusSerializer.cs 98.74% <100.00%> (+0.01%) ⬆️
...s.HttpListener/Internal/PrometheusSerializerExt.cs 98.40% <96.96%> (-0.52%) ⬇️

... and 5 files with indirect coverage changes

@martincostello martincostello marked this pull request as ready for review April 29, 2026 21:52
@martincostello martincostello requested a review from a team as a code owner April 29, 2026 21:52
Copilot AI review requested due to automatic review settings April 29, 2026 21:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds support for exporting OpenMetrics {name}_created series for counters and histograms when a metric start time is available, and updates tests/changelogs accordingly.

Changes:

  • Emit {name}_created samples for counters and histograms in OpenMetrics format (when MetricPoint.StartTime is present).
  • Extend serializer and integration tests to validate presence/absence of _created depending on OpenMetrics negotiation.
  • Update Prometheus exporter changelogs to document the new behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusSerializerTests.cs Adds assertions that _created is exported only for OpenMetrics (counter + histogram).
test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs Updates HTTP listener integration expectations to include _created in OpenMetrics responses.
test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs Updates ASP.NET Core middleware integration expectations to include _created in OpenMetrics responses.
src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializerExt.cs Implements writing of {name}_created lines based on MetricPoint.StartTime.
src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md Documents the new _created OpenMetrics series behavior.
src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md Documents the new _created OpenMetrics series behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Add missing `TYPE` metadata.
@martincostello martincostello marked this pull request as draft April 29, 2026 22:24
@martincostello martincostello marked this pull request as ready for review April 30, 2026 15:13
@rajkumar-rangaraj
Copy link
Copy Markdown
Member

@martincostello could you please check the copilot cli feedback.

PR #7223 Review: [Exporter.Prometheus] Export _created series for OpenMetrics

🔴 CRITICAL: Incorrect # TYPE _created gauge metadata line

The PR emits a separate # TYPE {name}_created gauge metadata declaration. However, per the OpenMetrics spec,
_created is a suffix/sample within the parent MetricFamily, NOT a separate MetricFamily. None of the spec examples
show a separate TYPE line for _created:

Spec example (Counter) — NO separate TYPE for _created:

TYPE foo counter

foo_total 17.0
foo_created 1520430000.123

The PR incorrectly emits:

TYPE foo_created gauge ← NOT in any spec example

TYPE foo counter

foo_total 17.0
foo_created 1520430000.123

This could cause Prometheus parsers to reject the output since they know _created is a special suffix, not a
standalone gauge.

🟡 MEDIUM: Timestamp precision

WriteUnixTimeSeconds uses ToUnixTimeMilliseconds() / 1000.0 → only millisecond precision. The WriteDouble with G17
format may produce verbose representations. Functional but worth documenting.

🟢 LOW: Double iteration of MetricPoints

HasCreatedMetric() iterates all metric points to check for non-default StartTime, then the main loop iterates again.
GetMetricPoints() returns a new MetricPointsAccessor struct each time, so it's correct but slightly inefficient.

✅ Verified OK

  • _created correctly excluded for gauges (only counters + histograms)
  • WriteCreatedMetric correctly guards with StartTime != default per-point
  • Non-OpenMetrics paths correctly use empty string for createdMetric
  • HasCreatedMetric double-iteration is safe (enumerator is value-type, reusable)
  • All CI checks pass

The # TYPE {name}_created gauge metadata line appears to violate the OpenMetrics spec. The rest of the implementation looks solid.

@martincostello
Copy link
Copy Markdown
Member Author

martincostello commented May 1, 2026

Will do - the fun of Copilot. Changes originally authored by it won't always fulfill its own review analysis 😄

- Remove non-spec `TYPE` for `_counter`.
- Fix-up timestamp precision.
Fix-up duplicated definitions.
Add missing suffix.
@martincostello martincostello added the keep-open Prevents issues and pull requests being closed as stale label May 8, 2026
@Kielek
Copy link
Copy Markdown
Member

Kielek commented May 19, 2026

Codex feedback:
[P2] src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializerExt.cs:134 ties histogram _created emission to the same block that emits _sum / _count. For OpenMetrics histograms with negative bucket bounds, this block is skipped, so _created is also skipped. The spec only forbids _sum in that case; it still says histogram points should contain Created, and the text format defines _created independently of _sum / _count. Move the WriteCreatedMetric(...) call outside that !hasNegativeBucketBounds block so it still emits after the buckets when StartTime is available.

Fix `_created` metrics not being emitted for negative histogram bucket bounds.
@martincostello
Copy link
Copy Markdown
Member Author

Done.

@martincostello martincostello enabled auto-merge May 19, 2026 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

keep-open Prevents issues and pull requests being closed as stale pkg:OpenTelemetry.Exporter.Prometheus.AspNetCore Issues related to OpenTelemetry.Exporter.Prometheus.AspNetCore NuGet package pkg:OpenTelemetry.Exporter.Prometheus.HttpListener Issues related to OpenTelemetry.Exporter.Prometheus.HttpListener NuGet package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants