Skip to content
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
15ba450
[Exporter.Prometheus] Fix scope metadata
martincostello May 1, 2026
db4ca48
[Exporter.Prometheus] Update test cases
martincostello May 1, 2026
50942c7
[Exporter.Prometheus] Update CHANGELOGs
martincostello May 1, 2026
60a53b7
[Exporter.Prometheus] Address feedback
martincostello May 1, 2026
65db37d
Merge branch 'main' into fix-scope-metadata
martincostello May 1, 2026
a51c12a
[Exporter.Prometheus] Extend coverage
martincostello May 1, 2026
48c6919
Merge branch 'main' into fix-scope-metadata
martincostello May 4, 2026
9402121
Merge branch 'main' into fix-scope-metadata
martincostello May 5, 2026
ab0849c
Merge branch 'main' into fix-scope-metadata
martincostello May 5, 2026
926f714
[Exporter.Prometheus] Update CHANGELOGs
martincostello May 5, 2026
25e7374
Merge branch 'main' into fix-scope-metadata
martincostello May 13, 2026
00ab131
Merge branch 'main' into fix-scope-metadata
martincostello May 18, 2026
c5d2abb
Merge branch 'main' into fix-scope-metadata
martincostello May 19, 2026
9dfc038
[Exporter.Prometheus] Address feedback
martincostello May 19, 2026
a5a99b4
[Exporter.Prometheus] Fix CHANGELOGs
martincostello May 19, 2026
a9846cd
Merge branch 'main' into fix-scope-metadata
martincostello May 22, 2026
92924ae
Merge branch 'main' into fix-scope-metadata
martincostello May 30, 2026
691f9ce
[Exporter.Prometheus] Fix-up merge
martincostello May 30, 2026
36bbbe9
[Exporter.Prometheus] Address feedback
martincostello May 30, 2026
98141c1
Merge branch 'main' into fix-scope-metadata
martincostello Jun 1, 2026
44fa775
[Exporter.Prometheus] Fix SA1203
martincostello Jun 1, 2026
34ac7ea
[Exporter.Prometheus] Address feedback
martincostello Jun 1, 2026
0658b03
Merge branch 'main' into fix-scope-metadata
martincostello Jun 2, 2026
191f148
[Exporter.Prometheus] Address feedback
martincostello Jun 2, 2026
06d421f
[Exporter.Prometheus] Use FrozenSet
martincostello Jun 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 deletions src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,45 +26,45 @@ Notes](../../RELEASENOTES.md).

