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.
22 // Prometheus recommends the use of timestamps instead of “time since event”,
23 // so you can use this to get the number of seconds since the epoch.
24 // Note that this will be wrong if your clock changes, so for non-metric use,
25 // you should use std::chrono::steady_clock instead.
26 double get_timestamp_for_metrics();
33 TYPE_HISTOGRAM, // Internal use only.
34 TYPE_SUMMARY, // Internal use only.
41 void set_prefix(const std::string &prefix) // Not thread-safe; must be set before HTTPD starts up.
43 this->prefix = prefix;
46 void add(const std::string &name, std::atomic<int64_t> *location, Type type = TYPE_COUNTER)
48 add(name, {}, location, type);
51 void add(const std::string &name, std::atomic<double> *location, Type type = TYPE_COUNTER)
53 add(name, {}, location, type);
56 void add(const std::string &name, Histogram *location)
58 add(name, {}, location);
61 void add(const std::string &name, Summary *location)
63 add(name, {}, location);
66 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);
67 void add(const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels, std::atomic<double> *location, Type type = TYPE_COUNTER);
68 void add(const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels, Histogram *location, Laziness laziness = PRINT_ALWAYS);
69 void add(const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels, Summary *location, Laziness laziness = PRINT_ALWAYS);
71 void remove(const std::string &name)
76 void remove(const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels);
78 void remove_if_exists(const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels);
80 std::string serialize() const;
83 static std::string serialize_name(const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels);
84 static std::string serialize_labels(const std::vector<std::pair<std::string, std::string>> &labels);
93 MetricKey(const std::string &name, const std::vector<std::pair<std::string, std::string>> labels)
94 : name(name), labels(labels), serialized_labels(serialize_labels(labels))
98 bool operator< (const MetricKey &other) const
100 if (name != other.name)
101 return name < other.name;
102 return serialized_labels < other.serialized_labels;
105 const std::string name;
106 const std::vector<std::pair<std::string, std::string>> labels;
107 const std::string serialized_labels;
111 Laziness laziness; // Only for TYPE_HISTOGRAM.
113 std::atomic<int64_t> *location_int64;
114 std::atomic<double> *location_double;
115 Histogram *location_histogram;
116 Summary *location_summary;
120 mutable std::mutex mu;
121 std::map<std::string, Type> types; // Ordered the same as metrics.
122 std::map<MetricKey, Metric> metrics;
123 static std::string prefix;
125 friend class Histogram;
126 friend class Summary;
131 void init(const std::vector<double> &bucket_vals);
132 void init_uniform(size_t num_buckets); // Sets up buckets 0..(N-1).
133 void init_geometric(double min, double max, size_t num_buckets);
134 void count_event(double val);
135 std::string serialize(Metrics::Laziness laziness, const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels) const;
138 // Bucket <i> counts number of events where val[i - 1] < x <= val[i].
139 // The end histogram ends up being made into a cumulative one,
140 // but that's not how we store it here.
143 std::atomic<int64_t> count{0};
145 std::unique_ptr<Bucket[]> buckets;
147 std::atomic<double> sum{0.0};
148 std::atomic<int64_t> count_after_last_bucket{0};
151 // This is a pretty dumb streaming quantile class, but it's exact, and we don't have
152 // too many values (typically one per frame, and one-minute interval), so we don't
153 // need anything fancy.
156 void init(const std::vector<double> &quantiles, double window_seconds);
157 void count_event(double val);
158 std::string serialize(Metrics::Laziness laziness, const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels);
161 std::vector<double> quantiles;
162 std::chrono::duration<double> window;
164 mutable std::mutex mu;
165 std::deque<std::pair<std::chrono::steady_clock::time_point, double>> values;
166 std::atomic<double> sum{0.0};
167 std::atomic<int64_t> count{0};
170 extern Metrics global_metrics;
172 #endif // !defined(_METRICS_H)