prometheus-net

Форк
0
/
DiagnosticSourceAdapter.cs 
118 строк · 3.9 Кб
1
#if NET
2
using System.Diagnostics;
3

4
namespace Prometheus;
5

6
/// <summary>
7
/// Monitors all DiagnosticSource events and exposes them as Prometheus counters.
8
/// The event data is discarded, only the number of occurrences is measured.
9
/// </summary>
10
/// <remarks>
11
/// This is a very coarse data set due to lacking any intelligence on the payload.
12
/// Users are recommended to make custom adapters with more detail for specific use cases.
13
/// </remarks>
14
public sealed class DiagnosticSourceAdapter : IDisposable
15
{
16
    /// <summary>
17
    /// Starts listening for DiagnosticSource events and reporting them as Prometheus metrics.
18
    /// Dispose of the return value to stop listening.
19
    /// </summary>
20
    public static IDisposable StartListening() => StartListening(DiagnosticSourceAdapterOptions.Default);
21

22
    /// <summary>
23
    /// Starts listening for DiagnosticSource events and reporting them as Prometheus metrics.
24
    /// Dispose of the return value to stop listening.
25
    /// </summary>
26
    public static IDisposable StartListening(DiagnosticSourceAdapterOptions options) => new DiagnosticSourceAdapter(options);
27

28
    private DiagnosticSourceAdapter(DiagnosticSourceAdapterOptions options)
29
    {
30
        _options = options;
31
        _metric = Metrics.WithCustomRegistry(options.Registry)
32
            .CreateCounter("diagnostic_events_total", "Total count of events received via the DiagnosticSource infrastructure.", labelNames: new[]
33
            {
34
                "source", // Name of the DiagnosticSource
35
                "event" // Name of the event
36
            });
37

38
        var newListenerObserver = new NewListenerObserver(OnNewListener);
39
        _newListenerSubscription = DiagnosticListener.AllListeners.Subscribe(newListenerObserver);
40
    }
41

42
    private readonly DiagnosticSourceAdapterOptions _options;
43
    private readonly Counter _metric;
44

45
    private readonly IDisposable _newListenerSubscription;
46

47
    // listener name -> subscription
48
    private readonly Dictionary<string, IDisposable> _newEventSubscription = new Dictionary<string, IDisposable>();
49
    private readonly object _newEventSubscriptionLock = new object();
50

51
    private void OnNewListener(DiagnosticListener listener)
52
    {
53
        lock (_newEventSubscriptionLock)
54
        {
55
            if (_newEventSubscription.TryGetValue(listener.Name, out var oldSubscription))
56
            {
57
                oldSubscription.Dispose();
58
                _newEventSubscription.Remove(listener.Name);
59
            }
60

61
            if (!_options.ListenerFilterPredicate(listener))
62
                return;
63

64
            var listenerName = listener.Name;
65
            var newEventObserver = new NewEventObserver(kvp => OnEvent(listenerName, kvp.Key, kvp.Value));
66
            _newEventSubscription[listenerName] = listener.Subscribe(newEventObserver);
67
        }
68
    }
69

70
    private void OnEvent(string listenerName, string eventName, object? payload)
71
    {
72
        _metric.WithLabels(listenerName, eventName).Inc();
73
    }
74

75
    private sealed class NewListenerObserver(Action<DiagnosticListener> onNewListener) : IObserver<DiagnosticListener>
76
    {
77
        public void OnCompleted()
78
        {
79
        }
80

81
        public void OnError(Exception error)
82
        {
83
        }
84

85
        public void OnNext(DiagnosticListener listener)
86
        {
87
            onNewListener(listener);
88
        }
89
    }
90

91
    private sealed class NewEventObserver(Action<KeyValuePair<string, object?>> onEvent) : IObserver<KeyValuePair<string, object?>>
92
    {
93
        public void OnCompleted()
94
        {
95
        }
96

97
        public void OnError(Exception error)
98
        {
99
        }
100

101
        public void OnNext(KeyValuePair<string, object?> receivedEvent)
102
        {
103
            onEvent(receivedEvent);
104
        }
105
    }
106

107
    public void Dispose()
108
    {
109
        _newListenerSubscription.Dispose();
110

111
        lock (_newEventSubscriptionLock)
112
        {
113
            foreach (var subscription in _newEventSubscription.Values)
114
                subscription.Dispose();
115
        }
116
    }
117
}
118
#endif

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.