prometheus-net

Форк
0
/
ManagedLifetimeHistogram.cs 
107 строк · 5.0 Кб
1
namespace Prometheus;
2

3
/// <summary>
4
/// This class implements two sets of functionality:
5
/// 1. A lifetime-managed metric handle that can be used to take leases on the metric.
6
/// 2. An automatically-lifetime-extending-on-use metric that creates leases automatically.
7
/// 
8
/// While conceptually separate, we merge the two sets into one class to avoid allocating a bunch of small objects
9
/// every time you want to obtain a lifetime-extending-on-use metric (which tends to be on a relatively hot path).
10
/// 
11
/// The lifetime-extending feature only supports write operations because we cannot guarantee that the metric is still alive when reading.
12
/// </summary>
13
internal sealed class ManagedLifetimeHistogram : ManagedLifetimeMetricHandle<Histogram.Child, IHistogram>, ICollector<IHistogram>
14
{
15
    static ManagedLifetimeHistogram()
16
    {
17
        _assignUnlabelledFunc = AssignUnlabelled;
18
    }
19

20
    public ManagedLifetimeHistogram(Collector<Histogram.Child> metric, TimeSpan expiresAfter) : base(metric, expiresAfter)
21
    {
22
    }
23

24
    public override ICollector<IHistogram> WithExtendLifetimeOnUse() => this;
25

26
    #region ICollector<IHistogram> implementation (for WithExtendLifetimeOnUse)
27
    public string Name => _metric.Name;
28
    public string Help => _metric.Help;
29
    public string[] LabelNames => _metric.LabelNames;
30

31
    public IHistogram Unlabelled => NonCapturingLazyInitializer.EnsureInitialized(ref _unlabelled, this, _assignUnlabelledFunc);
32
    private AutoLeasingInstance? _unlabelled;
33
    private static readonly Action<ManagedLifetimeHistogram> _assignUnlabelledFunc;
34
    private static void AssignUnlabelled(ManagedLifetimeHistogram instance) => instance._unlabelled = new AutoLeasingInstance(instance, Array.Empty<string>());
35

36
    // These do not get cached, so are potentially expensive - user code should try avoiding re-allocating these when possible,
37
    // though admittedly this may not be so easy as often these are on the hot path and the very reason that lifetime-managed
38
    // metrics are used is that we do not have a meaningful way to reuse metrics or identify their lifetime.
39
    public IHistogram WithLabels(params string[] labelValues) => WithLabels(labelValues.AsMemory());
40

41
    public IHistogram WithLabels(ReadOnlyMemory<string> labelValues)
42
    {
43
        return new AutoLeasingInstance(this, labelValues);
44
    }
45

46
    public IHistogram WithLabels(ReadOnlySpan<string> labelValues)
47
    {
48
        // We are allocating a long-lived auto-leasing wrapper here, so there is no way we can just use the span directly.
49
        // We must copy it to a long-lived array. Another reason to avoid re-allocating these as much as possible.
50
        return new AutoLeasingInstance(this, labelValues.ToArray());
51
    }
52
    #endregion
53

54
    private sealed class AutoLeasingInstance : IHistogram
55
    {
56
        public AutoLeasingInstance(IManagedLifetimeMetricHandle<IHistogram> inner, ReadOnlyMemory<string> labelValues)
57
        {
58
            _inner = inner;
59
            _labelValues = labelValues;
60
        }
61

62
        private readonly IManagedLifetimeMetricHandle<IHistogram> _inner;
63
        private readonly ReadOnlyMemory<string> _labelValues;
64

65
        public double Sum => throw new NotSupportedException("Read operations on a lifetime-extending-on-use expiring metric are not supported.");
66
        public long Count => throw new NotSupportedException("Read operations on a lifetime-extending-on-use expiring metric are not supported.");
67

68
        public void Observe(double val, long count)
69
        {
70
            var args = new ObserveValCountArgs(val, count);
71

72
            // We use the Span overload to signal that we expect the label values to be known already.
73
            _inner.WithLease(_observeValCountCoreFunc, args, _labelValues.Span);
74
        }
75

76
        private readonly struct ObserveValCountArgs(double val, long count)
77
        {
78
            public readonly double Val = val;
79
            public readonly long Count = count;
80
        }
81

82
        private static void ObserveValCountCore(ObserveValCountArgs args, IHistogram histogram) => histogram.Observe(args.Val, args.Count);
83
        private static readonly Action<ObserveValCountArgs, IHistogram> _observeValCountCoreFunc = ObserveValCountCore;
84

85
        public void Observe(double val, Exemplar? exemplar)
86
        {
87
            var args = new ObserveValExemplarArgs(val, exemplar);
88

89
            // We use the Span overload to signal that we expect the label values to be known already.
90
            _inner.WithLease(_observeValExemplarCoreFunc, args, _labelValues.Span);
91
        }
92

93
        private readonly struct ObserveValExemplarArgs(double val, Exemplar? exemplar)
94
        {
95
            public readonly double Val = val;
96
            public readonly Exemplar? Exemplar = exemplar;
97
        }
98

99
        private static void ObserveValExemplarCore(ObserveValExemplarArgs args, IHistogram histogram) => histogram.Observe(args.Val, args.Exemplar);
100
        private static readonly Action<ObserveValExemplarArgs, IHistogram> _observeValExemplarCoreFunc = ObserveValExemplarCore;
101

102
        public void Observe(double val)
103
        {
104
            Observe(val, null);
105
        }
106
    }
107
}
108

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

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

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

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