20331b09d4c8a1b16b03d67c9708d7b4979102c6
[platform/core/dotnet/diagnostics.git] /
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3
4 using System;
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;
10
11 namespace Microsoft.Diagnostics.Monitoring.EventPipe.Triggers.SystemDiagnosticsMetrics
12 {
13     /// <summary>
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.
16     /// </summary>
17     internal sealed class SystemDiagnosticsMetricsTrigger :
18         ITraceEventTrigger
19     {
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);
26
27         private readonly CounterFilter _filter;
28         private readonly SystemDiagnosticsMetricsTriggerImpl _impl;
29         private readonly string _meterName;
30         private readonly string _sessionId;
31
32         public SystemDiagnosticsMetricsTrigger(SystemDiagnosticsMetricsTriggerSettings settings)
33         {
34             if (null == settings)
35             {
36                 throw new ArgumentNullException(nameof(settings));
37             }
38
39             Validate(settings);
40
41             _filter = new CounterFilter(settings.CounterIntervalSeconds);
42             _filter.AddFilter(settings.MeterName, new string[] { settings.InstrumentName });
43
44             _impl = new SystemDiagnosticsMetricsTriggerImpl(settings);
45
46             _meterName = settings.MeterName;
47
48             _sessionId = settings.SessionId;
49         }
50
51         public IReadOnlyDictionary<string, IReadOnlyCollection<string>> GetProviderEventMap()
52         {
53             return _eventMapCache.GetOrAdd(_meterName, CreateEventMapForProvider);
54         }
55
56         public bool HasSatisfiedCondition(TraceEvent traceEvent)
57         {
58             // Filter to the counter of interest before forwarding to the implementation
59             if (traceEvent.TryGetCounterPayload(_filter, _sessionId, out ICounterPayload payload))
60             {
61                 return _impl.HasSatisfiedCondition(payload);
62             }
63             return false;
64         }
65
66         public static MetricSourceConfiguration CreateConfiguration(SystemDiagnosticsMetricsTriggerSettings settings)
67         {
68             Validate(settings);
69
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;
76
77             return config;
78         }
79
80         private static void Validate(SystemDiagnosticsMetricsTriggerSettings settings)
81         {
82             ValidationContext context = new(settings);
83             Validator.ValidateObject(settings, context, validateAllProperties: true);
84         }
85
86         private IReadOnlyDictionary<string, IReadOnlyCollection<string>> CreateEventMapForProvider(string providerName)
87         {
88             return new ReadOnlyDictionary<string, IReadOnlyCollection<string>>(
89                 new Dictionary<string, IReadOnlyCollection<string>>()
90                 {
91                     { "System.Diagnostics.Metrics", new ReadOnlyCollection<string>(Array.Empty<string>()) }
92                 });
93         }
94     }
95 }