]> git.sesse.net Git - nageru/blobdiff - metrics.h
Fix a crash on getting metrics after switching file.
[nageru] / metrics.h
index e54bbcf41b083ea1dcc36c2a2ab781cad81471dc..a8156587a5f2484da831eda01af26cc0c4742454 100644 (file)
--- a/metrics.h
+++ b/metrics.h
@@ -7,31 +7,87 @@
 // which makes it quite unwieldy. Thus, we'll package our own for the time being.
 
 #include <atomic>
+#include <map>
+#include <memory>
 #include <mutex>
 #include <string>
-#include <unordered_map>
+#include <vector>
+
+class Histogram;
 
 class Metrics {
 public:
        enum Type {
                TYPE_COUNTER,
                TYPE_GAUGE,
+               TYPE_HISTOGRAM,  // Internal use only.
        };
 
-       void register_int_metric(const std::string &name, std::atomic<int64_t> *location, Type type = TYPE_COUNTER);
-       void register_double_metric(const std::string &name, std::atomic<double> *location, Type type = TYPE_COUNTER);
+       void add(const std::string &name, std::atomic<int64_t> *location, Type type = TYPE_COUNTER)
+       {
+               add(name, {}, location, type);
+       }
+
+       void add(const std::string &name, std::atomic<double> *location, Type type = TYPE_COUNTER)
+       {
+               add(name, {}, location, type);
+       }
+
+       void add(const std::string &name, Histogram *location)
+       {
+               add(name, {}, location);
+       }
+
+       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);
+       void add(const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels, std::atomic<double> *location, Type type = TYPE_COUNTER);
+       void add(const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels, Histogram *location);
+
        std::string serialize() const;
 
 private:
-       template<class T>
+       enum DataType {
+               DATA_TYPE_INT64,
+               DATA_TYPE_DOUBLE,
+               DATA_TYPE_HISTOGRAM,
+       };
+
        struct Metric {
-               Type type;
-               std::atomic<T> *location;
+               DataType data_type;
+               std::string name;
+               std::vector<std::pair<std::string, std::string>> labels;
+               union {
+                       std::atomic<int64_t> *location_int64;
+                       std::atomic<double> *location_double;
+                       Histogram *location_histogram;
+               };
        };
 
        mutable std::mutex mu;
-       std::unordered_map<std::string, Metric<int64_t>> int_metrics;
-       std::unordered_map<std::string, Metric<double>> double_metrics;
+       std::map<std::string, Type> types;
+       std::vector<Metric> metrics;
+       std::vector<Histogram> histograms;
+};
+
+class Histogram {
+public:
+       void init(const std::vector<double> &bucket_vals);
+       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<std::pair<std::string, std::string>> &labels) const;
+
+private:
+       // Bucket <i> counts number of events where val[i - 1] < x <= val[i].
+       // The end histogram ends up being made into a cumulative one,
+       // but that's not how we store it here.
+       struct Bucket {
+               double val;
+               std::atomic<int64_t> count{0};
+       };
+       std::unique_ptr<Bucket[]> buckets;
+       size_t num_buckets;
+       std::atomic<double> sum{0.0};
+       std::atomic<int64_t> count_after_last_bucket{0};
 };
 
 extern Metrics global_metrics;