Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ OpenTelemetry.Exporter.PrometheusAspNetCoreOptions
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.DisableTotalNameSuffixForCounters.get -> bool
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.DisableTotalNameSuffixForCounters.set -> void
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.PrometheusAspNetCoreOptions() -> void
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ScopeInfoEnabled.get -> bool
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ScopeInfoEnabled.set -> void
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ScrapeEndpointPath.get -> string?
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ScrapeEndpointPath.set -> void
OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ScrapeResponseCacheDurationMilliseconds.get -> int
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ Notes](../../RELEASENOTES.md).
* Fix incorrect handling of leading digits in metric names for OpenMetrics.
([#7454](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7454))

* Add `PrometheusAspNetCoreOptions.ScopeInfoEnabled` property to enable or
disable scope labels in Prometheus metrics. Defaults to `true`.
([#7436](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7436))

## 1.16.0-beta.1

Released 2026-Jun-10
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ public bool DisableTotalNameSuffixForCounters
set => this.ExporterOptions.DisableTotalNameSuffixForCounters = value;
}

/// <summary>
/// Gets or sets a value indicating whether the scope information (name, version, schema URL) is added to the scrape response.
/// Default value: <see langword="true"/>.
/// </summary>
public bool ScopeInfoEnabled
{
get => this.ExporterOptions.ScopeInfoEnabled;
set => this.ExporterOptions.ScopeInfoEnabled = value;
}

/// <summary>
/// Gets or sets the cache duration in milliseconds for scrape responses. Default value: 300.
/// </summary>
Expand Down
6 changes: 6 additions & 0 deletions src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ to expose the scraping endpoint on a different port.
The `PrometheusExporter` can be configured using the `PrometheusAspNetCoreOptions`
properties.

### ScopeInfoEnabled

Specifies whether metrics include
[scope labels](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/compatibility/prometheus_and_openmetrics.md#instrumentation-scope-1).
Default value: `true`. Set to `false` to disable scope labels.

### ScrapeEndpointPath

Defines the path for the Prometheus scrape endpoint for the middleware
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ OpenTelemetry.Exporter.PrometheusHttpListenerOptions.Port.get -> int
OpenTelemetry.Exporter.PrometheusHttpListenerOptions.Port.set -> void
OpenTelemetry.Exporter.PrometheusHttpListenerOptions.DisableTotalNameSuffixForCounters.get -> bool
OpenTelemetry.Exporter.PrometheusHttpListenerOptions.DisableTotalNameSuffixForCounters.set -> void
OpenTelemetry.Exporter.PrometheusHttpListenerOptions.ScopeInfoEnabled.get -> bool
OpenTelemetry.Exporter.PrometheusHttpListenerOptions.ScopeInfoEnabled.set -> void
OpenTelemetry.Exporter.PrometheusHttpListenerOptions.PrometheusHttpListenerOptions() -> void
OpenTelemetry.Exporter.PrometheusHttpListenerOptions.ScrapeEndpointPath.get -> string?
OpenTelemetry.Exporter.PrometheusHttpListenerOptions.ScrapeEndpointPath.set -> void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ Notes](../../RELEASENOTES.md).
* Fix incorrect handling of leading digits in metric names for OpenMetrics.
([#7454](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7454))

* Add `PrometheusHttpListenerOptions.ScopeInfoEnabled` property to enable or
disable scope labels in Prometheus metrics. Defaults to `true`.
([#7436](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7436))

## 1.16.0-beta.1

Released 2026-Jun-10
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ internal sealed class PrometheusCollectionManager
private readonly ConcurrentDictionary<PrometheusProtocol, PrometheusProtocolState> protocolStates = new();

private readonly PrometheusExporter exporter;
private readonly bool scopeInfoEnabled;
private readonly TimeSpan scrapeResponseCacheDuration;
private readonly long baseTimestamp = Stopwatch.GetTimestamp();
private readonly PrometheusExporter.ExportFunc onCollectRef;
Expand All @@ -29,6 +30,7 @@ internal sealed class PrometheusCollectionManager
public PrometheusCollectionManager(PrometheusExporter exporter)
{
this.exporter = exporter;
this.scopeInfoEnabled = this.exporter.ScopeInfoEnabled;
this.scrapeResponseCacheDuration = TimeSpan.FromMilliseconds(this.exporter.ScrapeResponseCacheDurationMilliseconds);
this.onCollectRef = this.OnCollect;
this.metricsCache = [];
Expand Down Expand Up @@ -353,6 +355,7 @@ private bool TryWriteResponse(PrometheusProtocol protocol, PrometheusProtocolSta

var cursor = this.WriteTargetInfo(serializer, state);
var metricStates = this.GetMetricStates(serializer, metrics);
var options = new TextFormatSerializerOptions(suppressScopeInfo: !this.scopeInfoEnabled);

foreach (var metricState in metricStates)
{
Expand All @@ -369,7 +372,8 @@ private bool TryWriteResponse(PrometheusProtocol protocol, PrometheusProtocolSta
metricState.WriteUnit,
metricState.WriteHelp,
metricState.Unit,
metricState.Help);
metricState.Help,
options);

break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public PrometheusExporter(PrometheusExporterOptions options)
{
Guard.ThrowIfNull(options);

this.ScopeInfoEnabled = options.ScopeInfoEnabled;
this.ScrapeResponseCacheDurationMilliseconds = options.ScrapeResponseCacheDurationMilliseconds;
this.DisableTotalNameSuffixForCounters = options.DisableTotalNameSuffixForCounters;

Expand All @@ -42,6 +43,8 @@ public PrometheusExporter(PrometheusExporterOptions options)

internal PrometheusCollectionManager CollectionManager { get; }

internal bool ScopeInfoEnabled { get; }

internal int ScrapeResponseCacheDurationMilliseconds { get; }

internal bool DisableTotalNameSuffixForCounters { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,16 @@ internal sealed class PrometheusExporterOptions
{
public PrometheusExporterOptions()
{
this.ScopeInfoEnabled = true;
this.ScrapeResponseCacheDurationMilliseconds = 300;
}

/// <summary>
/// Gets or sets a value indicating whether the scope information (name, version, schema URL) is added to the scrape response.
/// Default value: <see langword="true"/>.
/// </summary>
public bool ScopeInfoEnabled { get; set; }

/// <summary>
/// Gets or sets the cache duration in milliseconds for scrape responses. Default value: 300.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@ protected override int WriteExplicitBound(byte[] buffer, int cursor, double expl
protected override bool ShouldWriteSumAndCount(bool hasNegativeBucketBounds)
=> !hasNegativeBucketBounds;

protected override int WriteCounterExemplar(byte[] buffer, int cursor, in MetricPoint metricPoint, PrometheusMetric prometheusMetric, bool isLongValue)
protected override int WriteCounterExemplar(
byte[] buffer,
int cursor,
in MetricPoint metricPoint,
PrometheusMetric prometheusMetric,
bool isLongValue)
{
if (prometheusMetric.Type == PrometheusType.Counter &&
TryGetLatestExemplar(metricPoint, out var exemplar))
Expand All @@ -63,11 +68,17 @@ protected override int WriteCounterExemplar(byte[] buffer, int cursor, in Metric
return cursor;
}

protected override int WriteCounterCreated(byte[] buffer, int cursor, Metric metric, PrometheusMetric prometheusMetric, in MetricPoint metricPoint)
protected override int WriteCounterCreated(
byte[] buffer,
int cursor,
Metric metric,
PrometheusMetric prometheusMetric,
in MetricPoint metricPoint,
in TextFormatSerializerOptions options)
{
if (prometheusMetric.Type == PrometheusType.Counter)
{
cursor = this.WriteCreatedMetric(buffer, cursor, metric, prometheusMetric, metricPoint);
cursor = this.WriteCreatedMetric(buffer, cursor, metric, prometheusMetric, metricPoint, options);
}

return cursor;
Expand All @@ -83,8 +94,8 @@ protected override int WriteHistogramBucketExemplar(byte[] buffer, int cursor, i
return cursor;
}

protected override int WriteHistogramCreated(byte[] buffer, int cursor, Metric metric, PrometheusMetric prometheusMetric, in MetricPoint metricPoint)
=> this.WriteCreatedMetric(buffer, cursor, metric, prometheusMetric, metricPoint, ReservedHistogramLabelNames);
protected override int WriteHistogramCreated(byte[] buffer, int cursor, Metric metric, PrometheusMetric prometheusMetric, in MetricPoint metricPoint, in TextFormatSerializerOptions options)
=> this.WriteCreatedMetric(buffer, cursor, metric, prometheusMetric, metricPoint, options, ReservedHistogramLabelNames);

private static bool TryGetLatestExemplar(in MetricPoint metricPoint, out Exemplar exemplar)
{
Expand Down Expand Up @@ -150,12 +161,13 @@ private int WriteCreatedMetric(
Metric metric,
PrometheusMetric prometheusMetric,
in MetricPoint metricPoint,
in TextFormatSerializerOptions options,
IReadOnlyCollection<string>? reservedOutputKeys = null)
{
cursor = this.WriteMetricMetadataName(buffer, cursor, prometheusMetric);

cursor = WriteAsciiStringNoEscape(buffer, cursor, "_created");
cursor = WriteTags(buffer, cursor, metric, metricPoint.Tags, reservedOutputKeys: reservedOutputKeys);
cursor = WriteTags(buffer, cursor, metric, metricPoint.Tags, options, reservedOutputKeys: reservedOutputKeys);

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ protected override bool ShouldWriteSumAndCount(bool hasNegativeBucketBounds)
protected override int WriteCounterExemplar(byte[] buffer, int cursor, in MetricPoint metricPoint, PrometheusMetric prometheusMetric, bool isLongValue)
=> cursor;

protected override int WriteCounterCreated(byte[] buffer, int cursor, Metric metric, PrometheusMetric prometheusMetric, in MetricPoint metricPoint)
protected override int WriteCounterCreated(byte[] buffer, int cursor, Metric metric, PrometheusMetric prometheusMetric, in MetricPoint metricPoint, in TextFormatSerializerOptions options)
=> cursor;

protected override int WriteHistogramBucketExemplar(byte[] buffer, int cursor, in MetricPoint metricPoint, double lowerBoundExclusive, double upperBoundInclusive)
=> cursor;

protected override int WriteHistogramCreated(byte[] buffer, int cursor, Metric metric, PrometheusMetric prometheusMetric, in MetricPoint metricPoint)
protected override int WriteHistogramCreated(byte[] buffer, int cursor, Metric metric, PrometheusMetric prometheusMetric, in MetricPoint metricPoint, in TextFormatSerializerOptions options)
=> cursor;
}
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ public int WriteMetric(
bool writeUnit,
bool writeHelp,
string? unitOverride,
string? helpOverride)
string? helpOverride,
in TextFormatSerializerOptions options = default)
{
if (writeType)
{
Expand All @@ -168,7 +169,7 @@ public int WriteMetric(
{
// Counter and Gauge
cursor = this.WriteMetricName(buffer, cursor, prometheusMetric);
cursor = WriteTags(buffer, cursor, metric, metricPoint.Tags);
cursor = WriteTags(buffer, cursor, metric, metricPoint.Tags, options);

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

Expand All @@ -189,15 +190,15 @@ public int WriteMetric(

buffer[cursor++] = AsciiLineFeed;

cursor = this.WriteCounterCreated(buffer, cursor, metric, prometheusMetric, in metricPoint);
cursor = this.WriteCounterCreated(buffer, cursor, metric, prometheusMetric, in metricPoint, in options);
}
}
else
{
foreach (ref readonly var metricPoint in metric.GetMetricPoints())
{
var tags = metricPoint.Tags;
var serializedTags = SerializeTags(metric, tags, ReservedHistogramLabelNames);
var serializedTags = SerializeTags(metric, tags, options, ReservedHistogramLabelNames);
var hasNegativeBucketBounds = false;
var previousBound = double.NegativeInfinity;

Expand Down Expand Up @@ -259,7 +260,7 @@ public int WriteMetric(
buffer[cursor++] = AsciiLineFeed;
}

cursor = this.WriteHistogramCreated(buffer, cursor, metric, prometheusMetric, in metricPoint);
cursor = this.WriteHistogramCreated(buffer, cursor, metric, prometheusMetric, in metricPoint, in options);
}
}

Expand Down Expand Up @@ -575,6 +576,7 @@ internal static int WriteTags(
int cursor,
Metric metric,
ReadOnlyTagCollection tags,
in TextFormatSerializerOptions options,
bool writeEnclosingBraces = true,
IReadOnlyCollection<string>? reservedOutputKeys = null)
{
Expand All @@ -587,7 +589,10 @@ internal static int WriteTags(
buffer[cursor++] = unchecked((byte)'{');
}

WriteScopeLabels();
if (!options.SuppressScopeInfo)
{
WriteScopeLabels();
}

if (TryWritePointTags())
{
Comment thread
martincostello marked this conversation as resolved.
Expand Down Expand Up @@ -683,6 +688,7 @@ internal static int WriteUnixTimeSeconds(byte[] buffer, int cursor, DateTimeOffs
internal static byte[] SerializeTags(
Metric metric,
ReadOnlyTagCollection tags,
in TextFormatSerializerOptions options,
IReadOnlyCollection<string>? reservedOutputKeys = null)
{
var buffer = new byte[128];
Expand All @@ -696,6 +702,7 @@ internal static byte[] SerializeTags(
0,
metric,
tags,
options,
writeEnclosingBraces: false,
reservedOutputKeys: reservedOutputKeys);

Expand Down Expand Up @@ -873,7 +880,12 @@ internal int WriteUnitMetadata(byte[] buffer, int cursor, PrometheusMetric metri
/// <param name="prometheusMetric">The Prometheus metric.</param>
/// <param name="isLongValue">Indicates whether the value is a long.</param>
/// <returns>The new cursor position after writing.</returns>
protected abstract int WriteCounterExemplar(byte[] buffer, int cursor, in MetricPoint metricPoint, PrometheusMetric prometheusMetric, bool isLongValue);
protected abstract int WriteCounterExemplar(
byte[] buffer,
int cursor,
in MetricPoint metricPoint,
PrometheusMetric prometheusMetric,
bool isLongValue);

/// <summary>
/// Writes the <c>_created</c> series (if any) that follows a counter sample.
Expand All @@ -883,8 +895,15 @@ internal int WriteUnitMetadata(byte[] buffer, int cursor, PrometheusMetric metri
/// <param name="metric">The metric.</param>
/// <param name="prometheusMetric">The Prometheus metric.</param>
/// <param name="metricPoint">The metric point.</param>
/// <param name="options">The serializer options.</param>
/// <returns>The new cursor position after writing.</returns>
protected abstract int WriteCounterCreated(byte[] buffer, int cursor, Metric metric, PrometheusMetric prometheusMetric, in MetricPoint metricPoint);
protected abstract int WriteCounterCreated(
byte[] buffer,
int cursor,
Metric metric,
PrometheusMetric prometheusMetric,
in MetricPoint metricPoint,
in TextFormatSerializerOptions options);

/// <summary>
/// Writes the exemplar (if any) that follows a histogram bucket sample value.
Expand All @@ -895,7 +914,12 @@ internal int WriteUnitMetadata(byte[] buffer, int cursor, PrometheusMetric metri
/// <param name="lowerBoundExclusive">The exclusive lower bound of the histogram bucket.</param>
/// <param name="upperBoundInclusive">The inclusive upper bound of the histogram bucket.</param>
/// <returns>The new cursor position after writing.</returns>
protected abstract int WriteHistogramBucketExemplar(byte[] buffer, int cursor, in MetricPoint metricPoint, double lowerBoundExclusive, double upperBoundInclusive);
protected abstract int WriteHistogramBucketExemplar(
byte[] buffer,
int cursor,
in MetricPoint metricPoint,
double lowerBoundExclusive,
double upperBoundInclusive);

/// <summary>
/// Determines whether the histogram <c>_sum</c> and <c>_count</c> series should be written.
Expand All @@ -914,8 +938,15 @@ internal int WriteUnitMetadata(byte[] buffer, int cursor, PrometheusMetric metri
/// <param name="metric">The metric.</param>
/// <param name="prometheusMetric">The Prometheus metric.</param>
/// <param name="metricPoint">The metric point.</param>
/// <param name="options">The serializer options.</param>
/// <returns>The new cursor position after writing.</returns>
protected abstract int WriteHistogramCreated(byte[] buffer, int cursor, Metric metric, PrometheusMetric prometheusMetric, in MetricPoint metricPoint);
protected abstract int WriteHistogramCreated(
byte[] buffer,
int cursor,
Metric metric,
PrometheusMetric prometheusMetric,
in MetricPoint metricPoint,
in TextFormatSerializerOptions options);

private static string GetLabelValueString(object? labelValue) => labelValue switch
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

namespace OpenTelemetry.Exporter.Prometheus.Serialization;

/// <summary>
/// Options for <see cref="TextFormatSerializer"/>.
/// </summary>
internal readonly struct TextFormatSerializerOptions
{
/// <summary>
/// A value indicating whether the scope information (name, version, schema URL) is suppressed from the scrape response.
/// </summary>
public readonly bool SuppressScopeInfo; // Inverted so the default struct is the default value (false = included).

/// <summary>
/// Initializes a new instance of the <see cref="TextFormatSerializerOptions"/> struct.
/// </summary>
/// <param name="suppressScopeInfo">Whether the scope information is suppressed from the scrape response.</param>
public TextFormatSerializerOptions(bool suppressScopeInfo)
{
this.SuppressScopeInfo = suppressScopeInfo;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ private static BaseExportingMetricReader BuildPrometheusHttpListenerMetricReader
{
var exporter = new PrometheusExporter(new PrometheusExporterOptions
{
ScopeInfoEnabled = options.ScopeInfoEnabled,
ScrapeResponseCacheDurationMilliseconds = options.ScrapeResponseCacheDurationMilliseconds,
DisableTotalNameSuffixForCounters = options.DisableTotalNameSuffixForCounters,
});
Expand Down
Loading