prometheus-net

Форк
0
/
ObservedExemplar.cs 
93 строки · 3.0 Кб
1
using Microsoft.Extensions.ObjectPool;
2
using System.Diagnostics;
3

4
namespace Prometheus;
5

6
/// <summary>
7
/// Internal representation of an Exemplar ready to be serialized.
8
/// </summary>
9
internal sealed class ObservedExemplar
10
{
11
    /// <summary>
12
    /// OpenMetrics places a length limit of 128 runes on the exemplar (sum of all key value pairs).
13
    /// </summary>
14
    private const int MaxRunes = 128;
15

16
    /// <summary>
17
    /// We have a pool of unused instances that we can reuse, to avoid constantly allocating memory. Once the set of metrics stabilizes,
18
    /// all allocations should generally be coming from the pool. We expect the default pool configuratiopn to be suitable for this.
19
    /// </summary>
20
    private static readonly ObjectPool<ObservedExemplar> Pool = ObjectPool.Create<ObservedExemplar>();
21

22
    public static readonly ObservedExemplar Empty = new();
23

24
    internal static Func<double> NowProvider = DefaultNowProvider;
25
    internal static double DefaultNowProvider() => LowGranularityTimeSource.GetSecondsFromUnixEpoch();
26

27
    public Exemplar? Labels { get; private set; }
28
    public double Value { get; private set; }
29
    public double Timestamp { get; private set; }
30

31
    public ObservedExemplar()
32
    {
33
        Labels = null;
34
        Value = 0;
35
        Timestamp = 0;
36
    }
37

38
    public bool IsValid => Labels != null;
39

40
    private void Update(Exemplar labels, double value)
41
    {
42
        Debug.Assert(this != Empty, "Do not mutate the sentinel");
43

44
        var totalRuneCount = 0;
45

46
        for (var i = 0; i < labels.Length; i++)
47
        {
48
            totalRuneCount += labels[i].RuneCount;
49
            for (var j = 0; j < labels.Length; j++)
50
            {
51
                if (i == j) continue;
52
                if (ByteArraysEqual(labels[i].KeyBytes, labels[j].KeyBytes))
53
                    throw new ArgumentException("Exemplar contains duplicate keys.");
54
            }
55
        }
56

57
        if (totalRuneCount > MaxRunes)
58
            throw new ArgumentException($"Exemplar consists of {totalRuneCount} runes, exceeding the OpenMetrics limit of {MaxRunes}.");
59

60
        Labels = labels;
61
        Value = value;
62
        Timestamp = NowProvider();
63
    }
64

65
    private static bool ByteArraysEqual(byte[] a, byte[] b)
66
    {
67
        if (a.Length != b.Length) return false;
68

69
        for (var i = 0; i < a.Length; i++)
70
            if (a[i] != b[i]) return false;
71

72
        return true;
73
    }
74

75
    /// <remarks>
76
    /// Takes ownership of the labels and will destroy them when the instance is returned to the pool.
77
    /// </remarks>
78
    public static ObservedExemplar CreatePooled(Exemplar labels, double value)
79
    {
80
        var instance = Pool.Get();
81
        instance.Update(labels, value);
82
        return instance;
83
    }
84

85
    public static void ReturnPooledIfNotEmpty(ObservedExemplar instance)
86
    {
87
        if (object.ReferenceEquals(instance, Empty))
88
            return; // We never put the "Empty" instance into the pool. Do the check here to avoid repeating it any time we return instances to the pool.
89

90
        instance.Labels?.ReturnToPoolIfNotEmpty();
91
        Pool.Return(instance);
92
    }
93
}

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

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

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

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