diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
index ed5e35e4f094a5..62a37ab56e29fe 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
@@ -49,6 +49,7 @@ System.Diagnostics.DiagnosticSource
+
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Helpers.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Helpers.cs
new file mode 100644
index 00000000000000..874b61de6958e4
--- /dev/null
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Helpers.cs
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+namespace System.Diagnostics
+{
+ internal static class Helpers
+ {
+ internal static string FormatTags(IEnumerable>? tags)
+ {
+ if (tags is null)
+ {
+ return string.Empty;
+ }
+
+ StringBuilder sb = new StringBuilder();
+ bool first = true;
+ foreach (KeyValuePair tag in tags)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ sb.Append(',');
+ }
+
+ sb.Append(tag.Key).Append('=').Append(tag.Value);
+ }
+ return sb.ToString();
+ }
+
+ internal static string FormatTags(KeyValuePair[] labels)
+ {
+ if (labels is null || labels.Length == 0)
+ {
+ return string.Empty;
+ }
+
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < labels.Length; i++)
+ {
+ sb.Append(labels[i].Key).Append('=').Append(labels[i].Value);
+ if (i != labels.Length - 1)
+ {
+ sb.Append(',');
+ }
+ }
+ return sb.ToString();
+ }
+
+ internal static string FormatObjectHash(object? obj) =>
+ obj is null ? string.Empty : RuntimeHelpers.GetHashCode(obj).ToString(CultureInfo.InvariantCulture);
+ }
+}
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs
index 34ecde9bf1a26d..3c7090d5d6d954 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs
@@ -32,12 +32,12 @@ internal sealed class AggregationManager
private readonly MeterListener _listener;
private int _currentTimeSeries;
private int _currentHistograms;
- private readonly Action _collectMeasurement;
+ private readonly Action _collectMeasurement;
private readonly Action _beginCollection;
private readonly Action _endCollection;
- private readonly Action _beginInstrumentMeasurements;
- private readonly Action _endInstrumentMeasurements;
- private readonly Action _instrumentPublished;
+ private readonly Action _beginInstrumentMeasurements;
+ private readonly Action _endInstrumentMeasurements;
+ private readonly Action _instrumentPublished;
private readonly Action _initialInstrumentEnumerationComplete;
private readonly Action _collectionError;
private readonly Action _timeSeriesLimitReached;
@@ -47,12 +47,12 @@ internal sealed class AggregationManager
public AggregationManager(
int maxTimeSeries,
int maxHistograms,
- Action collectMeasurement,
+ Action collectMeasurement,
Action beginCollection,
Action endCollection,
- Action beginInstrumentMeasurements,
- Action endInstrumentMeasurements,
- Action instrumentPublished,
+ Action beginInstrumentMeasurements,
+ Action endInstrumentMeasurements,
+ Action instrumentPublished,
Action initialInstrumentEnumerationComplete,
Action collectionError,
Action timeSeriesLimitReached,
@@ -118,17 +118,18 @@ public AggregationManager SetCollectionPeriod(TimeSpan collectionPeriod)
private void CompletedMeasurements(Instrument instrument, object? cookie)
{
_instruments.Remove(instrument);
- _endInstrumentMeasurements(instrument);
+ Debug.Assert(cookie is not null);
+ _endInstrumentMeasurements(instrument, (InstrumentState)cookie);
RemoveInstrumentState(instrument);
}
private void PublishedInstrument(Instrument instrument, MeterListener _)
{
- _instrumentPublished(instrument);
InstrumentState? state = GetInstrumentState(instrument);
+ _instrumentPublished(instrument, state);
if (state != null)
{
- _beginInstrumentMeasurements(instrument);
+ _beginInstrumentMeasurements(instrument, state);
#pragma warning disable CA1864 // Prefer the 'IDictionary.TryAdd(TKey, TValue)' method. IDictionary.TryAdd() is not available in one of the builds
if (!_instruments.ContainsKey(instrument))
#pragma warning restore CA1864
@@ -418,7 +419,7 @@ internal void Collect()
{
kv.Value.Collect(kv.Key, (LabeledAggregationStatistics labeledAggStats) =>
{
- _collectMeasurement(kv.Key, labeledAggStats);
+ _collectMeasurement(kv.Key, labeledAggStats, kv.Value);
});
}
}
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/InstrumentState.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/InstrumentState.cs
index fa1b2612aad9a0..c67c609ac0517e 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/InstrumentState.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/InstrumentState.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Security;
+using System.Threading;
namespace System.Diagnostics.Metrics
{
@@ -14,16 +15,19 @@ internal abstract class InstrumentState
// This can be called concurrently with Update()
public abstract void Collect(Instrument instrument, Action aggregationVisitFunc);
- }
+ public abstract int ID { get; }
+ }
internal sealed class InstrumentState : InstrumentState
where TAggregator : Aggregator
{
private AggregatorStore _aggregatorStore;
+ private static int s_idCounter;
public InstrumentState(Func createAggregatorFunc)
{
+ ID = Interlocked.Increment(ref s_idCounter);
_aggregatorStore = new AggregatorStore(createAggregatorFunc);
}
@@ -38,5 +42,7 @@ public override void Update(double measurement, ReadOnlySpan s_allMeters = new List();
private List _instruments = new List();
private Dictionary> _nonObservableInstrumentsCache = new();
+
internal bool Disposed { get; private set; }
internal static bool IsSupported { get; } = InitializeIsSupported();
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs
index ba789aa98b15bf..c3ac57bb310f36 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs
@@ -115,40 +115,40 @@ public void CollectionStop(string sessionId, DateTime intervalStartTime, DateTim
WriteEvent(3, sessionId, intervalStartTime, intervalEndTime);
}
- [Event(4, Keywords = Keywords.TimeSeriesValues, Version = 1)]
+ [Event(4, Keywords = Keywords.TimeSeriesValues, Version = 2)]
#if !NET8_0_OR_GREATER
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
#endif
- public void CounterRateValuePublished(string sessionId, string meterName, string? meterVersion, string instrumentName, string? unit, string tags, string rate, string value)
+ public void CounterRateValuePublished(string sessionId, string meterName, string? meterVersion, string instrumentName, string? unit, string tags, string rate, string value, int instrumentId)
{
- WriteEvent(4, sessionId, meterName, meterVersion ?? "", instrumentName, unit ?? "", tags, rate, value);
+ WriteEvent(4, sessionId, meterName, meterVersion ?? "", instrumentName, unit ?? "", tags, rate, value, instrumentId);
}
- [Event(5, Keywords = Keywords.TimeSeriesValues)]
+ [Event(5, Keywords = Keywords.TimeSeriesValues, Version = 2)]
#if !NET8_0_OR_GREATER
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
#endif
- public void GaugeValuePublished(string sessionId, string meterName, string? meterVersion, string instrumentName, string? unit, string tags, string lastValue)
+ public void GaugeValuePublished(string sessionId, string meterName, string? meterVersion, string instrumentName, string? unit, string tags, string lastValue, int instrumentId)
{
- WriteEvent(5, sessionId, meterName, meterVersion ?? "", instrumentName, unit ?? "", tags, lastValue);
+ WriteEvent(5, sessionId, meterName, meterVersion ?? "", instrumentName, unit ?? "", tags, lastValue, instrumentId);
}
- [Event(6, Keywords = Keywords.TimeSeriesValues, Version = 1)]
+ [Event(6, Keywords = Keywords.TimeSeriesValues, Version = 2)]
#if !NET8_0_OR_GREATER
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
#endif
- public void HistogramValuePublished(string sessionId, string meterName, string? meterVersion, string instrumentName, string? unit, string tags, string quantiles, int count, double sum)
+ public void HistogramValuePublished(string sessionId, string meterName, string? meterVersion, string instrumentName, string? unit, string tags, string quantiles, int count, double sum, int instrumentId)
{
- WriteEvent(6, sessionId, meterName, meterVersion ?? "", instrumentName, unit ?? "", tags, quantiles, count, sum);
+ WriteEvent(6, sessionId, meterName, meterVersion ?? "", instrumentName, unit ?? "", tags, quantiles, count, sum, instrumentId);
}
// Sent when we begin to monitor the value of a instrument, either because new session filter arguments changed subscriptions
// or because an instrument matching the pre-existing filter has just been created. This event precedes all *MetricPublished events
// for the same named instrument.
- [Event(7, Keywords = Keywords.TimeSeriesValues, Version = 1)]
+ [Event(7, Keywords = Keywords.TimeSeriesValues, Version = 2)]
#if !NET8_0_OR_GREATER
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
@@ -163,15 +163,16 @@ public void BeginInstrumentReporting(
string? description,
string instrumentTags,
string meterTags,
- string meterScopeHash)
+ string meterScopeHash,
+ int instrumentId)
{
WriteEvent(7, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "",
- instrumentTags, meterTags, meterScopeHash);
+ instrumentTags, meterTags, meterScopeHash, instrumentId);
}
// Sent when we stop monitoring the value of a instrument, either because new session filter arguments changed subscriptions
// or because the Meter has been disposed.
- [Event(8, Keywords = Keywords.TimeSeriesValues, Version = 1)]
+ [Event(8, Keywords = Keywords.TimeSeriesValues, Version = 2)]
#if !NET8_0_OR_GREATER
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
@@ -186,10 +187,11 @@ public void EndInstrumentReporting(
string? description,
string instrumentTags,
string meterTags,
- string meterScopeHash)
+ string meterScopeHash,
+ int instrumentId)
{
WriteEvent(8, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "",
- instrumentTags, meterTags, meterScopeHash);
+ instrumentTags, meterTags, meterScopeHash, instrumentId);
}
[Event(9, Keywords = Keywords.TimeSeriesValues | Keywords.Messages | Keywords.InstrumentPublishing)]
@@ -204,7 +206,7 @@ public void InitialInstrumentEnumerationComplete(string sessionId)
WriteEvent(10, sessionId);
}
- [Event(11, Keywords = Keywords.InstrumentPublishing, Version = 1)]
+ [Event(11, Keywords = Keywords.InstrumentPublishing, Version = 2)]
#if !NET8_0_OR_GREATER
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
@@ -219,10 +221,11 @@ public void InstrumentPublished(
string? description,
string instrumentTags,
string meterTags,
- string meterScopeHash)
+ string meterScopeHash,
+ int instrumentId)
{
WriteEvent(11, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "",
- instrumentTags, meterTags, meterScopeHash);
+ instrumentTags, meterTags, meterScopeHash, instrumentId);
}
[Event(12, Keywords = Keywords.TimeSeriesValues)]
@@ -249,14 +252,14 @@ public void MultipleSessionsNotSupportedError(string runningSessionId)
WriteEvent(15, runningSessionId);
}
- [Event(16, Keywords = Keywords.TimeSeriesValues, Version = 1)]
+ [Event(16, Keywords = Keywords.TimeSeriesValues, Version = 2)]
#if !NET8_0_OR_GREATER
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")]
#endif
- public void UpDownCounterRateValuePublished(string sessionId, string meterName, string? meterVersion, string instrumentName, string? unit, string tags, string rate, string value)
+ public void UpDownCounterRateValuePublished(string sessionId, string meterName, string? meterVersion, string instrumentName, string? unit, string tags, string rate, string value, int instrumentId)
{
- WriteEvent(16, sessionId, meterName, meterVersion ?? "", instrumentName, unit ?? "", tags, rate, value);
+ WriteEvent(16, sessionId, meterName, meterVersion ?? "", instrumentName, unit ?? "", tags, rate, value, instrumentId);
}
[Event(17, Keywords = Keywords.TimeSeriesValues)]
@@ -413,8 +416,8 @@ public void OnEventCommand(EventCommandEventArgs command)
}
}
}
- if ((command.Command == EventCommand.Update || command.Command == EventCommand.Enable) &&
- command.Arguments != null)
+
+ if ((command.Command == EventCommand.Update || command.Command == EventCommand.Enable) && command.Arguments != null)
{
IncrementRefCount(commandSessionId, command);
@@ -432,22 +435,22 @@ public void OnEventCommand(EventCommandEventArgs command)
string sessionId = _sessionId;
_aggregationManager = new AggregationManager(
- maxTimeSeries,
- maxHistograms,
- (i, s) => TransmitMetricValue(i, s, sessionId),
- (startIntervalTime, endIntervalTime) => Parent.CollectionStart(sessionId, startIntervalTime, endIntervalTime),
- (startIntervalTime, endIntervalTime) => Parent.CollectionStop(sessionId, startIntervalTime, endIntervalTime),
- i => Parent.BeginInstrumentReporting(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description,
- FormatTags(i.Tags), FormatTags(i.Meter.Tags), FormatScopeHash(i.Meter.Scope)),
- i => Parent.EndInstrumentReporting(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description,
- FormatTags(i.Tags), FormatTags(i.Meter.Tags), FormatScopeHash(i.Meter.Scope)),
- i => Parent.InstrumentPublished(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description,
- FormatTags(i.Tags), FormatTags(i.Meter.Tags), FormatScopeHash(i.Meter.Scope)),
- () => Parent.InitialInstrumentEnumerationComplete(sessionId),
- e => Parent.Error(sessionId, e.ToString()),
- () => Parent.TimeSeriesLimitReached(sessionId),
- () => Parent.HistogramLimitReached(sessionId),
- e => Parent.ObservableInstrumentCallbackError(sessionId, e.ToString()));
+ maxTimeSeries: maxTimeSeries,
+ maxHistograms: maxHistograms,
+ collectMeasurement: (i, s, state) => TransmitMetricValue(i, s, sessionId, state),
+ beginCollection: (startIntervalTime, endIntervalTime) => Parent.CollectionStart(sessionId, startIntervalTime, endIntervalTime),
+ endCollection: (startIntervalTime, endIntervalTime) => Parent.CollectionStop(sessionId, startIntervalTime, endIntervalTime),
+ beginInstrumentMeasurements: (i, state) => Parent.BeginInstrumentReporting(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description,
+ Helpers.FormatTags(i.Tags), Helpers.FormatTags(i.Meter.Tags), Helpers.FormatObjectHash(i.Meter.Scope), state.ID),
+ endInstrumentMeasurements: (i, state) => Parent.EndInstrumentReporting(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description,
+ Helpers.FormatTags(i.Tags), Helpers.FormatTags(i.Meter.Tags), Helpers.FormatObjectHash(i.Meter.Scope), state.ID),
+ instrumentPublished: (i, state) => Parent.InstrumentPublished(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description,
+ Helpers.FormatTags(i.Tags), Helpers.FormatTags(i.Meter.Tags), Helpers.FormatObjectHash(i.Meter.Scope), state is null ? 0 : state.ID),
+ initialInstrumentEnumerationComplete: () => Parent.InitialInstrumentEnumerationComplete(sessionId),
+ collectionError: e => Parent.Error(sessionId, e.ToString()),
+ timeSeriesLimitReached: () => Parent.TimeSeriesLimitReached(sessionId),
+ histogramLimitReached: () => Parent.HistogramLimitReached(sessionId),
+ observableInstrumentCallbackError: e => Parent.ObservableInstrumentCallbackError(sessionId, e.ToString()));
_aggregationManager.SetCollectionPeriod(TimeSpan.FromSeconds(refreshIntervalSecs));
@@ -657,79 +660,32 @@ private void ParseSpecs(string? metricsSpecs)
}
}
- private static void TransmitMetricValue(Instrument instrument, LabeledAggregationStatistics stats, string sessionId)
+ private static void TransmitMetricValue(Instrument instrument, LabeledAggregationStatistics stats, string sessionId, InstrumentState? instrumentState)
{
+ int instrumentId = instrumentState?.ID ?? 0;
if (stats.AggregationStatistics is CounterStatistics rateStats)
{
if (rateStats.IsMonotonic)
{
- Log.CounterRateValuePublished(sessionId, instrument.Meter.Name, instrument.Meter.Version, instrument.Name, instrument.Unit, FormatTags(stats.Labels),
- rateStats.Delta.HasValue ? rateStats.Delta.Value.ToString(CultureInfo.InvariantCulture) : "",
- rateStats.Value.ToString(CultureInfo.InvariantCulture));
+ Log.CounterRateValuePublished(sessionId, instrument.Meter.Name, instrument.Meter.Version, instrument.Name, instrument.Unit, Helpers.FormatTags(stats.Labels),
+ rateStats.Delta.HasValue ? rateStats.Delta.Value.ToString(CultureInfo.InvariantCulture) : "", rateStats.Value.ToString(CultureInfo.InvariantCulture), instrumentId);
}
else
{
- Log.UpDownCounterRateValuePublished(sessionId, instrument.Meter.Name, instrument.Meter.Version, instrument.Name, instrument.Unit, FormatTags(stats.Labels),
- rateStats.Delta.HasValue ? rateStats.Delta.Value.ToString(CultureInfo.InvariantCulture) : "",
- rateStats.Value.ToString(CultureInfo.InvariantCulture));
+ Log.UpDownCounterRateValuePublished(sessionId, instrument.Meter.Name, instrument.Meter.Version, instrument.Name, instrument.Unit, Helpers.FormatTags(stats.Labels),
+ rateStats.Delta.HasValue ? rateStats.Delta.Value.ToString(CultureInfo.InvariantCulture) : "", rateStats.Value.ToString(CultureInfo.InvariantCulture), instrumentId);
}
}
else if (stats.AggregationStatistics is LastValueStatistics lastValueStats)
{
- Log.GaugeValuePublished(sessionId, instrument.Meter.Name, instrument.Meter.Version, instrument.Name, instrument.Unit, FormatTags(stats.Labels),
- lastValueStats.LastValue.HasValue ? lastValueStats.LastValue.Value.ToString(CultureInfo.InvariantCulture) : "");
+ Log.GaugeValuePublished(sessionId, instrument.Meter.Name, instrument.Meter.Version, instrument.Name, instrument.Unit, Helpers.FormatTags(stats.Labels),
+ lastValueStats.LastValue.HasValue ? lastValueStats.LastValue.Value.ToString(CultureInfo.InvariantCulture) : "", instrumentId);
}
else if (stats.AggregationStatistics is HistogramStatistics histogramStats)
{
- Log.HistogramValuePublished(sessionId, instrument.Meter.Name, instrument.Meter.Version, instrument.Name, instrument.Unit, FormatTags(stats.Labels), FormatQuantiles(histogramStats.Quantiles), histogramStats.Count, histogramStats.Sum);
- }
- }
-
- private static string FormatScopeHash(object? scope) =>
- scope is null ? string.Empty : RuntimeHelpers.GetHashCode(scope).ToString(CultureInfo.InvariantCulture);
-
- private static string FormatTags(IEnumerable>? tags)
- {
- if (tags is null)
- {
- return string.Empty;
- }
-
- StringBuilder sb = new StringBuilder();
- bool first = true;
- foreach (KeyValuePair tag in tags)
- {
- if (first)
- {
- first = false;
- }
- else
- {
- sb.Append(',');
- }
-
- sb.Append(tag.Key).Append('=');
-
- if (tag.Value is not null)
- {
- sb.Append(tag.Value.ToString());
- }
- }
- return sb.ToString();
- }
-
- private static string FormatTags(KeyValuePair[] labels)
- {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < labels.Length; i++)
- {
- sb.Append(labels[i].Key).Append('=').Append(labels[i].Value);
- if (i != labels.Length - 1)
- {
- sb.Append(',');
- }
+ Log.HistogramValuePublished(sessionId, instrument.Meter.Name, instrument.Meter.Version, instrument.Name, instrument.Unit, Helpers.FormatTags(stats.Labels), FormatQuantiles(histogramStats.Quantiles),
+ histogramStats.Count, histogramStats.Sum, instrumentId);
}
- return sb.ToString();
}
private static string FormatQuantiles(QuantileValue[] quantiles)
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs
index 43aeb17afa2bc5..3e2b40d51d1e57 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs
@@ -1516,37 +1516,68 @@ public void EventSourceEnforcesHistogramLimitAndNotMaxTimeSeries()
AssertCollectStartStopEventsPresent(events, IntervalSecs, 3);
}
- private static string FormatScopeHash(object? scope) =>
- scope is null ? string.Empty : RuntimeHelpers.GetHashCode(scope).ToString(CultureInfo.InvariantCulture);
+ public static IEnumerable