diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/PublicAPI.Unshipped.txt index cba2e2aea0a..9e08604f954 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/.publicApi/PublicAPI.Unshipped.txt @@ -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.ResourceConstantLabels.get -> System.Func? +OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ResourceConstantLabels.set -> void OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ScopeInfoEnabled.get -> bool OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ScopeInfoEnabled.set -> void OpenTelemetry.Exporter.PrometheusAspNetCoreOptions.ScrapeEndpointPath.get -> string? diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md index c975dde0869..87c0a0a3f55 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md @@ -35,6 +35,11 @@ Notes](../../RELEASENOTES.md). when negotiated via the `Accept` header. ([#7440](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7440)) +* Add `PrometheusAspNetCoreOptions.ResourceConstantLabels` property to select + resource attributes to add to each metric as constant labels. Defaults to + `null` (no resource attributes are added as metric labels). + ([#7471](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7471)) + ## 1.16.0-beta.1 Released 2026-Jun-10 diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusAspNetCoreOptions.cs b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusAspNetCoreOptions.cs index 5a5c75401b2..2a1a9f12bac 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusAspNetCoreOptions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/PrometheusAspNetCoreOptions.cs @@ -58,5 +58,20 @@ public bool TargetInfoEnabled set => this.ExporterOptions.TargetInfoEnabled = value; } + /// + /// Gets or sets a predicate used to select which resource attributes are added to each metric as constant labels. + /// The predicate is invoked with the resource attribute key and should return to include the + /// attribute. Default value: (no resource attributes are added as metric labels). + /// + /// + /// Note: Resource attributes copied as metric labels are always included in the target_info metric + /// regardless of this predicate. + /// + public Func? ResourceConstantLabels + { + get => this.ExporterOptions.ResourceConstantLabels; + set => this.ExporterOptions.ResourceConstantLabels = value; + } + internal PrometheusExporterOptions ExporterOptions { get; } = new(); } diff --git a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md index 30493347d06..834ad150d59 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md +++ b/src/OpenTelemetry.Exporter.Prometheus.AspNetCore/README.md @@ -148,6 +148,26 @@ Specifies whether to produce a [`target_info`](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/compatibility/prometheus_and_openmetrics.md#resource-attributes-1) metric. Default value: `true`. Set to `false` to disable the `target_info` metric. +### ResourceConstantLabels + +A predicate used to select which +[resource attributes](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/prometheus.md#resource-attributes-as-metric-labels) +are added to each metric as constant labels. The predicate is invoked with the +resource attribute key and should return `true` to include the attribute. +Default value: `null` (no resource attributes are added as metric labels). +Resource attributes copied as metric labels are always included in the +`target_info` metric regardless of this predicate. + +```csharp +services.AddOpenTelemetry() + .WithMetrics(builder => builder + .AddPrometheusExporter(options => + { + // Add all resource attributes as metric labels. + options.ResourceConstantLabels = static _ => true; + })); +``` + ## Troubleshooting This component uses an diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/PublicAPI.Unshipped.txt index d75614e7e12..3c1097b0df7 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/.publicApi/PublicAPI.Unshipped.txt @@ -9,6 +9,8 @@ OpenTelemetry.Exporter.PrometheusHttpListenerOptions.DisableTotalNameSuffixForCo OpenTelemetry.Exporter.PrometheusHttpListenerOptions.DisableTotalNameSuffixForCounters.set -> void OpenTelemetry.Exporter.PrometheusHttpListenerOptions.ScopeInfoEnabled.get -> bool OpenTelemetry.Exporter.PrometheusHttpListenerOptions.ScopeInfoEnabled.set -> void +OpenTelemetry.Exporter.PrometheusHttpListenerOptions.ResourceConstantLabels.get -> System.Func? +OpenTelemetry.Exporter.PrometheusHttpListenerOptions.ResourceConstantLabels.set -> void OpenTelemetry.Exporter.PrometheusHttpListenerOptions.TargetInfoEnabled.get -> bool OpenTelemetry.Exporter.PrometheusHttpListenerOptions.TargetInfoEnabled.set -> void OpenTelemetry.Exporter.PrometheusHttpListenerOptions.PrometheusHttpListenerOptions() -> void diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md index 5aad537d7df..c5dbddd30fa 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md @@ -41,6 +41,11 @@ Notes](../../RELEASENOTES.md). when negotiated via the `Accept` header. ([#7440](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7440)) +* Add `PrometheusHttpListenerOptions.ResourceConstantLabels` property to select + resource attributes to add to each metric as constant labels. Defaults to + `null` (no resource attributes are added as metric labels). + ([#7471](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7471)) + ## 1.16.0-beta.1 Released 2026-Jun-10 diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/PrometheusCollectionManager.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/PrometheusCollectionManager.cs index a8f5f65e5ce..be2d07bd8ad 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/PrometheusCollectionManager.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/PrometheusCollectionManager.cs @@ -18,11 +18,14 @@ internal sealed class PrometheusCollectionManager private readonly PrometheusExporter exporter; private readonly bool scopeInfoEnabled; private readonly bool targetInfoEnabled; + private readonly Func? resourceConstantLabelsFilter; private readonly TimeSpan scrapeResponseCacheDuration; private readonly long baseTimestamp = Stopwatch.GetTimestamp(); private readonly PrometheusExporter.ExportFunc onCollectRef; private readonly Dictionary metricsCache; private int metricsCacheCount; + private IReadOnlyList>? resourceConstantLabels; + private bool resourceConstantLabelsComputed; private int globalLockState; private CollectionContext? collectionContext; private CollectionContext? onCollectContext; @@ -33,6 +36,7 @@ public PrometheusCollectionManager(PrometheusExporter exporter) this.exporter = exporter; this.scopeInfoEnabled = this.exporter.ScopeInfoEnabled; this.targetInfoEnabled = this.exporter.TargetInfoEnabled; + this.resourceConstantLabelsFilter = this.exporter.ResourceConstantLabels; this.scrapeResponseCacheDuration = TimeSpan.FromMilliseconds(this.exporter.ScrapeResponseCacheDurationMilliseconds); this.onCollectRef = this.OnCollect; this.metricsCache = []; @@ -357,7 +361,9 @@ private bool TryWriteResponse(in PrometheusProtocol protocol, PrometheusProtocol var cursor = this.targetInfoEnabled ? this.WriteTargetInfo(serializer, state) : 0; var metricStates = this.GetMetricStates(serializer, metrics); - var options = new TextFormatSerializerOptions(suppressScopeInfo: !this.scopeInfoEnabled); + var options = new TextFormatSerializerOptions( + suppressScopeInfo: !this.scopeInfoEnabled, + resourceConstantLabels: this.GetResourceConstantLabels()); foreach (var metricState in metricStates) { @@ -477,6 +483,32 @@ state.GeneratedAtElapsed is { } generatedAtElapsed && private PrometheusProtocolState GetProtocolState(in PrometheusProtocol protocol) => this.protocolStates.GetOrAdd(protocol, static _ => new()); + private IReadOnlyList>? GetResourceConstantLabels() + { + if (!this.resourceConstantLabelsComputed) + { + if (this.resourceConstantLabelsFilter is { } filter) + { + List>? labels = null; + + foreach (var attribute in this.exporter.Resource.Attributes) + { + if (filter(attribute.Key)) + { + labels ??= []; + labels.Add(attribute); + } + } + + this.resourceConstantLabels = labels; + } + + this.resourceConstantLabelsComputed = true; + } + + return this.resourceConstantLabels; + } + private int WriteTargetInfo(TextFormatSerializer serializer, PrometheusProtocolState state) { while (true) diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/PrometheusExporter.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/PrometheusExporter.cs index cb21b87046b..247b967b62c 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/PrometheusExporter.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/PrometheusExporter.cs @@ -27,6 +27,7 @@ public PrometheusExporter(PrometheusExporterOptions options) this.ScrapeResponseCacheDurationMilliseconds = options.ScrapeResponseCacheDurationMilliseconds; this.TargetInfoEnabled = options.TargetInfoEnabled; this.DisableTotalNameSuffixForCounters = options.DisableTotalNameSuffixForCounters; + this.ResourceConstantLabels = options.ResourceConstantLabels; this.CollectionManager = new PrometheusCollectionManager(this); } @@ -52,6 +53,8 @@ public PrometheusExporter(PrometheusExporterOptions options) internal bool DisableTotalNameSuffixForCounters { get; } + internal Func? ResourceConstantLabels { get; } + internal Resource Resource { get => field ??= this.ParentProvider.GetResource(); diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/PrometheusExporterOptions.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/PrometheusExporterOptions.cs index f58c742db20..392dbbbd620 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/PrometheusExporterOptions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/PrometheusExporterOptions.cs @@ -49,4 +49,11 @@ public int ScrapeResponseCacheDurationMilliseconds /// Gets or sets a value indicating whether addition of _total suffix for counter metric names is disabled. Default value: . /// public bool DisableTotalNameSuffixForCounters { get; set; } + + /// + /// Gets or sets a predicate used to select which resource attributes are added to each metric as constant labels. + /// The predicate is invoked with the resource attribute key and should return to include the + /// attribute. Default value: (no resource attributes are added as metric labels). + /// + public Func? ResourceConstantLabels { get; set; } } diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/Serialization/TextFormatSerializer.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/Serialization/TextFormatSerializer.cs index 17d42b1abf1..62ad3c31a53 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/Serialization/TextFormatSerializer.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/Serialization/TextFormatSerializer.cs @@ -778,34 +778,43 @@ internal int WriteTags( List<(int Start, int Length)>? writtenKeyRanges = null; var wroteLabel = false; + var resourceConstantLabels = options.ResourceConstantLabels; + var hasResourceConstantLabels = resourceConstantLabels is { Count: > 0 }; + if (writeEnclosingBraces) { buffer[cursor++] = unchecked((byte)'{'); } - if (!quotedNameBytes.IsEmpty) - { - cursor = WriteQuotedName(buffer, cursor, quotedNameBytes, quotedNameSuffix); - wroteLabel = true; - } - - if (!options.SuppressScopeInfo) + // The fast path writes scope labels and point tags directly to the buffer. It cannot + // account for resource constant labels (which may collide with, and therefore need to be + // merged with, point tags), so it is skipped whenever any are present. + if (!hasResourceConstantLabels) { - WriteScopeLabels(); - } - - if (TryWritePointTags()) - { - if (writeEnclosingBraces) + if (!quotedNameBytes.IsEmpty) { - buffer[cursor++] = unchecked((byte)'}'); + cursor = WriteQuotedName(buffer, cursor, quotedNameBytes, quotedNameSuffix); + wroteLabel = true; } - else if (wroteLabel) + + if (!options.SuppressScopeInfo) { - buffer[cursor++] = unchecked((byte)','); + WriteScopeLabels(); } - return cursor; + if (TryWritePointTags()) + { + if (writeEnclosingBraces) + { + buffer[cursor++] = unchecked((byte)'}'); + } + else if (wroteLabel) + { + buffer[cursor++] = unchecked((byte)','); + } + + return cursor; + } } cursor = startCursor; @@ -827,6 +836,14 @@ internal int WriteTags( this.AddLabel(tag.Key, tag.Value, ref labels, reservedOutputKeys); } + if (hasResourceConstantLabels) + { + foreach (var resourceLabel in resourceConstantLabels!) + { + this.AddLabel(resourceLabel.Key, resourceLabel.Value, ref labels, reservedOutputKeys); + } + } + return WriteLabels(buffer, cursor, labels, writeEnclosingBraces, quotedNameBytes, quotedNameSuffix); void WriteScopeLabels() diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/Serialization/TextFormatSerializerOptions.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/Serialization/TextFormatSerializerOptions.cs index fe9aaf06372..442e689ca64 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/Serialization/TextFormatSerializerOptions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/Shared/Serialization/TextFormatSerializerOptions.cs @@ -13,12 +13,21 @@ internal readonly struct TextFormatSerializerOptions /// public readonly bool SuppressScopeInfo; // Inverted so the default struct is the default value (false = included). + /// + /// The resource attributes to add to each metric as constant labels, or if none. + /// + public readonly IReadOnlyList>? ResourceConstantLabels; + /// /// Initializes a new instance of the struct. /// /// Whether the scope information is suppressed from the scrape response. - public TextFormatSerializerOptions(bool suppressScopeInfo) + /// The resource attributes to add to each metric as constant labels, or if none. + public TextFormatSerializerOptions( + bool suppressScopeInfo, + IReadOnlyList>? resourceConstantLabels) { this.SuppressScopeInfo = suppressScopeInfo; + this.ResourceConstantLabels = resourceConstantLabels; } } diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs index 091a910d034..073f6887341 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerMeterProviderBuilderExtensions.cs @@ -71,6 +71,7 @@ private static BaseExportingMetricReader BuildPrometheusHttpListenerMetricReader ScrapeResponseCacheDurationMilliseconds = options.ScrapeResponseCacheDurationMilliseconds, TargetInfoEnabled = options.TargetInfoEnabled, DisableTotalNameSuffixForCounters = options.DisableTotalNameSuffixForCounters, + ResourceConstantLabels = options.ResourceConstantLabels, }); var reader = new BaseExportingMetricReader(exporter) diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs index 30ce6d15d51..9a85daf916c 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/PrometheusHttpListenerOptions.cs @@ -99,6 +99,17 @@ public int ScrapeResponseCacheDurationMilliseconds /// public bool TargetInfoEnabled { get; set; } = true; + /// + /// Gets or sets a predicate used to select which resource attributes are added to each metric as constant labels. + /// The predicate is invoked with the resource attribute key and should return to include the + /// attribute. Default value: (no resource attributes are added as metric labels). + /// + /// + /// Note: Resource attributes copied as metric labels are always included in the target_info metric + /// regardless of this predicate. + /// + public Func? ResourceConstantLabels { get; set; } + /// /// Gets or sets an optional callback to apply custom configuration for the /// instance used by the exporter. diff --git a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md index 7da27fb1f19..bba06542f23 100644 --- a/src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md +++ b/src/OpenTelemetry.Exporter.Prometheus.HttpListener/README.md @@ -64,6 +64,8 @@ variables. * `ScrapeEndpointPath`: Defines the Prometheus scrape endpoint path. (default `"/metrics"`). * `TargetInfoEnabled`: Whether to produce a `target_info` metric (default `true`). +* `ResourceConstantLabels`: A predicate selecting which resource attributes are + added to each metric as constant labels (default `null`). * `DisableTotalNameSuffixForCounters`: Whether to disable the `_total` suffix for counter metrics (default `false`). * `DisableTimestamp`: Whether to disable the timestamp for metrics (default `false`). @@ -117,6 +119,27 @@ Specifies whether to produce a [`target_info`](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/compatibility/prometheus_and_openmetrics.md#resource-attributes-1) metric. Default value: `true`. Set to `false` to disable the `target_info` metric. +### ResourceConstantLabels + +A predicate used to select which +[resource attributes](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/prometheus.md#resource-attributes-as-metric-labels) +are added to each metric as constant labels. The predicate is invoked with the +resource attribute key and should return `true` to include the attribute. +Default value: `null` (no resource attributes are added as metric labels). +Resource attributes copied as metric labels are always included in the +`target_info` metric regardless of this predicate. + +```csharp +var meterProvider = Sdk.CreateMeterProviderBuilder() + .AddMeter(MyMeter.Name) + .AddPrometheusHttpListener(options => + { + // Add all resource attributes as metric labels. + options.ResourceConstantLabels = static _ => true; + }) + .Build(); +``` + ## Troubleshooting This component uses an diff --git a/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs b/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs index d9ffec481ce..7583caad567 100644 --- a/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs +++ b/test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs @@ -62,6 +62,26 @@ public async Task RunWithTargetInfoEnabledConfigured(bool targetInfoEnabled) await Verify(output, "text", PrometheusSerializerTests.VerifySettings).UseParameters(targetInfoEnabled); } + [Theory] + [InlineData("all")] + [InlineData("service_name")] + [InlineData("none")] + public async Task RunWithResourceConstantLabelsConfigured(string filter) + { + var output = await RunPrometheusExporterMiddlewareIntegrationTest( + "/metrics", + app => app.UseOpenTelemetryPrometheusScrapingEndpoint(), + services => services.Configure(o => o.ResourceConstantLabels = filter switch + { + "all" => static _ => true, + "service_name" => static key => key == "service.name", + _ => static _ => false, + }), + assertResponseContent: false); + + await Verify(output, "text", PrometheusSerializerTests.VerifySettings).UseParameters(filter); + } + [Fact] public async Task RunWithCustomScrapeEndpointPath() { diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs index c9978f70ec7..ffb09eda3ad 100644 --- a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs +++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs @@ -62,6 +62,28 @@ public async Task RunHttpServerWithTargetInfoEnabledConfigured(bool targetInfoEn await Verify(output, "text", PrometheusSerializerTests.VerifySettings).UseParameters(targetInfoEnabled); } + [Theory] + [InlineData("all")] + [InlineData("service_name")] + [InlineData("none")] + public async Task RunHttpServerWithResourceConstantLabelsConfigured(string filter) + { + var output = await RunPrometheusExporterHttpServerIntegrationTest( + configureListener: (options) => + { + options.ResourceConstantLabels = filter switch + { + "all" => static _ => true, + "service_name" => static key => key == "service.name", + _ => static _ => false, + }; + return options.Port; + }, + assertResponseContent: false); + + await Verify(output, "text", PrometheusSerializerTests.VerifySettings).UseParameters(filter); + } + [Fact] public async Task RunHttpServerWithNoMetrics() { diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusSerializerTests.cs b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusSerializerTests.cs index c2d377425ec..70595434b1d 100644 --- a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusSerializerTests.cs +++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusSerializerTests.cs @@ -2160,7 +2160,7 @@ private static int WriteMetric(byte[] buffer, int cursor, Metric metric, bool us { TextFormatSerializer serializer = useOpenMetrics ? TextFormatSerializer.OpenMetricsV1 : TextFormatSerializer.PrometheusV1; var prometheusMetric = PrometheusMetric.Create(metric, disableTotalNameSuffixForCounters: false); - var options = new TextFormatSerializerOptions(suppressScopeInfo); + var options = new TextFormatSerializerOptions(suppressScopeInfo, null); return serializer.WriteMetric( buffer, diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.RunHttpServerWithResourceConstantLabelsConfigured_filter=all.verified.text b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.RunHttpServerWithResourceConstantLabelsConfigured_filter=all.verified.text new file mode 100644 index 00000000000..7d31f432b0a --- /dev/null +++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.RunHttpServerWithResourceConstantLabelsConfigured_filter=all.verified.text @@ -0,0 +1,8 @@ +# TYPE target info +# HELP target Target metadata +target_info{service_name="my_service",service_instance_id="id1"} 1 +# TYPE counter_double_bytes counter +# UNIT counter_double_bytes bytes +counter_double_bytes_total{otel_scope_name="PrometheusHttpListenerTests",otel_scope_version="1.0.1",key1="value1",key2="value2",service_name="my_service",service_instance_id="id1"} 101.17 +counter_double_bytes_created{otel_scope_name="PrometheusHttpListenerTests",otel_scope_version="1.0.1",key1="value1",key2="value2",service_name="my_service",service_instance_id="id1"} +# EOF diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.RunHttpServerWithResourceConstantLabelsConfigured_filter=none.verified.text b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.RunHttpServerWithResourceConstantLabelsConfigured_filter=none.verified.text new file mode 100644 index 00000000000..6dbc7342bc6 --- /dev/null +++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.RunHttpServerWithResourceConstantLabelsConfigured_filter=none.verified.text @@ -0,0 +1,8 @@ +# TYPE target info +# HELP target Target metadata +target_info{service_name="my_service",service_instance_id="id1"} 1 +# TYPE counter_double_bytes counter +# UNIT counter_double_bytes bytes +counter_double_bytes_total{otel_scope_name="PrometheusHttpListenerTests",otel_scope_version="1.0.1",key1="value1",key2="value2"} 101.17 +counter_double_bytes_created{otel_scope_name="PrometheusHttpListenerTests",otel_scope_version="1.0.1",key1="value1",key2="value2"} +# EOF diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.RunHttpServerWithResourceConstantLabelsConfigured_filter=service_name.verified.text b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.RunHttpServerWithResourceConstantLabelsConfigured_filter=service_name.verified.text new file mode 100644 index 00000000000..bf7c44aefe9 --- /dev/null +++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.RunHttpServerWithResourceConstantLabelsConfigured_filter=service_name.verified.text @@ -0,0 +1,8 @@ +# TYPE target info +# HELP target Target metadata +target_info{service_name="my_service",service_instance_id="id1"} 1 +# TYPE counter_double_bytes counter +# UNIT counter_double_bytes bytes +counter_double_bytes_total{otel_scope_name="PrometheusHttpListenerTests",otel_scope_version="1.0.1",key1="value1",key2="value2",service_name="my_service"} 101.17 +counter_double_bytes_created{otel_scope_name="PrometheusHttpListenerTests",otel_scope_version="1.0.1",key1="value1",key2="value2",service_name="my_service"} +# EOF diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.RunWithResourceConstantLabelsConfigured_filter=all.verified.text b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.RunWithResourceConstantLabelsConfigured_filter=all.verified.text new file mode 100644 index 00000000000..ac80bc461fa --- /dev/null +++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.RunWithResourceConstantLabelsConfigured_filter=all.verified.text @@ -0,0 +1,8 @@ +# TYPE target info +# HELP target Target metadata +target_info{service_name="my_service",service_instance_id="id1"} 1 +# TYPE counter_double_bytes counter +# UNIT counter_double_bytes bytes +counter_double_bytes_total{otel_scope_name="PrometheusExporterMiddlewareTests",otel_scope_version="1.0.1",key1="value1",key2="value2",service_name="my_service",service_instance_id="id1"} 101.17 +counter_double_bytes_created{otel_scope_name="PrometheusExporterMiddlewareTests",otel_scope_version="1.0.1",key1="value1",key2="value2",service_name="my_service",service_instance_id="id1"} +# EOF diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.RunWithResourceConstantLabelsConfigured_filter=none.verified.text b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.RunWithResourceConstantLabelsConfigured_filter=none.verified.text new file mode 100644 index 00000000000..dd9b959a12b --- /dev/null +++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.RunWithResourceConstantLabelsConfigured_filter=none.verified.text @@ -0,0 +1,8 @@ +# TYPE target info +# HELP target Target metadata +target_info{service_name="my_service",service_instance_id="id1"} 1 +# TYPE counter_double_bytes counter +# UNIT counter_double_bytes bytes +counter_double_bytes_total{otel_scope_name="PrometheusExporterMiddlewareTests",otel_scope_version="1.0.1",key1="value1",key2="value2"} 101.17 +counter_double_bytes_created{otel_scope_name="PrometheusExporterMiddlewareTests",otel_scope_version="1.0.1",key1="value1",key2="value2"} +# EOF diff --git a/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.RunWithResourceConstantLabelsConfigured_filter=service_name.verified.text b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.RunWithResourceConstantLabelsConfigured_filter=service_name.verified.text new file mode 100644 index 00000000000..a4b6393cf60 --- /dev/null +++ b/test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.RunWithResourceConstantLabelsConfigured_filter=service_name.verified.text @@ -0,0 +1,8 @@ +# TYPE target info +# HELP target Target metadata +target_info{service_name="my_service",service_instance_id="id1"} 1 +# TYPE counter_double_bytes counter +# UNIT counter_double_bytes bytes +counter_double_bytes_total{otel_scope_name="PrometheusExporterMiddlewareTests",otel_scope_version="1.0.1",key1="value1",key2="value2",service_name="my_service"} 101.17 +counter_double_bytes_created{otel_scope_name="PrometheusExporterMiddlewareTests",otel_scope_version="1.0.1",key1="value1",key2="value2",service_name="my_service"} +# EOF