]> git.sesse.net Git - nageru/blob - metrics.h
Make the histograms more flexible.
[nageru] / metrics.h
1 #ifndef _METRICS_H
2 #define _METRICS_H 1
3
4 // A simple global class to keep track of metrics export in Prometheus format.
5 // It would be better to use a more full-featured Prometheus client library for this,
6 // but it would introduce a dependency that is not commonly packaged in distributions,
7 // which makes it quite unwieldy. Thus, we'll package our own for the time being.
8
9 #include <atomic>
10 #include <map>
11 #include <memory>
12 #include <mutex>
13 #include <string>
14 #include <vector>
15
16 class Histogram;
17
18 class Metrics {
19 public:
20         enum Type {
21                 TYPE_COUNTER,
22                 TYPE_GAUGE,
23                 TYPE_HISTOGRAM,  // Internal use only.
24         };
25
26         void add(const std::string &name, std::atomic<int64_t> *location, Type type = TYPE_COUNTER)
27         {
28                 add(name, {}, location, type);
29         }
30
31         void add(const std::string &name, std::atomic<double> *location, Type type = TYPE_COUNTER)
32         {
33                 add(name, {}, location, type);
34         }
35
36         void add(const std::string &name, Histogram *location)
37         {
38                 add(name, {}, location);
39         }
40
41         void add(const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels, std::atomic<int64_t> *location, Type type = TYPE_COUNTER);
42         void add(const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels, std::atomic<double> *location, Type type = TYPE_COUNTER);
43         void add(const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels, Histogram *location);
44
45         std::string serialize() const;
46
47 private:
48         enum DataType {
49                 DATA_TYPE_INT64,
50                 DATA_TYPE_DOUBLE,
51                 DATA_TYPE_HISTOGRAM,
52         };
53
54         struct Metric {
55                 DataType data_type;
56                 std::string name;
57                 std::vector<std::pair<std::string, std::string>> labels;
58                 union {
59                         std::atomic<int64_t> *location_int64;
60                         std::atomic<double> *location_double;
61                         Histogram *location_histogram;
62                 };
63         };
64
65         mutable std::mutex mu;
66         std::map<std::string, Type> types;
67         std::vector<Metric> metrics;
68         std::vector<Histogram> histograms;
69 };
70
71 class Histogram {
72 public:
73         void init(const std::vector<double> &bucket_vals);
74         void init_uniform(size_t num_buckets);  // Sets up buckets 0..(N-1).
75         void count_event(double val);
76         std::string serialize(const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels) const;
77
78 private:
79         // Bucket <i> counts number of events where val[i - 1] < x <= val[i].
80         // The end histogram ends up being made into a cumulative one,
81         // but that's not how we store it here.
82         struct Bucket {
83                 double val;
84                 std::atomic<int64_t> count{0};
85         };
86         std::unique_ptr<Bucket[]> buckets;
87         size_t num_buckets;
88         std::atomic<double> sum{0.0};
89         std::atomic<int64_t> count_after_last_bucket{0};
90 };
91
92 extern Metrics global_metrics;
93
94 #endif  // !defined(_METRICS_H)