Skip to content

[Exporter.Prometheus] Fix Accept header handling#7208

Merged
martincostello merged 4 commits into
open-telemetry:mainfrom
martincostello:prometheus-content-negotiation
Apr 30, 2026
Merged

[Exporter.Prometheus] Fix Accept header handling#7208
martincostello merged 4 commits into
open-telemetry:mainfrom
martincostello:prometheus-content-negotiation

Conversation

@martincostello

@martincostello martincostello commented Apr 29, 2026

Copy link
Copy Markdown
Member

Changes

Update the handling of the Accept header to follow the requirements documented in Scrape protocol content negotiation.

The behaviour isn't 100% compliant yet - it requires some tweaks to the serializer to be fully-compliant as I've not included it here and are in #7209.

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)

- Update the handling of the `Accept` header to follow the requirements documented in https://prometheus.io/docs/instrumenting/content_negotiation/.
- Removed unused code.
@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
<Compile Include="$(RepoRoot)\src\OpenTelemetry.Exporter.Prometheus.HttpListener\Internal\PrometheusSerializerExt.cs" Link="Includes/PrometheusSerializerExt.cs" />
<Compile Include="$(RepoRoot)\src\OpenTelemetry.Exporter.Prometheus.HttpListener\Internal\PrometheusType.cs" Link="Includes/PrometheusType.cs" />
<Compile Include="$(RepoRoot)\src\OpenTelemetry.Exporter.Prometheus.HttpListener\Internal\PrometheusMetric.cs" Link="Includes/PrometheusMetric.cs" />
<Compile Include="$(RepoRoot)\src\OpenTelemetry.Exporter.Prometheus.HttpListener\Internal\PrometheusHeadersParser.cs" Link="Includes/PrometheusHeadersParser.cs" />

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This was removed in favour of a native implementation as ASP.NET Core has built-in parsers for the Accept header and we were manually re-parsing it.

@codecov

codecov Bot commented Apr 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.64865% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 89.68%. Comparing base (24832b1) to head (749cdab).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

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

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #7208   +/-   ##
=======================================
  Coverage   89.67%   89.68%           
=======================================
  Files         272      272           
  Lines       13378    13434   +56     
=======================================
+ Hits        11997    12048   +51     
- Misses       1381     1386    +5     
Flag Coverage Δ
unittests-Project-Experimental 89.46% <98.64%> (-0.10%) ⬇️
unittests-Project-Stable 89.43% <98.64%> (-0.16%) ⬇️
unittests-UnstableCoreLibraries-Experimental 41.32% <98.64%> (+0.35%) ⬆️

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

Files with missing lines Coverage Δ
...metheus.AspNetCore/PrometheusExporterMiddleware.cs 98.24% <100.00%> (+0.74%) ⬆️
...s.HttpListener/Internal/PrometheusHeadersParser.cs 98.14% <97.91%> (-1.86%) ⬇️

... and 5 files with indirect coverage changes

- Add a constant for the OpenMetrics version.
- Update CHANGELOGs with PR number.
@martincostello martincostello marked this pull request as ready for review April 29, 2026 10:28
@martincostello martincostello requested a review from a team as a code owner April 29, 2026 10:28
Copilot AI review requested due to automatic review settings April 29, 2026 10:28

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.

Pull request overview

Updates Prometheus exporter content negotiation to better follow Prometheus scrape protocol rules by improving Accept header parsing and OpenMetrics vs Prometheus text selection.

Changes:

  • Enhanced Accept header parsing to account for whitespace, q weights, and OpenMetrics version (including quoted values).
  • Updated ASP.NET Core middleware to use typed Accept headers (GetTypedHeaders().Accept) and select the preferred format by quality.
  • Expanded unit test coverage for header parsing/negotiation scenarios and updated changelogs.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHeadersParserTests.cs Adds additional valid/invalid Accept header test cases (whitespace, quoted version, q weights).
test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs Refactors some tests and adds a focused unit test for AcceptsOpenMetrics using typed header parsing.
src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusHeadersParser.cs Implements Accept parsing with whitespace trimming, version parsing (quoted), and q-based negotiation.
src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md Documents the improved Accept header handling change.
src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs Switches to typed Accept parsing and applies q-based OpenMetrics vs text selection.
src/OpenTelemetry.Exporter.Prometheus.AspNetCore/OpenTelemetry.Exporter.Prometheus.AspNetCore.csproj Stops linking the shared PrometheusHeadersParser into the AspNetCore project.
src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md Documents the improved Accept header handling change.

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

