X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=metrics.h;h=e2e1e74f5ac9bb818f5bbdb8e6798ec27cadf869;hb=e284d1c7a2e18ee7e4aea082c4a57a3504a0f5e8;hp=0371668bd2a1e25c1adaed613071ac8e3c6c0551;hpb=1836dccf699779d9092a75755cec96cea1734a2a;p=nageru diff --git a/metrics.h b/metrics.h index 0371668..e2e1e74 100644 --- a/metrics.h +++ b/metrics.h @@ -7,13 +7,17 @@ // which makes it quite unwieldy. Thus, we'll package our own for the time being. #include +#include +#include #include #include #include #include +#include #include class Histogram; +class Summary; // Prometheus recommends the use of timestamps instead of “time since event”, // so you can use this to get the number of seconds since the epoch. @@ -27,6 +31,11 @@ public: TYPE_COUNTER, TYPE_GAUGE, TYPE_HISTOGRAM, // Internal use only. + TYPE_SUMMARY, // Internal use only. + }; + enum Laziness { + PRINT_ALWAYS, + PRINT_WHEN_NONEMPTY, }; void add(const std::string &name, std::atomic *location, Type type = TYPE_COUNTER) @@ -44,9 +53,22 @@ public: add(name, {}, location); } + void add(const std::string &name, Summary *location) + { + add(name, {}, location); + } + void add(const std::string &name, const std::vector> &labels, std::atomic *location, Type type = TYPE_COUNTER); void add(const std::string &name, const std::vector> &labels, std::atomic *location, Type type = TYPE_COUNTER); - void add(const std::string &name, const std::vector> &labels, Histogram *location); + void add(const std::string &name, const std::vector> &labels, Histogram *location, Laziness laziness = PRINT_ALWAYS); + void add(const std::string &name, const std::vector> &labels, Summary *location, Laziness laziness = PRINT_ALWAYS); + + void remove(const std::string &name) + { + remove(name, {}); + } + + void remove(const std::string &name, const std::vector> &labels); std::string serialize() const; @@ -58,6 +80,7 @@ private: DATA_TYPE_INT64, DATA_TYPE_DOUBLE, DATA_TYPE_HISTOGRAM, + DATA_TYPE_SUMMARY, }; struct MetricKey { MetricKey(const std::string &name, const std::vector> labels) @@ -78,19 +101,21 @@ private: }; struct Metric { DataType data_type; + Laziness laziness; // Only for TYPE_HISTOGRAM. union { std::atomic *location_int64; std::atomic *location_double; Histogram *location_histogram; + Summary *location_summary; }; }; mutable std::mutex mu; std::map types; // Ordered the same as metrics. std::map metrics; - std::vector histograms; friend class Histogram; + friend class Summary; }; class Histogram { @@ -99,7 +124,7 @@ public: void init_uniform(size_t num_buckets); // Sets up buckets 0..(N-1). void init_geometric(double min, double max, size_t num_buckets); void count_event(double val); - std::string serialize(const std::string &name, const std::vector> &labels) const; + std::string serialize(Metrics::Laziness laziness, const std::string &name, const std::vector> &labels) const; private: // Bucket counts number of events where val[i - 1] < x <= val[i]. @@ -115,6 +140,25 @@ private: std::atomic count_after_last_bucket{0}; }; +// This is a pretty dumb streaming quantile class, but it's exact, and we don't have +// too many values (typically one per frame, and one-minute interval), so we don't +// need anything fancy. +class Summary { +public: + void init(const std::vector &quantiles, double window_seconds); + void count_event(double val); + std::string serialize(Metrics::Laziness laziness, const std::string &name, const std::vector> &labels); + +private: + std::vector quantiles; + std::chrono::duration window; + + mutable std::mutex mu; + std::deque> values; + std::atomic sum{0.0}; + std::atomic count{0}; +}; + extern Metrics global_metrics; #endif // !defined(_METRICS_H)