Skip to content

[Exporter.Prometheus] Add target_info fallback#7238

Open
martincostello wants to merge 12 commits into
open-telemetry:mainfrom
martincostello:add-target-info-fallback
Open

[Exporter.Prometheus] Add target_info fallback#7238
martincostello wants to merge 12 commits into
open-telemetry:mainfrom
martincostello:add-target-info-fallback

Conversation

@martincostello
Copy link
Copy Markdown
Member

Changes

Add Prometheus text fallback target_info output as a gauge so resource metadata is still exposed as Info-typed metrics are unavailable for PrometheusText exposition format.

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)

Add Prometheus text fallback `target_info` output as a gauge so resource metadata is still exposed as Info-typed metrics are unavailable for PrometheusText exposition format.
@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 May 1, 2026
Comment thread src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md Outdated
Comment thread src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented May 1, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.92%. Comparing base (f3e872f) to head (1cb025e).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #7238      +/-   ##
==========================================
+ Coverage   89.86%   89.92%   +0.05%     
==========================================
  Files         276      276              
  Lines       14007    14022      +15     
==========================================
+ Hits        12588    12609      +21     
+ Misses       1419     1413       -6     
Flag Coverage Δ
unittests-Project-Experimental 89.61% <100.00%> (-0.22%) ⬇️
unittests-Project-Stable 89.85% <100.00%> (+<0.01%) ⬆️
unittests-UnstableCoreLibraries-Experimental 47.22% <100.00%> (+0.04%) ⬆️

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

Files with missing lines Coverage Δ
...tpListener/Internal/PrometheusCollectionManager.cs 91.73% <100.00%> (+0.13%) ⬆️
...heus.HttpListener/Internal/PrometheusSerializer.cs 98.78% <100.00%> (+0.05%) ⬆️

... and 6 files with indirect coverage changes

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 a Prometheus text/plain fallback for resource metadata by emitting target_info as a gauge (value 1) when Info-typed metric families aren’t available in the Prometheus text exposition format.

Changes:

  • Emit target_info as # TYPE target_info gauge / # HELP target_info ... for Prometheus text output while keeping OpenMetrics # TYPE target info.
  • Cache target_info serialization separately for plain text vs OpenMetrics responses.
  • Update HttpListener and AspNetCore integration tests + exporter changelogs to reflect the new plaintext output.

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/PrometheusHttpListenerTests.cs Updates expected scrape output to include plaintext target_info gauge.
test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs Updates expected scrape output to include plaintext target_info gauge.
src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializer.cs Makes WriteTargetInfo switch between OpenMetrics info vs plaintext gauge family names.
src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusCollectionManager.cs Writes/caches target_info for both formats and splits cached lengths by format.
src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md Documents the fallback behavior addition.
src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md Documents the fallback behavior addition.
Comments suppressed due to low confidence (1)

src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializer.cs:472

  • WriteTargetInfo always appends a comma for each resource attribute and then unconditionally does cursor-- to overwrite the last comma. If resource is not reference-equal to Resource.Empty but has zero attributes (e.g., Resource.Empty.Merge(Resource.Empty) returns a new empty Resource), this will overwrite the { and emit invalid exposition (target_info} 1). Track whether any labels were written (or check for an empty attribute collection) and either omit braces/commas or skip emitting the metric when there are no attributes.
        cursor = WriteAsciiStringNoEscape(buffer, cursor, "target_info");
        buffer[cursor++] = unchecked((byte)'{');

        foreach (var attribute in resource.Attributes)
        {
            cursor = WriteLabel(buffer, cursor, attribute.Key, attribute.Value);

            buffer[cursor++] = unchecked((byte)',');
        }

        cursor--; // Write over the last written comma

        buffer[cursor++] = unchecked((byte)'}');

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

@martincostello martincostello marked this pull request as ready for review May 1, 2026 20:38
@martincostello martincostello requested a review from a team as a code owner May 1, 2026 20:38
@martincostello martincostello enabled auto-merge May 4, 2026 09:28
@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

From Codex:
[P2] src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusCollectionManager.cs:238 now calls WriteTargetInfo for the default text/plain path too. WriteTargetInfo only skips the Resource.Empty singleton, so a reachable empty-but-not-singleton resource, for example one returned by a detector or built from empty attributes, writes no labels and then cursor-- overwrites {, producing invalid exposition like target_info} 1. This was already risky for OpenMetrics, but this PR extends it to the default scrape format. Guard on empty resource.Attributes or handle the no-label sample explicitly, and add a plaintext regression test.

Fix generated corrupted metrics if no resources are present.
@martincostello
Copy link
Copy Markdown
Member Author

Feedback addressed.

Wait until all metrics are present, not just one.
Comment thread src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md Outdated
Comment thread src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md Outdated
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.

3 participants