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 _sessionId;
32 public SystemDiagnosticsMetricsTrigger(SystemDiagnosticsMetricsTriggerSettings settings)
36 throw new ArgumentNullException(nameof(settings));
41 _filter = new CounterFilter(settings.CounterIntervalSeconds);
42 _filter.AddFilter(settings.MeterName, new string[] { settings.InstrumentName });
44 _impl = new SystemDiagnosticsMetricsTriggerImpl(settings);
46 _meterName = settings.MeterName;
48 _sessionId = settings.SessionId;
51 public IReadOnlyDictionary<string, IReadOnlyCollection<string>> GetProviderEventMap()
53 return _eventMapCache.GetOrAdd(_meterName, CreateEventMapForProvider);
56 public bool HasSatisfiedCondition(TraceEvent traceEvent)
58 // Filter to the counter of interest before forwarding to the implementation
59 if (traceEvent.TryGetCounterPayload(_filter, _sessionId, out ICounterPayload payload))
61 return _impl.HasSatisfiedCondition(payload);
66 public static MetricSourceConfiguration CreateConfiguration(SystemDiagnosticsMetricsTriggerSettings settings)
70 MetricSourceConfiguration config = new(
71 settings.CounterIntervalSeconds,
72 MetricSourceConfiguration.CreateProviders(new string[] { settings.MeterName }, MetricType.Meter),
73 settings.MaxHistograms,
74 settings.MaxTimeSeries);
75 settings.SessionId = config.SessionId;
80 private static void Validate(SystemDiagnosticsMetricsTriggerSettings settings)
82 ValidationContext context = new(settings);
83 Validator.ValidateObject(settings, context, validateAllProperties: true);
86 private IReadOnlyDictionary<string, IReadOnlyCollection<string>> CreateEventMapForProvider(string providerName)
88 return new ReadOnlyDictionary<string, IReadOnlyCollection<string>>(
89 new Dictionary<string, IReadOnlyCollection<string>>()
91 { "System.Diagnostics.Metrics", new ReadOnlyCollection<string>(Array.Empty<string>()) }