1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
5 using System.Collections.Concurrent;
6 using System.Collections.Generic;
7 using System.Collections.ObjectModel;
8 using System.ComponentModel.DataAnnotations;
9 using Microsoft.Diagnostics.Tracing;
11 namespace Microsoft.Diagnostics.Monitoring.EventPipe.Triggers.SystemDiagnosticsMetrics
14 /// Trigger that detects when the specified instrument's value is held
15 /// above, below, or between threshold values for a specified duration of time.
17 internal sealed class SystemDiagnosticsMetricsTrigger :
20 // A cache of the list of events that are expected from the specified event provider.
21 // This is a mapping of event provider name to the event map returned by GetProviderEventMap.
22 // This allows caching of the event map between multiple instances of the trigger that
23 // use the same event provider as the source of counter events.
24 private static readonly ConcurrentDictionary<string, IReadOnlyDictionary<string, IReadOnlyCollection<string>>> _eventMapCache =
25 new(StringComparer.OrdinalIgnoreCase);
27 private readonly CounterFilter _filter;
28 private readonly SystemDiagnosticsMetricsTriggerImpl _impl;
29 private readonly string _meterName;
30 private readonly string _clientId;
31 private readonly string _sessionId;
33 public SystemDiagnosticsMetricsTrigger(SystemDiagnosticsMetricsTriggerSettings settings)
37 throw new ArgumentNullException(nameof(settings));
42 _filter = new CounterFilter(settings.CounterIntervalSeconds);
43 _filter.AddFilter(settings.MeterName, new string[] { settings.InstrumentName });
45 _impl = new SystemDiagnosticsMetricsTriggerImpl(settings);
47 _meterName = settings.MeterName;
49 _clientId = settings.ClientId;
51 _sessionId = settings.SessionId;
54 public IReadOnlyDictionary<string, IReadOnlyCollection<string>> GetProviderEventMap()
56 return _eventMapCache.GetOrAdd(_meterName, CreateEventMapForProvider);
59 public bool HasSatisfiedCondition(TraceEvent traceEvent)
61 // Filter to the counter of interest before forwarding to the implementation
62 if (traceEvent.TryGetCounterPayload(_filter, _sessionId, _clientId, out ICounterPayload payload))
64 return _impl.HasSatisfiedCondition(payload);
69 public static MetricSourceConfiguration CreateConfiguration(SystemDiagnosticsMetricsTriggerSettings settings)
73 MetricSourceConfiguration config = new(
74 settings.CounterIntervalSeconds,
75 MetricSourceConfiguration.CreateProviders(new string[] { settings.MeterName }, MetricType.Meter),
76 settings.MaxHistograms,
77 settings.MaxTimeSeries,
78 useSharedSession: settings.UseSharedSession);
79 settings.ClientId = config.ClientId;
80 settings.SessionId = config.SessionId;
85 private static void Validate(SystemDiagnosticsMetricsTriggerSettings settings)
87 ValidationContext context = new(settings);
88 Validator.ValidateObject(settings, context, validateAllProperties: true);
91 private IReadOnlyDictionary<string, IReadOnlyCollection<string>> CreateEventMapForProvider(string providerName)
93 return new ReadOnlyDictionary<string, IReadOnlyCollection<string>>(
94 new Dictionary<string, IReadOnlyCollection<string>>()
96 { "System.Diagnostics.Metrics", new ReadOnlyCollection<string>(Array.Empty<string>()) }