* Fix non-ASCII characters in metric names and unit strings not being sanitized
correctly during Prometheus serialization.
([#7184](https://github.com/open-telemetry/opentelemetry-dotnet/issues/7184))
([#7184](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7184))

* Fix case where reader tracking could be reset while readers were still active.
([#7190](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7190))

* Improve `Accept` header handling for format negotiation so OpenMetrics is
selected correctly by considering whitespace and `q` weights.
([#7208](https://github.com/open-telemetry/opentelemetry-dotnet/issues/7208))
([#7208](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7208))

* Emit OpenMetrics exemplars for counters and histogram buckets.
([#7222](https://github.com/open-telemetry/opentelemetry-dotnet/issues/7222))
([#7222](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7222))

* Fix incorrect handling of untyped metrics when using OpenMetrics format.
([#7219](https://github.com/open-telemetry/opentelemetry-dotnet/issues/7219))
([#7219](https://github.com/open-telemetry/opentelemetry-dotnet/pull/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](https://github.com/open-telemetry/opentelemetry-dotnet/issues/7209))
([#7209](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7209))

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

* Omit histogram `_sum` and `_count` in OpenMetrics when negative bucket
thresholds are present.
([#7221](https://github.com/open-telemetry/opentelemetry-dotnet/issues/7221))
([#7221](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7221))

* Fix `ArgumentException` if `OTEL_SDK_DISABLED=true`.
([#7273](https://github.com/open-telemetry/opentelemetry-dotnet/issues/7273))
([#7273](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7273))

* Update `Accept` header parsing to more closely follow the Prometheus
[Scrape protocol content negotiation](https://prometheus.io/docs/instrumenting/content_negotiation/)
specification.
([#7266](https://github.com/open-telemetry/opentelemetry-dotnet/issues/7266))
([#7266](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7266))

* Abort scrape request processing if request exceeds the value specified by the
`X-Prometheus-Scrape-Timeout-Seconds` HTTP request header.
([#7252](https://github.com/open-telemetry/opentelemetry-dotnet/issues/7252))
([#7252](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7252))

* Use the canonical representation for histogram "le" label values when using
OpenMetrics.
Expand All @@ -84,13 +84,21 @@ Notes](../../RELEASENOTES.md).
specified by the HTTP request headers.
([#7274](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7274))

* Include instrumentation scope metadata on samples using `otel_scope_*` labels
including scope version, schema URL, and prefixed scope attributes. OpenMetrics
output no longer emits a separate `otel_scope_info` scope metadata metric.
([#7237](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7237))

* Drop conflicting scope attributes named `name`, `version`, and `schema_url`.
([#7237](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7237))

## 1.15.3-beta.1

Released 2026-Apr-21

* Fixed metric unit strings containing invalid Prometheus characters (e.g. `# RU`)
not being sanitized, resulting in malformed metric names.
([#6187](https://github.com/open-telemetry/opentelemetry-dotnet/issues/6187))
([#7033](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7033))

* Fixed Prometheus metric serialization to handle empty label names without
throwing during scrape rendering.
Expand Down
28 changes: 18 additions & 10 deletions src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Notes](../../RELEASENOTES.md).

* Fix non-ASCII characters in metric names and unit strings not being sanitized
correctly during Prometheus serialization.
([#7184](https://github.com/open-telemetry/opentelemetry-dotnet/issues/7184))
([#7184](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7184))

* Add support for caching the scrape endpoint HTTP responses using the
`PrometheusHttpListenerOptions.ScrapeResponseCacheDurationMilliseconds` option.
Expand All @@ -45,13 +45,13 @@ Notes](../../RELEASENOTES.md).

* Improve `Accept` header handling for format negotiation so OpenMetrics is
selected correctly by considering whitespace and `q` weights.
([#7208](https://github.com/open-telemetry/opentelemetry-dotnet/issues/7208))
([#7208](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7208))

* Emit OpenMetrics exemplars for counters and histogram buckets.
([#7222](https://github.com/open-telemetry/opentelemetry-dotnet/issues/7222))
([#7222](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7222))

* Fix incorrect handling of untyped metrics when using OpenMetrics format.
([#7219](https://github.com/open-telemetry/opentelemetry-dotnet/issues/7219))
([#7219](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7219))

* Add support for configuring the HTTP listener endpoint host and port using
the `OTEL_EXPORTER_PROMETHEUS_HOST` and `OTEL_EXPORTER_PROMETHEUS_PORT`
Expand All @@ -62,24 +62,24 @@ Notes](../../RELEASENOTES.md).
* Fix Prometheus/OpenMetrics serialization to emit metric and label names
containing and `_` instead of dropping them and prefixing leading digits.
Invalid characters are replaced with `_` instead of being dropped.
([#7209](https://github.com/open-telemetry/opentelemetry-dotnet/issues/7209))
([#7209](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7209))

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

* Omit histogram `_sum` and `_count` in OpenMetrics when negative bucket
thresholds are present.
([#7221](https://github.com/open-telemetry/opentelemetry-dotnet/issues/7221))
([#7221](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7221))

* Update `Accept` header parsing to more closely follow the Prometheus
[Scrape protocol content negotiation](https://prometheus.io/docs/instrumenting/content_negotiation/)
specification.
([#7266](https://github.com/open-telemetry/opentelemetry-dotnet/issues/7266))
([#7266](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7266))

* Abort scrape request processing if request exceeds the value specified by the
`X-Prometheus-Scrape-Timeout-Seconds` HTTP request header.
([#7252](https://github.com/open-telemetry/opentelemetry-dotnet/issues/7252))
([#7252](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7252))

* Use the canonical representation for histogram "le" label values when using
OpenMetrics.
Expand All @@ -95,13 +95,21 @@ Notes](../../RELEASENOTES.md).
OpenMetrics and a start time is available.
([#7223](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7223))

* Include instrumentation scope metadata on samples using `otel_scope_*` labels
including scope version, schema URL, and prefixed scope attributes. OpenMetrics
output no longer emits a separate `otel_scope_info` scope metadata metric.
([#7237](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7237))

* Drop conflicting scope attributes named `name`, `version`, and `schema_url`.
([#7237](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7237))

## 1.15.3-beta.1

Released 2026-Apr-21

* Fixed metric unit strings containing invalid Prometheus characters (e.g. `# RU`)
not being sanitized, resulting in malformed metric names.
([#6187](https://github.com/open-telemetry/opentelemetry-dotnet/issues/6187))
([#7033](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7033))

* Fixed Prometheus metric serialization to handle empty label names without
throwing during scrape rendering.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ internal sealed class PrometheusCollectionManager
private readonly long baseTimestamp = Stopwatch.GetTimestamp();
private readonly PrometheusExporter.ExportFunc onCollectRef;
private readonly Dictionary<Metric, PrometheusMetric> metricsCache;
private readonly HashSet<string> scopes;
private int metricsCacheCount;
private byte[] plainTextBuffer = new byte[85000]; // encourage the object to live in LOH (large object heap)
private byte[] openMetricsBuffer = new byte[85000]; // encourage the object to live in LOH (large object heap)
Expand All @@ -39,7 +38,6 @@ public PrometheusCollectionManager(PrometheusExporter exporter)
this.scrapeResponseCacheDuration = TimeSpan.FromMilliseconds(this.exporter.ScrapeResponseCacheDurationMilliseconds);
this.onCollectRef = this.OnCollect;
this.metricsCache = [];
this.scopes = [];
this.GetElapsedTime = () => Stopwatch.GetElapsedTime(this.baseTimestamp);
}

Expand Down Expand Up @@ -235,52 +233,10 @@ private ExportResult OnCollect(in Batch<Metric> metrics)
{
var cursor = 0;
ref var buffer = ref (this.exporter.OpenMetricsRequested ? ref this.openMetricsBuffer : ref this.plainTextBuffer);

try
{
cursor = this.WriteTargetInfo(ref buffer);

if (this.exporter.OpenMetricsRequested)
{
this.scopes.Clear();
var writeScopeMetadata = true;

foreach (var metric in metrics)
{
if (!PrometheusSerializer.CanWriteMetric(metric))
{
continue;
}

if (this.scopes.Add(metric.MeterName))
{
while (true)
{
try
{
cursor = PrometheusSerializer.WriteScopeInfo(buffer, cursor, metric.MeterName, openMetricsRequested: true, writeMetadata: writeScopeMetadata);
writeScopeMetadata = false;

break;
}
catch (IndexOutOfRangeException)
{
if (!IncreaseBufferSize(ref buffer))
{
// there are two cases we might run into the following condition:
// 1. we have many metrics to be exported - in this case we probably want
// to put some upper limit and allow the user to configure it.
// 2. we got an IndexOutOfRangeException which was triggered by some other
// code instead of the buffer[cursor++] - in this case we should give up
// at certain point rather than allocating like crazy.
throw;
}
}
}
}
}
}

var metricStates = this.GetMetricStates(metrics, this.exporter.OpenMetricsRequested);

foreach (var metricState in metricStates)
Expand Down Expand Up @@ -407,7 +363,7 @@ private List<MetricState> GetMetricStates(in Batch<Metric> metrics, bool openMet
{
var precomputedMetricStates = new List<PrecomputedMetricState>();
var metadataStates = new Dictionary<string, MetadataState>(StringComparer.Ordinal);
var droppedMetricNames = new HashSet<string>(StringComparer.Ordinal);
HashSet<string>? droppedMetricNames = null;

foreach (var metric in metrics)
{
Expand All @@ -431,6 +387,7 @@ private List<MetricState> GetMetricStates(in Batch<Metric> metrics, bool openMet

if (metadataState.Type != prometheusMetric.Type)
{
droppedMetricNames ??= new(StringComparer.Ordinal);
droppedMetricNames.Add(metadataName);
PrometheusExporterEventSource.Log.ConflictingType(metadataName, metadataState.Type, prometheusMetric.Type);
}
Expand Down Expand Up @@ -484,7 +441,7 @@ private List<MetricState> GetMetricStates(in Batch<Metric> metrics, bool openMet

foreach (var metricState in precomputedMetricStates)
{
if (droppedMetricNames.Contains(metricState.MetadataName))
if (droppedMetricNames?.Contains(metricState.MetadataName) is true)
{
continue;
}
Expand Down
Loading