Comment thread src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs Outdated
Comment thread src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusExporterMiddleware.cs Outdated
- Parse `Accept` case-insensitively.
- Check `quality` is between 0 and 1.
@martincostello martincostello marked this pull request as ready for review April 29, 2026 12:41
vgmello added a commit to vgmello/momentum that referenced this pull request Jun 11, 2026
Updated
[OpenTelemetry.Exporter.OpenTelemetryProtocol](https://github.com/open-telemetry/opentelemetry-dotnet)
from 1.15.3 to 1.16.0.

<details>
<summary>Release notes</summary>

_Sourced from [OpenTelemetry.Exporter.OpenTelemetryProtocol's
releases](https://github.com/open-telemetry/opentelemetry-dotnet/releases)._

## 1.16.0

For highlights and announcements pertaining to this release see:
[Release Notes >
1.16.0](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/RELEASENOTES.md#​1160).

The following changes are from the previous release
[1.16.0-rc.1](https://github.com/open-telemetry/opentelemetry-dotnet/releases/tag/core-1.16.0-rc.1).

* NuGet: [OpenTelemetry
v1.16.0](https://www.nuget.org/packages/OpenTelemetry/1.16.0)

  No notable changes.

See
[CHANGELOG](https://github.com/open-telemetry/opentelemetry-dotnet/blob/core-1.16.0/src/OpenTelemetry/CHANGELOG.md)
for details.

* NuGet: [OpenTelemetry.Api
v1.16.0](https://www.nuget.org/packages/OpenTelemetry.Api/1.16.0)

  No notable changes.

See
[CHANGELOG](https://github.com/open-telemetry/opentelemetry-dotnet/blob/core-1.16.0/src/OpenTelemetry.Api/CHANGELOG.md)
for details.

* NuGet: [OpenTelemetry.Api.ProviderBuilderExtensions
v1.16.0](https://www.nuget.org/packages/OpenTelemetry.Api.ProviderBuilderExtensions/1.16.0)

  No notable changes.

See
[CHANGELOG](https://github.com/open-telemetry/opentelemetry-dotnet/blob/core-1.16.0/src/OpenTelemetry.Api.ProviderBuilderExtensions/CHANGELOG.md)
for details.

* NuGet: [OpenTelemetry.Exporter.Console
v1.16.0](https://www.nuget.org/packages/OpenTelemetry.Exporter.Console/1.16.0)

  No notable changes.

See
[CHANGELOG](https://github.com/open-telemetry/opentelemetry-dotnet/blob/core-1.16.0/src/OpenTelemetry.Exporter.Console/CHANGELOG.md)
for details.

* NuGet: [OpenTelemetry.Exporter.InMemory
v1.16.0](https://www.nuget.org/packages/OpenTelemetry.Exporter.InMemory/1.16.0)

  No notable changes.

See
[CHANGELOG](https://github.com/open-telemetry/opentelemetry-dotnet/blob/core-1.16.0/src/OpenTelemetry.Exporter.InMemory/CHANGELOG.md)
for details.

* NuGet: [OpenTelemetry.Exporter.OpenTelemetryProtocol
v1.16.0](https://www.nuget.org/packages/OpenTelemetry.Exporter.OpenTelemetryProtocol/1.16.0)

  No notable changes.

See
[CHANGELOG](https://github.com/open-telemetry/opentelemetry-dotnet/blob/core-1.16.0/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md)
for details.

* NuGet: [OpenTelemetry.Exporter.Zipkin
v1.16.0](https://www.nuget.org/packages/OpenTelemetry.Exporter.Zipkin/1.16.0)

  No notable changes.

See
[CHANGELOG](https://github.com/open-telemetry/opentelemetry-dotnet/blob/core-1.16.0/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md)
for details.

* NuGet: [OpenTelemetry.Extensions.Hosting
v1.16.0](https://www.nuget.org/packages/OpenTelemetry.Extensions.Hosting/1.16.0)

  No notable changes.

 ... (truncated)

## 1.16.0-rc.1

The following changes are from the previous release
[1.15.3](https://github.com/open-telemetry/opentelemetry-dotnet/releases/tag/core-1.15.3).

* NuGet: [OpenTelemetry
v1.16.0-rc.1](https://www.nuget.org/packages/OpenTelemetry/1.16.0-rc.1)

* Stop validating View-provided metric stream `Name` against the
instrument
    name syntax, per
[spec
clarification](open-telemetry/opentelemetry-specification#5094).

([#​7300](open-telemetry/opentelemetry-dotnet#7300))
  
* Fix incorrect validation of `OTEL_BSP_*` and `OTEL_BLRP_*` environment
    variables.

([#​7187](open-telemetry/opentelemetry-dotnet#7187))
  
* Fix observable instrument callbacks running once per reader instead of
    once per collection cycle.

([#​7188](open-telemetry/opentelemetry-dotnet#7188))
  
* Added exception safety for user-supplied `ExemplarReservoir`
implementations.
Exceptions thrown from `Offer` are now caught and logged rather than
propagating
    out of `Counter.Add`/`Histogram.Record`.

([#​7277](open-telemetry/opentelemetry-dotnet#7277))
  
* Update `OpenTelemetrySdkEventSource` to support the W3C randomness
flag.

([#​7301](open-telemetry/opentelemetry-dotnet#7301))
  
  * Added `ObservedTimestamp` property to `LogRecord`.

([#​6979](open-telemetry/opentelemetry-dotnet#6979))
  
* **Breaking Change** Explicit histogram boundaries no longer allow more
than
    10 million values.

([#​7165](open-telemetry/opentelemetry-dotnet#7165))
  
* Fixed a circular reference which could cause a `LoggerProvider` to
fail to
resolve when one of its dependencies depends on `ILogger` or
`ILoggerFactory`.
As part of this fix the `LoggerProvider` resolved from dependency
injection
is now created lazily when the first logger is created rather than when
`ILoggerProvider` or `ILoggerFactory` is resolved. A consequence is that
any
invalid configuration now surfaces when the first log record is written
instead
    of when the logging services are resolved.

([#​7308](open-telemetry/opentelemetry-dotnet#7308))

See
[CHANGELOG](https://github.com/open-telemetry/opentelemetry-dotnet/blob/core-1.16.0-rc.1/src/OpenTelemetry/CHANGELOG.md)
for details.

* NuGet: [OpenTelemetry.Api
v1.16.0-rc.1](https://www.nuget.org/packages/OpenTelemetry.Api/1.16.0-rc.1)

  * **Experimental (pre-release builds only):**
Add support for using environment variables as context propagation
carriers.

([#​7174](open-telemetry/opentelemetry-dotnet#7174))
  
* Fix `BaggagePropagator` to correctly follow Key and Value Encoding
rules as per
 ... (truncated)

## 1.16.0-beta.1

The following changes are from the previous release
[1.15.3-beta.1](https://github.com/open-telemetry/opentelemetry-dotnet/releases/tag/coreunstable-1.15.3-beta.1).

* NuGet: [OpenTelemetry.Exporter.Prometheus.AspNetCore
v1.16.0-beta.1](https://www.nuget.org/packages/OpenTelemetry.Exporter.Prometheus.AspNetCore/1.16.0-beta.1)

* Fixed scrape response cache freshness using monotonic time so it is
not
    affected by NTP system clock adjustments.

([#​7253](open-telemetry/opentelemetry-dotnet#7253))
  
  * **Breaking Change** Removed `DisableTimestamp` property from
    `PrometheusAspNetCoreOptions`.

([#​7176](open-telemetry/opentelemetry-dotnet#7176))
  
* Fixed the serialization of `NaN`, `PositiveInfinity`, and
`NegativeInfinity`
    values in Prometheus metrics to be compliant with the specification.

([#​7179](open-telemetry/opentelemetry-dotnet#7179))
  
* Fixed loss of precision when serializing `double` and `float` values
in
Prometheus metrics to be compliant with the specification by using 17
    significant digits to represent such values.

([#​7179](open-telemetry/opentelemetry-dotnet#7179))
  
* Fix non-ASCII characters in metric names and unit strings not being
sanitized
    correctly during Prometheus serialization.

([#​7184](open-telemetry/opentelemetry-dotnet#7184))
  
* Fix case where reader tracking could be reset while readers were still
active.

([#​7190](open-telemetry/opentelemetry-dotnet#7190))
  
* Improve `Accept` header handling for format negotiation so OpenMetrics
is
    selected correctly by considering whitespace and `q` weights.

([#​7208](open-telemetry/opentelemetry-dotnet#7208))
  
  * Emit OpenMetrics exemplars for counters and histogram buckets.

([#​7222](open-telemetry/opentelemetry-dotnet#7222))
  
* Fix incorrect handling of untyped metrics when using OpenMetrics
format.

([#​7219](open-telemetry/opentelemetry-dotnet#7219))
  
* Fix Prometheus/OpenMetrics serialization to emit metric and label
names
containing `_` instead of dropping them and prefixing leading digits.
    Invalid characters are replaced with `_` instead of being dropped.

([#​7209](open-telemetry/opentelemetry-dotnet#7209))
  
* Add `escaping=underscores` to the `Accept` header handling for content
    negotiation so OpenMetrics are handled correctly.

([#​7209](open-telemetry/opentelemetry-dotnet#7209))
  
* Omit histogram `_sum` and `_count` in OpenMetrics when negative bucket
    thresholds are present.

([#​7221](open-telemetry/opentelemetry-dotnet#7221))
 ... (truncated)

Commits viewable in [compare
view](open-telemetry/opentelemetry-dotnet@core-1.15.3...core-1.16.0).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=OpenTelemetry.Exporter.OpenTelemetryProtocol&package-manager=nuget&previous-version=1.15.3&new-version=1.16.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Vitor M <4777793+vgmello@users.noreply.github.com>
This was referenced Jun 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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