diff --git a/src/Orleans.Core/Core/DefaultClientServices.cs b/src/Orleans.Core/Core/DefaultClientServices.cs index f2cdf597961..4a685183249 100644 --- a/src/Orleans.Core/Core/DefaultClientServices.cs +++ b/src/Orleans.Core/Core/DefaultClientServices.cs @@ -53,7 +53,9 @@ public static void AddDefaultServices(IClientBuilder builder) // Common services services.AddLogging(); services.AddOptions(); + services.AddMetrics(); services.TryAddSingleton(TimeProvider.System); + services.TryAddSingleton(); // Options logging services.TryAddSingleton(typeof(IOptionFormatter<>), typeof(DefaultOptionsFormatter<>)); diff --git a/src/Orleans.Core/Diagnostics/Metrics/ApplicationRequestInstruments.cs b/src/Orleans.Core/Diagnostics/Metrics/ApplicationRequestInstruments.cs index 8924d38ae1b..c45ce5ea9b7 100644 --- a/src/Orleans.Core/Diagnostics/Metrics/ApplicationRequestInstruments.cs +++ b/src/Orleans.Core/Diagnostics/Metrics/ApplicationRequestInstruments.cs @@ -1,34 +1,41 @@ -using System; -using System.Collections.Generic; using System.Diagnostics.Metrics; namespace Orleans.Runtime; -internal static class ApplicationRequestInstruments +internal class ApplicationRequestInstruments { - internal static Counter TimedOutRequestsCounter = Instruments.Meter.CreateCounter(InstrumentNames.APP_REQUESTS_TIMED_OUT); - internal static Counter CanceledRequestsCounter = Instruments.Meter.CreateCounter(InstrumentNames.APP_REQUESTS_CANCELED); + private readonly Counter _timedOutRequestsCounter; + private readonly Counter _canceledRequestsCounter; - private static readonly long[] AppRequestsLatencyHistogramBuckets = new long[] { 1, 2, 4, 6, 8, 10, 50, 100, 200, 400, 800, 1_000, 1_500, 2_000, 5_000, 10_000, 15_000 }; - private static readonly HistogramAggregator AppRequestsLatencyHistogramAggregator = new(AppRequestsLatencyHistogramBuckets, Array.Empty>(), value => new ("duration", $"{value}ms")); - private static readonly ObservableCounter AppRequestsLatencyHistogramBucket = Instruments.Meter.CreateObservableCounter(InstrumentNames.APP_REQUESTS_LATENCY_HISTOGRAM + "-bucket", AppRequestsLatencyHistogramAggregator.CollectBuckets); - private static readonly ObservableCounter AppRequestsLatencyHistogramCount = Instruments.Meter.CreateObservableCounter(InstrumentNames.APP_REQUESTS_LATENCY_HISTOGRAM + "-count", AppRequestsLatencyHistogramAggregator.CollectCount); - private static readonly ObservableCounter AppRequestsLatencyHistogramSum = Instruments.Meter.CreateObservableCounter(InstrumentNames.APP_REQUESTS_LATENCY_HISTOGRAM + "-sum", AppRequestsLatencyHistogramAggregator.CollectSum); + private static readonly long[] AppRequestsLatencyHistogramBuckets = [1, 2, 4, 6, 8, 10, 50, 100, 200, 400, 800, 1_000, 1_500, 2_000, 5_000, 10_000, 15_000]; + private readonly HistogramAggregator _appRequestsLatencyHistogramAggregator; + private readonly ObservableCounter _appRequestsLatencyHistogramBucket; + private readonly ObservableCounter _appRequestsLatencyHistogramCount; + private readonly ObservableCounter _appRequestsLatencyHistogramSum; + internal ApplicationRequestInstruments(OrleansInstruments instruments) + { + _timedOutRequestsCounter = instruments.Meter.CreateCounter(InstrumentNames.APP_REQUESTS_TIMED_OUT); + _canceledRequestsCounter = instruments.Meter.CreateCounter(InstrumentNames.APP_REQUESTS_CANCELED); + _appRequestsLatencyHistogramAggregator = new(AppRequestsLatencyHistogramBuckets, [], value => new("duration", $"{value}ms")); + _appRequestsLatencyHistogramBucket = instruments.Meter.CreateObservableCounter(InstrumentNames.APP_REQUESTS_LATENCY_HISTOGRAM + "-bucket", _appRequestsLatencyHistogramAggregator.CollectBuckets); + _appRequestsLatencyHistogramCount = instruments.Meter.CreateObservableCounter(InstrumentNames.APP_REQUESTS_LATENCY_HISTOGRAM + "-count", _appRequestsLatencyHistogramAggregator.CollectCount); + _appRequestsLatencyHistogramSum = instruments.Meter.CreateObservableCounter(InstrumentNames.APP_REQUESTS_LATENCY_HISTOGRAM + "-sum", _appRequestsLatencyHistogramAggregator.CollectSum); + } - internal static void OnAppRequestsEnd(long durationMilliseconds) + internal void OnAppRequestsEnd(long durationMilliseconds) { - if (AppRequestsLatencyHistogramSum.Enabled) - AppRequestsLatencyHistogramAggregator.Record(durationMilliseconds); + if (_appRequestsLatencyHistogramSum.Enabled) + _appRequestsLatencyHistogramAggregator.Record(durationMilliseconds); } - internal static void OnAppRequestsTimedOut() + internal void OnAppRequestsTimedOut() { - TimedOutRequestsCounter.Add(1); + _timedOutRequestsCounter.Add(1); } - internal static void OnAppRequestsCanceled() + internal void OnAppRequestsCanceled() { - CanceledRequestsCounter.Add(1); + _canceledRequestsCounter.Add(1); } } diff --git a/src/Orleans.Core/Diagnostics/Metrics/OrleansInstruments.cs b/src/Orleans.Core/Diagnostics/Metrics/OrleansInstruments.cs new file mode 100644 index 00000000000..3e28d43d85d --- /dev/null +++ b/src/Orleans.Core/Diagnostics/Metrics/OrleansInstruments.cs @@ -0,0 +1,16 @@ +using System; +using System.Diagnostics.Metrics; + +namespace Orleans.Runtime; + +/// +/// Provides the used by Orleans runtime metrics. +/// +/// The meter factory used to create the Orleans meter. +public class OrleansInstruments(IMeterFactory meterFactory) +{ + /// + /// Gets the Orleans runtime meter. + /// + public Meter Meter { get; } = (meterFactory ?? throw new ArgumentNullException(nameof(meterFactory))).Create("Microsoft.Orleans"); +} diff --git a/src/Orleans.Core/Runtime/CallbackData.cs b/src/Orleans.Core/Runtime/CallbackData.cs index 2dcb5201340..c7b89e06c7d 100644 --- a/src/Orleans.Core/Runtime/CallbackData.cs +++ b/src/Orleans.Core/Runtime/CallbackData.cs @@ -11,6 +11,7 @@ internal sealed partial class CallbackData { private readonly SharedCallbackData shared; private readonly IResponseCompletionSource context; + private readonly ApplicationRequestInstruments _applicationRequestInstruments; private int completed; private StatusResponse? lastKnownStatus; private ValueStopwatch stopwatch; @@ -19,11 +20,13 @@ internal sealed partial class CallbackData public CallbackData( SharedCallbackData shared, IResponseCompletionSource ctx, - Message msg) + Message msg, + ApplicationRequestInstruments applicationRequestInstruments) { this.shared = shared; this.context = ctx; this.Message = msg; + _applicationRequestInstruments = applicationRequestInstruments; this.stopwatch = ValueStopwatch.StartNew(); } @@ -101,8 +104,8 @@ private void OnCancellation() stopwatch.Stop(); SignalCancellation(); shared.Unregister(Message); - ApplicationRequestInstruments.OnAppRequestsEnd((long)stopwatch.Elapsed.TotalMilliseconds); - ApplicationRequestInstruments.OnAppRequestsTimedOut(); + _applicationRequestInstruments.OnAppRequestsEnd((long)stopwatch.Elapsed.TotalMilliseconds); + _applicationRequestInstruments.OnAppRequestsTimedOut(); OrleansCallBackDataEvent.Log.OnCanceled(Message); context.Complete(Response.FromException(new OperationCanceledException(_cancellationTokenRegistration.Token))); _cancellationTokenRegistration.Dispose(); @@ -123,8 +126,8 @@ public void OnTimeout() this.shared.Unregister(this.Message); _cancellationTokenRegistration.Dispose(); - ApplicationRequestInstruments.OnAppRequestsEnd((long)this.stopwatch.Elapsed.TotalMilliseconds); - ApplicationRequestInstruments.OnAppRequestsTimedOut(); + _applicationRequestInstruments.OnAppRequestsEnd((long)this.stopwatch.Elapsed.TotalMilliseconds); + _applicationRequestInstruments.OnAppRequestsTimedOut(); OrleansCallBackDataEvent.Log.OnTimeout(this.Message); @@ -148,7 +151,7 @@ public void OnTargetSiloFail() this.stopwatch.Stop(); this.shared.Unregister(this.Message); _cancellationTokenRegistration.Dispose(); - ApplicationRequestInstruments.OnAppRequestsEnd((long)this.stopwatch.Elapsed.TotalMilliseconds); + _applicationRequestInstruments.OnAppRequestsEnd((long)this.stopwatch.Elapsed.TotalMilliseconds); OrleansCallBackDataEvent.Log.OnTargetSiloFail(this.Message); var msg = this.Message; @@ -169,7 +172,7 @@ public void DoCallback(Message response) this.stopwatch.Stop(); _cancellationTokenRegistration.Dispose(); - ApplicationRequestInstruments.OnAppRequestsEnd((long)this.stopwatch.Elapsed.TotalMilliseconds); + _applicationRequestInstruments.OnAppRequestsEnd((long)this.stopwatch.Elapsed.TotalMilliseconds); // do callback outside the CallbackData lock. Just not a good practice to hold a lock for this unrelated operation. ResponseCallback(response, this.context); diff --git a/src/Orleans.Core/Runtime/OutsideRuntimeClient.cs b/src/Orleans.Core/Runtime/OutsideRuntimeClient.cs index 6bcfc673b7d..ef929478a18 100644 --- a/src/Orleans.Core/Runtime/OutsideRuntimeClient.cs +++ b/src/Orleans.Core/Runtime/OutsideRuntimeClient.cs @@ -32,6 +32,7 @@ internal partial class OutsideRuntimeClient : IRuntimeClient, IDisposable, IClus private readonly MessagingTrace messagingTrace; private readonly InterfaceToImplementationMappingCache _interfaceToImplementationMapping; + private readonly ApplicationRequestInstruments _applicationRequestInstruments; private IGrainCallCancellationManager _cancellationManager; private IClusterConnectionStatusObserver[] _statusObservers; @@ -71,10 +72,12 @@ public OutsideRuntimeClient( MessagingTrace messagingTrace, IServiceProvider serviceProvider, TimeProvider timeProvider, - InterfaceToImplementationMappingCache interfaceToImplementationMapping) + InterfaceToImplementationMappingCache interfaceToImplementationMapping, + OrleansInstruments orleansInstruments) { TimeProvider = timeProvider; _interfaceToImplementationMapping = interfaceToImplementationMapping; + _applicationRequestInstruments = new(orleansInstruments); this.ServiceProvider = serviceProvider; _localClientDetails = localClientDetails; this.loggerFactory = loggerFactory; @@ -281,7 +284,7 @@ public void SendRequest(GrainReference target, IInvokable request, IResponseComp if (!oneWay) { - var callbackData = new CallbackData(this.sharedCallbackData, context, message); + var callbackData = new CallbackData(this.sharedCallbackData, context, message, _applicationRequestInstruments); callbackData.SubscribeForCancellation(cancellationToken); callbacks.TryAdd(message.Id, callbackData); } diff --git a/src/Orleans.Runtime/Core/InsideRuntimeClient.cs b/src/Orleans.Runtime/Core/InsideRuntimeClient.cs index d0ef329e206..f555c902b9d 100644 --- a/src/Orleans.Runtime/Core/InsideRuntimeClient.cs +++ b/src/Orleans.Runtime/Core/InsideRuntimeClient.cs @@ -41,6 +41,7 @@ internal sealed partial class InsideRuntimeClient : IRuntimeClient, ILifecyclePa private MessageCenter messageCenter; private List grainCallFilters; private readonly DeepCopier _deepCopier; + private readonly ApplicationRequestInstruments _applicationRequestInstruments; private IGrainCallCancellationManager _cancellationManager; private HostedClient hostedClient; @@ -63,11 +64,13 @@ public InsideRuntimeClient( GrainInterfaceTypeToGrainTypeResolver interfaceToTypeResolver, DeepCopier deepCopier, TimeProvider timeProvider, - InterfaceToImplementationMappingCache interfaceToImplementationMapping) + InterfaceToImplementationMappingCache interfaceToImplementationMapping, + OrleansInstruments orleansInstruments) { TimeProvider = timeProvider; this.interfaceToImplementationMapping = interfaceToImplementationMapping; this._deepCopier = deepCopier; + this._applicationRequestInstruments = new(orleansInstruments); this.ServiceProvider = serviceProvider; this.MySilo = siloDetails.SiloAddress; this.callbacks = new ConcurrentDictionary<(GrainId, CorrelationId), CallbackData>(); @@ -173,7 +176,7 @@ public void SendRequest( Debug.Assert(context is not null); // Register a callback for the request. - var callbackData = new CallbackData(sharedData, context, message); + var callbackData = new CallbackData(sharedData, context, message, _applicationRequestInstruments); callbacks.TryAdd((message.SendingGrain, message.Id), callbackData); callbackData.SubscribeForCancellation(cancellationToken); } diff --git a/src/Orleans.Runtime/Hosting/DefaultSiloServices.cs b/src/Orleans.Runtime/Hosting/DefaultSiloServices.cs index 7e67c106b66..c2a3ae53774 100644 --- a/src/Orleans.Runtime/Hosting/DefaultSiloServices.cs +++ b/src/Orleans.Runtime/Hosting/DefaultSiloServices.cs @@ -64,7 +64,9 @@ internal static void AddDefaultServices(ISiloBuilder builder) // Common services services.AddLogging(); services.AddOptions(); + services.AddMetrics(); services.TryAddSingleton(TimeProvider.System); + services.TryAddSingleton(); services.TryAddSingleton(typeof(IOptionFormatter<>), typeof(DefaultOptionsFormatter<>)); services.TryAddSingleton(typeof(IOptionFormatterResolver<>), typeof(DefaultOptionsFormatterResolver<>)); diff --git a/src/api/Orleans.Core/Orleans.Core.cs b/src/api/Orleans.Core/Orleans.Core.cs index e2ebb3c68b0..97cb0bd61da 100644 --- a/src/api/Orleans.Core/Orleans.Core.cs +++ b/src/api/Orleans.Core/Orleans.Core.cs @@ -4513,4 +4513,4 @@ public override void SetArgument(int index, object value) { } public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { } } -} \ No newline at end of file +}