[Exporter.Prometheus] Use snapshot tests for PrometheusSerializer#7354
Conversation
- Emit OpenMetrics scope metadata as a single `otel_scope` metric family with `otel_scope_info` samples instead of repeating metadata for every scope. - Include instrumentation scope metadata on samples using `otel_scope_*` labels, including scope version, schema URL, and prefixed scope attributes. - Drop conflicting scope attributes named `name`, `version`, and `schema_url` to avoid collisions with generated scope labels.
Remove Go theme for .NET.
Add CHANGELOG entries.
Address Copilot review feedback.
Add more test coverage for patch.
Move additions to the end.
- Fix missing handling for post-normalization collisions. - Fix metadata conflict handling being bypassed in some cases.
Fix PR links.
Use canonical values for labels that are `float` or `double` to resolve TODO.
- Ensure `otel_scope_info` is sanitized. - Fix missing collision handling.
# Conflicts: # src/OpenTelemetry.Exporter.Prometheus.AspNetCore/CHANGELOG.md # src/OpenTelemetry.Exporter.Prometheus.HttpListener/CHANGELOG.md # src/OpenTelemetry.Exporter.Prometheus.HttpListener/Internal/PrometheusSerializer.cs
Fix SA1203 warning.
Update PrometheusSerializer so scope-tag collisions with point tags now preserve the scope tag’s raw original key through the final merge, which fixes lexicographic value ordering for cases like `z` vs. `otel_scope_z`.
Remove synthetic OpenMetrics `otel_scope`/`otel_scope_info` metadata family.
Use Verify snapshots for `PrometheusSerializer` unit tests.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7354 +/- ##
==========================================
+ Coverage 90.04% 90.07% +0.03%
==========================================
Files 276 276
Lines 14283 14283
==========================================
+ Hits 12861 12866 +5
+ Misses 1422 1417 -5
Flags with carried forward coverage won't be shown. Click here to find out more. |
Add snapshots for `PrometheusCollectionManager` tests too.
Use a stable service name to handle cross-platform differences in the test process' name.
There was a problem hiding this comment.
Pull request overview
This PR migrates Prometheus exporter unit/integration tests from partial regex-based assertions to Verify snapshot testing, improving coverage of full scrape/serialization outputs while scrubbing unstable values (timestamps, span/trace IDs, SDK version).
Changes:
- Replace brittle string/regex assertions with Verify snapshot assertions across
PrometheusSerializer-related tests. - Add a shared
VerifySettingsconfiguration to normalize/scrub unstable output and standardize snapshot naming/locations. - Add and populate
.verified.txtsnapshot baselines for a broad set of Prometheus/OpenMetrics serialization scenarios.
Reviewed changes
Copilot reviewed 75 out of 75 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| test/Shared/XunitContainerFixture{T}.cs | Adds IDE0005 suppression around a redundant using in shared fixture code. |
| test/Shared/EnabledOnDockerPlatformTheoryAttribute.cs | Adds IDE0005 suppression around using Xunit; in shared attribute helper. |
| test/Shared/EnabledOnDockerPlatformFactAttribute.cs | Adds IDE0005 suppression around using Xunit; in shared attribute helper. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PromToolCollection.cs | Removes explicit using Xunit; (relies on implicit/global imports). |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusSerializerTests.cs | Converts many tests to snapshot verification; introduces shared VerifySettings and scrubbing regexes. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusMetricTests.cs | Removes explicit using Xunit; (relies on implicit/global imports). |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusIntegrationTests.cs | Removes explicit using Xunit; (relies on implicit/global imports). |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerTests.cs | Removes explicit using Xunit; (relies on implicit/global imports). |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHttpListenerMeterProviderBuilderExtensionsTests.cs | Removes explicit using Xunit; (relies on implicit/global imports). |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusHeadersParserTests.cs | Removes explicit using Xunit; (relies on implicit/global imports). |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusCollectionManagerTests.cs | Switches scrape-output assertions to snapshots and stabilizes resource attributes for deterministic target_info. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusCollection.cs | Removes explicit using Xunit; (relies on implicit/global imports). |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/PrometheusAcceptHeaders.cs | Removes explicit using Xunit; (relies on implicit/global imports). |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/EventSourceTests.cs | Removes explicit using Xunit; (relies on implicit/global imports). |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests.csproj | Adds Verify.Xunit and assembly metadata for snapshot directory location. |
| test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusIntegrationTests.cs | Removes explicit using Xunit; (relies on implicit/global imports). |
| test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMiddlewareTests.cs | Removes explicit using Xunit; (relies on implicit/global imports). |
| test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/PrometheusExporterMeterProviderBuilderExtensionsTests.cs | Removes explicit using Xunit; (relies on implicit/global imports). |
| test/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests/OpenTelemetry.Exporter.Prometheus.AspNetCore.Tests.csproj | Adds Verify.Xunit and points to shared snapshots directory (path currently OS-specific). |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.WriteMetricPrefixesScopeAttributesAndDropsConflictingScopeAttributeNames.Net4_6.verified.txt | New snapshot baseline for net46 output variant. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.WriteMetricPrefixesScopeAttributesAndDropsConflictingScopeAttributeNames.DotNet8_0.verified.txt | New snapshot baseline for .NET 8 output variant. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.WriteMetricPrefixesScopeAttributesAndDropsConflictingScopeAttributeNames.DotNet9_0.verified.txt | New snapshot baseline for .NET 9 output variant. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.WriteMetricPrefixesScopeAttributesAndDropsConflictingScopeAttributeNames.DotNet10_0.verified.txt | New snapshot baseline for .NET 10 output variant. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.WriteMetricDropsScopeAttributesWhoseNormalizedNamesConflictWithGeneratedScopeNameAndVersionLabels.verified.txt | New snapshot baseline for scope-attribute conflict behavior. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.WriteMetricDropsScopeAttributesWhoseNormalizedNamesConflictWithGeneratedScopeLabels.verified.txt | New snapshot baseline for generated scope label conflicts. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.WriteMetricConcatenatesPointTagsThatCollideWithScopeLabels_snapshotName=plain_useOpenMetrics=True.verified.txt | New snapshot for point-tag collision behavior (OpenMetrics). |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.WriteMetricConcatenatesPointTagsThatCollideWithScopeLabels_snapshotName=plain_useOpenMetrics=False.verified.txt | New snapshot for point-tag collision behavior (text format). |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.WriteMetricConcatenatesPointTagsThatCollideWithScopeLabels_snapshotName=dots_useOpenMetrics=True.verified.txt | New snapshot for dotted-label collision behavior (OpenMetrics). |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.WriteMetricConcatenatesPointTagsThatCollideWithScopeLabels_snapshotName=dots_useOpenMetrics=False.verified.txt | New snapshot for dotted-label collision behavior (text format). |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.WriteMetricConcatenatesCollidingSanitizedLabelValuesInLexicographicOrder.verified.txt | New snapshot for sanitized value concatenation ordering. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.WriteMetricConcatenatesCollidingLeadingDigitLabelKeys.verified.txt | New snapshot for leading-digit label-key collision behavior. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.WriteMetricConcatenatesCollidingEmptyAndUnderscoreLabelKeys.verified.txt | New snapshot for empty/underscore label-key collision behavior. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.WriteHistogramMetricSerializesStaticTagsWithoutPreSerializedTags.verified.txt | New snapshot for histogram static-tag serialization behavior. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.SumWithScopeVersion.verified.txt | New snapshot for scope version label emission. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.SumWithOpenMetricsFormat.verified.txt | New snapshot for OpenMetrics sum formatting. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.SumNonMonotonicDouble.verified.txt | New snapshot for non-monotonic sum serialization. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.SumLongSerializesBoundaryValues_value=0.verified.txt | New snapshot for long boundary value 0. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.SumLongSerializesBoundaryValues_value=9223372036854775807.verified.txt | New snapshot for long boundary value long.MaxValue. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.SumDoubleInfinities.verified.txt | New snapshot for +Inf counter serialization. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.OpenMetricsWritesMetricFamiliesContiguously.verified.txt | New snapshot ensuring OpenMetrics metric family contiguity. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.OpenMetricsDoesNotReserveOtelScopeMetricFamilyNames.verified.txt | New snapshot ensuring otel_scope names are not reserved. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.OpenMetricsDoesNotEmitScopeInfoMetricFamily.verified.txt | New snapshot ensuring scope info family is not emitted. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.DuplicateMetricMetadataIsWrittenOncePerScrape.verified.txt | New snapshot ensuring metadata appears once per scrape. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.MetricMetadataDiscoveredLaterIsWrittenBeforeSamples.verified.txt | New snapshot for late-discovered HELP ordering. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.MetricUnitDiscoveredLaterIsWrittenBeforeSamples.verified.txt | New snapshot for late-discovered UNIT ordering. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.MetricHelpAndUnitDiscoveredTogetherLaterAreBothWrittenBeforeSamples.verified.txt | New snapshot for combined HELP/UNIT ordering behavior. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.ConflictingMetricTypesAreDroppedFromAScrape.verified.txt | New snapshot ensuring conflicting types are dropped. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.HistogramZeroDimension.verified.txt | New snapshot for zero-dimension histogram output. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.HistogramOneDimension.verified.txt | New snapshot for one-dimension histogram output. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.HistogramTwoDimensions.verified.txt | New snapshot for two-dimension histogram output. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.HistogramOneDimensionWithOpenMetricsFormat.verified.txt | New snapshot for OpenMetrics histogram formatting. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.HistogramOneDimensionWithScopeVersion.verified.txt | New snapshot for OpenMetrics histogram + scope version. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.HistogramWithOpenMetricsFormatEmitsLatestBucketExemplar.verified.txt | New snapshot for exemplar selection behavior. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.HistogramWithOpenMetricsFormatFiltersSanitizedReservedExemplarTagNames.verified.txt | New snapshot for filtering reserved exemplar labels. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.HistogramWithOpenMetricsFormatDropsCollidingLeLabelKeys.verified.txt | New snapshot for dropping colliding le labels. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.HistogramWithNegativeBucketBoundsOmitsSumAndCountWithOpenMetricsFormat.verified.txt | New snapshot for negative buckets omitting sum/count in OM format. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.HistogramInfinities.verified.txt | New snapshot for histogram +Inf sum. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.HistogramNaN.verified.txt | New snapshot for histogram NaN sum. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.HistogramExportsCreatedMetric_useOpenMetrics=True.verified.txt | New snapshot for _created emission in OpenMetrics. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.HistogramExportsCreatedMetric_useOpenMetrics=False.verified.txt | New snapshot ensuring no _created in text format. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.HistogramCreatedMetricSkipsReservedHistogramLabels.verified.txt | New snapshot ensuring reserved histogram labels are skipped for created metric. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.CounterExportsCreatedMetric_useOpenMetrics=True.verified.txt | New snapshot for counter _created emission in OpenMetrics. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.CounterExportsCreatedMetric_useOpenMetrics=False.verified.txt | New snapshot ensuring no counter _created in text format. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.CounterWithOpenMetricsFormatEmitsLatestExemplar.verified.txt | New snapshot for counter exemplar emission (latest). |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.CounterWithOpenMetricsFormatEmitsExemplarWithoutLabelsWhenOnlyReservedTagNamesAreFiltered.verified.txt | New snapshot for empty exemplar label-set after filtering. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.CounterWithOpenMetricsFormatFiltersSanitizedReservedExemplarTagNames.verified.txt | New snapshot for reserved exemplar label filtering (counter). |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.CounterWithOpenMetricsFormatDropsExemplarLabelsExceedingLimit.verified.txt | New snapshot for dropping overly-long exemplar labels. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.GaugeZeroDimension.verified.txt | New snapshot for basic gauge output. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.GaugeZeroDimensionWithDescription.verified.txt | New snapshot for gauge HELP emission. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.GaugeZeroDimensionWithUnit.verified.txt | New snapshot for gauge UNIT emission. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.GaugeZeroDimensionWithDescriptionAndUnit.verified.txt | New snapshot for gauge HELP+UNIT emission. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.GaugeOneDimension.verified.txt | New snapshot for labeled gauge output. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.GaugeBoolDimension.verified.txt | New snapshot for boolean label value formatting. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.GaugeEmptyDimensionName.verified.txt | New snapshot for empty dimension key normalization. |
| test/OpenTelemetry.Exporter.Prometheus.HttpListener.Tests/snapshots/PrometheusSerializer.GaugeDoubleSubnormal.verified.txt | New snapshot for -Inf/+Inf/NaN gauge serialization. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Fix IDE0005 after merge.
Remove `async Task` from tests that don't await.
Changes
Use Verify snapshots for
PrometheusSerializerunit tests instead of brittle text-base Regex matches that do not validate the whole scrape response.This PR intentionally only changes test code so that the snapshots could be auto-accepted during local development so that whatever is being verified is effectively the same content the previous assertions checked manually (excluding timestamps and span/trace IDs which aren't stable).
Merge requirement checklist
AppropriateCHANGELOG.mdfiles updated for non-trivial changesChanges in public API reviewed (if applicable)