From 102b976f529cdbaa19d14ef038a01aa64c0ace44 Mon Sep 17 00:00:00 2001 From: Paul Spangler <7519484+spanglerco@users.noreply.github.com> Date: Fri, 31 May 2024 16:53:21 -0500 Subject: [PATCH] MeterListener.Dispose always disables measurements (#102661) Fix #102465 --- .../Diagnostics/Metrics/MeterListener.cs | 9 ++- .../tests/MetricsTests.cs | 57 +++++++++++++++++++ 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MeterListener.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MeterListener.cs index 2c82af3c0b086b..017074586d583e 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MeterListener.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MeterListener.cs @@ -258,14 +258,17 @@ public void Dispose() s_allStartedListeners.Remove(this); DiagNode? current = _enabledMeasurementInstruments.First; - if (current is not null && measurementsCompleted is not null) + if (current is not null) { - callbacksArguments = new Dictionary(); + if (measurementsCompleted is not null) + { + callbacksArguments = new Dictionary(); + } do { object? state = current.Value.DisableMeasurements(this); - callbacksArguments.Add(current.Value, state); + callbacksArguments?.Add(current.Value, state); current = current.Next; } while (current is not null); diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs index b292e55f1bcf20..db5bd31d388217 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs @@ -923,6 +923,63 @@ public void ListenerDisposalsTest() }).Dispose(); } + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + public void ListenerWithoutMeasurementsCompletedDisposalsTest() + { + RemoteExecutor.Invoke(() => { + Meter meter = new Meter("MinimalListenerDisposalsTest"); + + Counter counter = meter.CreateCounter("Counter"); + UpDownCounter upDownCounter = meter.CreateUpDownCounter("upDownCounter"); + Histogram histogram = meter.CreateHistogram("Histogram"); + ObservableCounter observableCounter = meter.CreateObservableCounter("ObservableCounter", () => new Measurement(10, new KeyValuePair[] { new KeyValuePair("Key", "value")})); + ObservableGauge observableGauge = meter.CreateObservableGauge("ObservableGauge", () => new Measurement(5.7m, new KeyValuePair[] { new KeyValuePair("Key", "value")})); + ObservableUpDownCounter observableUpDownCounter = meter.CreateObservableUpDownCounter("ObservableUpDownCounter", () => new Measurement(-5.7f, new KeyValuePair[] { new KeyValuePair("Key", "value")})); + + MeterListener listener = new MeterListener(); + listener.InstrumentPublished = (theInstrument, theListener) => theListener.EnableMeasurementEvents(theInstrument, theInstrument); + + int count = 0; + + listener.SetMeasurementEventCallback((inst, measurement, tags, state) => count++); + listener.SetMeasurementEventCallback((inst, measurement, tags, state) => count++); + listener.SetMeasurementEventCallback((inst, measurement, tags, state) => count++); + listener.SetMeasurementEventCallback((inst, measurement, tags, state) => count++); + listener.SetMeasurementEventCallback((inst, measurement, tags, state) => count++); + listener.SetMeasurementEventCallback((inst, measurement, tags, state) => count++); + + listener.Start(); + + Assert.Equal(0, count); + + counter.Add(1); + Assert.Equal(1, count); + + upDownCounter.Add(-1); + Assert.Equal(2, count); + + histogram.Record(1); + Assert.Equal(3, count); + + listener.RecordObservableInstruments(); + Assert.Equal(6, count); + + listener.Dispose(); + + counter.Add(1); + Assert.Equal(6, count); + + upDownCounter.Add(-1); + Assert.Equal(6, count); + + histogram.Record(1); + Assert.Equal(6, count); + + listener.RecordObservableInstruments(); + Assert.Equal(6, count); + }).Dispose(); + } + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] public void MultipleListenersTest() {