diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/tests/MetricsTests.cs b/src/libraries/Microsoft.Extensions.Diagnostics/tests/MetricsTests.cs index cfda92c4388da..5721038535ac7 100644 --- a/src/libraries/Microsoft.Extensions.Diagnostics/tests/MetricsTests.cs +++ b/src/libraries/Microsoft.Extensions.Diagnostics/tests/MetricsTests.cs @@ -116,69 +116,35 @@ public void MeterDisposeTest() IMeterFactory meterFactory = sp.GetRequiredService(); Meter meter = meterFactory.Create("DisposableMeter"); - Counter counter = meter.CreateCounter("MyCounter"); - InstrumentRecorder recorder = new InstrumentRecorder(counter); + + using MeterListener listener = new MeterListener(); + listener.InstrumentPublished = (instrument, theListener) => + { + if (instrument == counter) + { + listener.EnableMeasurementEvents(counter, counter); + } + }; + int lastMeasurement = 0; + listener.SetMeasurementEventCallback((inst, measurement, tags, state) => lastMeasurement = measurement); + listener.Start(); + counter.Add(10); - Assert.Equal(1, recorder.GetMeasurements().Count()); - Assert.Equal(10, recorder.GetMeasurements().ElementAt(0).Value); + Assert.Equal(10, lastMeasurement); meter.Dispose(); // should be no-op + counter.Add(20); - Assert.Equal(2, recorder.GetMeasurements().Count()); - Assert.Equal(20, recorder.GetMeasurements().ElementAt(1).Value); + Assert.Equal(20, lastMeasurement); meter.Dispose(); // dispose again, should be no-op too counter.Add(30); - Assert.Equal(3, recorder.GetMeasurements().Count()); - Assert.Equal(30, recorder.GetMeasurements().ElementAt(2).Value); + Assert.Equal(30, lastMeasurement); // Now dispose the factory, the meter should be disposed too meterFactory.Dispose(); counter.Add(40); // recorder shouldn't observe this value as the meter created this instrument is disposed - Assert.Equal(3, recorder.GetMeasurements().Count()); - } - - [Fact] - public void InstrumentRecorderTest() - { - ServiceCollection services = new ServiceCollection(); - services.AddMetrics(); - var sp = services.BuildServiceProvider(); - using IMeterFactory meterFactory = sp.GetRequiredService(); - - MeterOptions options = new MeterOptions("name") - { - Version = "version", - Tags = new TagList() { { "key1", "value1" }, { "key2", "value2" } } - }; - - Meter meter = meterFactory.Create("MyMeter", "1.0.0", new TagList() { { "key1", "value1" }, { "key2", "value2" } }); - Assert.Same(meterFactory, meter.Scope); - - Counter counter = meter.CreateCounter("MyCounter"); - - InstrumentRecorder recorder1 = new InstrumentRecorder(counter); - Assert.Same(counter, recorder1.Instrument); - - InstrumentRecorder recorder2 = new InstrumentRecorder(meter, "MyCounter"); - Assert.Same(counter, recorder2.Instrument); - - InstrumentRecorder recorder3 = new InstrumentRecorder(scopeFilter: meterFactory, "MyMeter", "MyCounter"); - Assert.Same(counter, recorder3.Instrument); - - counter.Add(100, new KeyValuePair("k", "v")); - Assert.Equal(1, recorder1.GetMeasurements().Count()); - Assert.Equal(1, recorder2.GetMeasurements().Count()); - Assert.Equal(1, recorder3.GetMeasurements().Count()); - - Assert.Equal(100, recorder1.GetMeasurements().ElementAt(0).Value); - Assert.Equal(100, recorder2.GetMeasurements().ElementAt(0).Value); - Assert.Equal(100, recorder2.GetMeasurements().ElementAt(0).Value); - - KeyValuePair[] tags = new KeyValuePair[] { new KeyValuePair("k", "v") }; - Assert.Equal(tags, recorder1.GetMeasurements().ElementAt(0).Tags.ToArray()); - Assert.Equal(tags, recorder2.GetMeasurements().ElementAt(0).Tags.ToArray()); - Assert.Equal(tags, recorder3.GetMeasurements().ElementAt(0).Tags.ToArray()); + Assert.Equal(30, lastMeasurement); } [Fact] diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs index c2608ee2dddfc..65cc560a6ba28 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs @@ -389,15 +389,6 @@ public abstract class Instrument : Instrument where T : struct protected void RecordMeasurement(T measurement, in TagList tagList) { throw null; } protected void RecordMeasurement(T measurement, ReadOnlySpan> tags) { throw null; } } - public sealed class InstrumentRecorder : IDisposable where T : struct - { - public InstrumentRecorder(Instrument instrument) { throw null; } - public InstrumentRecorder(object? scopeFilter, string meterName, string instrumentName) { throw null; } - public InstrumentRecorder(Meter meter, string instrumentName) { throw null; } - public Instrument? Instrument { get { throw null; } } - public System.Collections.Generic.IEnumerable> GetMeasurements(bool clear = false) { throw null; } - public void Dispose() { throw null; } - } public readonly struct Measurement where T : struct { public Measurement(T value) { throw null; } @@ -545,7 +536,7 @@ public class MeterOptions public System.Collections.Generic.IEnumerable>? Tags { get { throw null;} set { throw null;} } public object? Scope { get { throw null;} set { throw null;} } public MeterOptions(string name) { throw null;} - } + } public sealed class ObservableCounter : ObservableInstrument where T : struct { internal ObservableCounter(Meter meter, string name, string? unit, string? description) : base(meter, name, unit, description) { throw null; } 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 235c490dda551..9bca6e1171903 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj @@ -52,7 +52,6 @@ System.Diagnostics.DiagnosticSource - diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/InstrumentRecorder.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/InstrumentRecorder.cs deleted file mode 100644 index 4b45167bbecd6..0000000000000 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/InstrumentRecorder.cs +++ /dev/null @@ -1,181 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Diagnostics.Metrics; -using System.Threading; - -namespace System.Diagnostics.Metrics -{ - /// - /// A helper class to record the measurements published from or . - /// - public sealed class InstrumentRecorder : IDisposable where T : struct - { - private bool _isObservableInstrument; - private bool _disposed; - private Instrument? _instrument; - - private MeterListener _meterListener; - private List> _measurements; - - /// - /// Initialize a new instance to record the measurements published by . - /// - /// The to record measurements from. - public InstrumentRecorder(Instrument instrument) - { - if (instrument is null) - { - throw new ArgumentNullException(nameof(instrument)); - } - - if (instrument is not Instrument and not ObservableInstrument) - { - throw new InvalidOperationException(SR.InvalidInstrumentType); - } - - _measurements = new List>(); - - _meterListener = new MeterListener(); - - _instrument = instrument; - _meterListener.SetMeasurementEventCallback(OnMeasurementRecorded); - _meterListener.EnableMeasurementEvents(instrument, state: null); - _meterListener.Start(); - } - - /// - /// Initialize a new instance to record the measurement published by an with the name - /// and a meter having the name and scope - /// - /// The name of the meter. - /// The name of the meter. - /// The name of the instrument. - public InstrumentRecorder(object? scopeFilter, string meterName, string instrumentName) - { - if (meterName is null) - { - throw new ArgumentNullException(nameof(meterName)); - } - - if (instrumentName is null) - { - throw new ArgumentNullException(nameof(instrumentName)); - } - - Initialize((instrument) => object.Equals(instrument.Meter.Scope, scopeFilter) && - instrument.Meter.Name == meterName && - instrument.Name == instrumentName); - - Debug.Assert(_meterListener is not null); - Debug.Assert(_measurements is not null); - } - - /// - /// Initialize a new instance to record the measurement published by an with the name - /// and the meter . - /// - /// The meter that produced the instrument required for recording the published measurements. - /// The name of the instrument. - public InstrumentRecorder(Meter meter, string instrumentName) - { - if (meter is null) - { - throw new ArgumentNullException(nameof(meter)); - } - - if (instrumentName is null) - { - throw new ArgumentNullException(nameof(instrumentName)); - } - - Initialize((instrument) => object.ReferenceEquals(instrument.Meter, meter) && instrument.Name == instrumentName); - - Debug.Assert(_meterListener is not null); - Debug.Assert(_measurements is not null); - } - - private void Initialize(Func instrumentPredicate) - { - _measurements = new List>(); - - _meterListener = new MeterListener(); - _meterListener.InstrumentPublished = (instrument, listener) => - { - if (instrumentPredicate(instrument) && (instrument is ObservableInstrument || instrument is Instrument)) - { - if (Interlocked.CompareExchange(ref _instrument, instrument, null) is null) - { - _isObservableInstrument = instrument is ObservableInstrument; - listener.EnableMeasurementEvents(instrument, state: null); - } - } - }; - - _meterListener.SetMeasurementEventCallback(OnMeasurementRecorded); - _meterListener.Start(); - } - - /// - /// Gets the that is being recorded. - /// - public Instrument? Instrument - { - get => _instrument; - private set => _instrument = value; - } - - private void OnMeasurementRecorded(Instrument instrument, T measurement, ReadOnlySpan> tags, object? state) - { - var m = new Measurement(measurement, tags); - - lock (_measurements) - { - _measurements.Add(m); - } - } - - /// - /// Gets the measurements recorded by this . - /// - /// If true, the previously recorded measurements will be cleared. - /// The measurements recorded by this . - public IEnumerable> GetMeasurements(bool clear = false) - { - if (_disposed) - { - throw new ObjectDisposedException(nameof(InstrumentRecorder)); - } - - if (_isObservableInstrument) - { - _meterListener.RecordObservableInstruments(); - } - - lock (_measurements) - { - IEnumerable> measurements = _measurements.ToArray(); - if (clear) - { - _measurements.Clear(); - } - return measurements; - } - } - - /// - /// Disposes the and stops recording measurements. - /// - public void Dispose() - { - if (_disposed) - { - return; - } - _disposed = true; - _meterListener.Dispose(); - } - } -} diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs index f6d86efe0f772..6faf68268ee46 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs @@ -1398,117 +1398,6 @@ public void TestInstrumentCreationWithTags() }).Dispose(); } - [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] - public void TestInstrumentRecorderNegativeCases() - { - RemoteExecutor.Invoke(() => { - using Meter meter = new Meter("TestInstrumentRecorderNegativeCases"); - - Assert.Throws(() => new InstrumentRecorder(instrument: null)); - Assert.Throws(() => new InstrumentRecorder(scopeFilter: null, meterName: null, instrumentName: "instrumentName")); - Assert.Throws(() => new InstrumentRecorder(scopeFilter:null, meterName:"meterName", instrumentName: null)); - Assert.Throws(() => new InstrumentRecorder(meter: null, instrumentName: "instrumentName")); - Assert.Throws(() => new InstrumentRecorder(meter: meter, instrumentName: null)); - - // Test InstrumentRecorder generic type mismatch the instrument generic type - Instrument instrument = meter.CreateCounter("counter"); - Assert.Throws(() => new InstrumentRecorder(instrument: instrument)); - - }).Dispose(); - } - - [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] - public void TestInstrumentRecorder() - { - RemoteExecutor.Invoke(() => { - using Meter meter = new Meter("TestInstrumentRecorder1"); - - // - // Test listening using instrument object - // - - Counter instrument = meter.CreateCounter("counter"); - InstrumentRecorder recorder1 = new InstrumentRecorder(instrument); - Assert.Equal(instrument, recorder1.Instrument); - Assert.Equal(new Measurement[0], recorder1.GetMeasurements()); - instrument.Add(1); - Assert.Equal(1, recorder1.GetMeasurements().Count()); - Assert.Equal(1, recorder1.GetMeasurements().ElementAt(0).Value); - Assert.Equal(0, recorder1.GetMeasurements().ElementAt(0).Tags.Length); - - recorder1.GetMeasurements(clear: true); // clear previous collected measurements - Assert.Equal(0, recorder1.GetMeasurements().Count()); - instrument.Add(2, new KeyValuePair("k1", "v1")); - Assert.Equal(1, recorder1.GetMeasurements().Count()); - Assert.Equal(2, recorder1.GetMeasurements().ElementAt(0).Value); - Assert.Equal(1, recorder1.GetMeasurements().ElementAt(0).Tags.Length); - Assert.Equal(new KeyValuePair("k1", "v1"), recorder1.GetMeasurements().ElementAt(0).Tags[0]); - - // - // Test listening using instrument name - // - - InstrumentRecorder recorder2 = new InstrumentRecorder(meter, "counter"); - Assert.Equal(instrument, recorder2.Instrument); - Assert.Equal(0, recorder2.GetMeasurements().Count()); - instrument.Add(3); - Assert.Equal(2, recorder1.GetMeasurements().Count()); - Assert.Equal(2, recorder1.GetMeasurements().ElementAt(0).Value); - Assert.Equal(3, recorder1.GetMeasurements().ElementAt(1).Value); - Assert.Equal(1, recorder2.GetMeasurements().Count()); - Assert.Equal(3, recorder2.GetMeasurements().ElementAt(0).Value); - - // - // Test listening using instrument name with different generic type - // - - InstrumentRecorder recorder3 = new InstrumentRecorder(meter, "counter"); - Assert.Null(recorder3.Instrument); - Counter instrument1 = meter.CreateCounter("counter"); - Assert.Equal(instrument1, recorder3.Instrument); - Assert.Equal(0, recorder3.GetMeasurements().Count()); - instrument1.Add(4); - Assert.Equal(1, recorder3.GetMeasurements().Count()); - Assert.Equal(4, recorder3.GetMeasurements().ElementAt(0).Value); - - // - // Test using scope filter - // - - // using same existing meter name - using Meter meter1 = new Meter("TestInstrumentRecorder1", null, null, "Scope1"); - - InstrumentRecorder recorder4 = new InstrumentRecorder(scopeFilter: null, meterName: "TestInstrumentRecorder1", instrumentName: "counter"); - Assert.Equal(instrument, recorder4.Instrument); - - InstrumentRecorder recorder5 = new InstrumentRecorder(scopeFilter: "Scope1", meterName: "TestInstrumentRecorder1", instrumentName: "counter"); - Assert.Null(recorder5.Instrument); - Counter instrument2 = meter1.CreateCounter("counter"); - Assert.Equal(instrument2, recorder5.Instrument); - - // - // Test meter creating 2 instruments with same name but different unit and ensure listening to the first created one - // - - Counter instrument3 = meter.CreateCounter("counter", "myUnit"); - InstrumentRecorder recorder6 = new InstrumentRecorder(meter: meter, instrumentName: "counter"); - Assert.Equal(instrument, recorder6.Instrument); - - // - // Ensure can listen to the observable instrument - // - - InstrumentRecorder recorder7 = new InstrumentRecorder(meter: meter, instrumentName: "observableCounter"); - Assert.Null(recorder7.Instrument); - ObservableCounter instrument4 = meter.CreateObservableCounter("observableCounter", () => 10); - Assert.Equal(instrument4, recorder7.Instrument); - Measurement measurementWith10Value = new Measurement(10, default); - Assert.True(recorder7.GetMeasurements().Same(new Measurement[] { measurementWith10Value })); - Assert.True(recorder7.GetMeasurements().Same(new Measurement[] { measurementWith10Value, measurementWith10Value })); - Assert.True(recorder7.GetMeasurements(true).Same(new Measurement[] { measurementWith10Value, measurementWith10Value, measurementWith10Value })); - Assert.True(recorder7.GetMeasurements().Same(new Measurement[] { measurementWith10Value })); - }).Dispose(); - } private void PublishCounterMeasurement(Counter counter, T value, KeyValuePair[] tags) where T : struct {