diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/ObservableCounter.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/ObservableCounter.cs index 52d64194087ca7..cb7fe046d86bad 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/ObservableCounter.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/ObservableCounter.cs @@ -17,6 +17,8 @@ public sealed class ObservableCounter : ObservableInstrument where T : str { private readonly object _callback; + internal override object? Callback => _callback; + internal ObservableCounter(Meter meter, string name, Func observeValue, string? unit, string? description) : this(meter, name, observeValue, unit, description, tags: null) { } @@ -50,6 +52,6 @@ internal ObservableCounter(Meter meter, string name, Func /// Observe() fetches the current measurements being tracked by this observable counter. /// - protected override IEnumerable> Observe() => Observe(_callback); + protected override IEnumerable> Observe() => ((Func>>)_callback)(); } } diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/ObservableGauge.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/ObservableGauge.cs index 8f6107c321d835..9071eed9bba329 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/ObservableGauge.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/ObservableGauge.cs @@ -17,6 +17,8 @@ public sealed class ObservableGauge : ObservableInstrument where T : struc { private readonly object _callback; + internal override object? Callback => _callback; + internal ObservableGauge(Meter meter, string name, Func observeValue, string? unit, string? description) : this(meter, name, observeValue, unit, description, tags: null) { } @@ -50,6 +52,6 @@ internal ObservableGauge(Meter meter, string name, Func /// Observe() fetches the current measurements being tracked by this observable counter. /// - protected override IEnumerable> Observe() => Observe(_callback); + protected override IEnumerable> Observe() => ((Func>>)_callback)(); } } diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/ObservableInstrument.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/ObservableInstrument.cs index 10a0f188ee67cf..e3086942f67a6b 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/ObservableInstrument.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/ObservableInstrument.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using System.Runtime.CompilerServices; namespace System.Diagnostics.Metrics { @@ -50,45 +49,45 @@ protected ObservableInstrument(Meter meter, string name, string? unit, string? d /// public override bool IsObservable => true; + // Returns the underlying user callback for built-in observable instruments, or null for user-defined subclasses. + // Subclasses provide their measurements via the abstract Observe() method instead. + internal virtual object? Callback => null; + // Will be called from MeterListener.RecordObservableInstruments for each observable instrument. internal override void Observe(MeterListener listener) { object? state = GetSubscriptionState(listener); - IEnumerable> measurements = Observe(); - if (measurements is null) + // Fast path for the built-in observable instruments: dispatch their callbacks + // directly to the listener, avoiding the per-observation Measurement[1] allocation that + // the IEnumerable> path used to require. + object? callback = Callback; + + if (callback is Func valueOnlyFunc) { + listener.NotifyMeasurement(this, valueOnlyFunc(), Instrument.EmptyTags, state); return; } - foreach (Measurement measurement in measurements) + if (callback is Func> measurementOnlyFunc) { + Measurement measurement = measurementOnlyFunc(); listener.NotifyMeasurement(this, measurement.Value, measurement.Tags, state); - } - } - - // Will be called from the concrete classes which extends ObservabilityInstrument when calling Observe() method. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static IEnumerable> Observe(object callback) - { - if (callback is Func valueOnlyFunc) - { - return new Measurement[1] { new Measurement(valueOnlyFunc()) }; + return; } - if (callback is Func> measurementOnlyFunc) + // Func>> built-ins and user-defined ObservableInstrument subclasses + // both fall through to the virtual Observe() override. + IEnumerable> measurements = Observe(); + if (measurements is null) { - return new Measurement[1] { measurementOnlyFunc() }; + return; } - if (callback is Func>> listOfMeasurementsFunc) + foreach (Measurement measurement in measurements) { - return listOfMeasurementsFunc(); + listener.NotifyMeasurement(this, measurement.Value, measurement.Tags, state); } - - Debug.Fail("Execution shouldn't reach this point"); - return null; } - } } diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/ObservableUpDownCounter.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/ObservableUpDownCounter.cs index fc472320e2b5d8..948cc02fc7a7a1 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/ObservableUpDownCounter.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/ObservableUpDownCounter.cs @@ -17,6 +17,8 @@ public sealed class ObservableUpDownCounter : ObservableInstrument where T { private readonly object _callback; + internal override object? Callback => _callback; + internal ObservableUpDownCounter(Meter meter, string name, Func observeValue, string? unit, string? description) : this(meter, name, observeValue, unit, description, tags: null) { } @@ -50,6 +52,6 @@ internal ObservableUpDownCounter(Meter meter, string name, Func /// Observe() fetches the current measurements being tracked by this observable counter. /// - protected override IEnumerable> Observe() => Observe(_callback); + protected override IEnumerable> Observe() => ((Func>>)_callback)(); } }