From: Steinar H. Gunderson Date: Mon, 12 Jun 2017 22:47:45 +0000 (+0200) Subject: Store the metrics sorted. X-Git-Tag: 1.6.1~49 X-Git-Url: https://git.sesse.net/?p=nageru;a=commitdiff_plain;h=12595ec000328e3ae26ace5252b936a605fef144 Store the metrics sorted. This makes it easier to remove them later (since you can index by name), which we're going to need. --- diff --git a/metrics.cpp b/metrics.cpp index fd5e54c..db3c4b8 100644 --- a/metrics.cpp +++ b/metrics.cpp @@ -18,9 +18,7 @@ double get_timestamp_for_metrics() return duration(system_clock::now().time_since_epoch()).count(); } -namespace { - -string serialize_name(const string &name, const vector> &labels) +string Metrics::serialize_name(const string &name, const vector> &labels) { if (labels.empty()) { return "nageru_" + name; @@ -36,18 +34,14 @@ string serialize_name(const string &name, const vector> &la return "nageru_" + name + "{" + label_str + "}"; } -} // namespace - void Metrics::add(const string &name, const vector> &labels, atomic *location, Metrics::Type type) { Metric metric; metric.data_type = DATA_TYPE_INT64; - metric.name = name; - metric.labels = labels; metric.location_int64 = location; lock_guard lock(mu); - metrics.push_back(metric); + metrics.emplace(MetricKey(name, labels), metric); assert(types.count(name) == 0 || types[name] == type); types[name] = type; } @@ -56,12 +50,10 @@ void Metrics::add(const string &name, const vector> &labels { Metric metric; metric.data_type = DATA_TYPE_DOUBLE; - metric.name = name; - metric.labels = labels; metric.location_double = location; lock_guard lock(mu); - metrics.push_back(metric); + metrics.emplace(MetricKey(name, labels), metric); assert(types.count(name) == 0 || types[name] == type); types[name] = type; } @@ -70,12 +62,10 @@ void Metrics::add(const string &name, const vector> &labels { Metric metric; metric.data_type = DATA_TYPE_HISTOGRAM; - metric.name = name; - metric.labels = labels; metric.location_histogram = location; lock_guard lock(mu); - metrics.push_back(metric); + metrics.emplace(MetricKey(name, labels), metric); assert(types.count(name) == 0 || types[name] == TYPE_HISTOGRAM); types[name] = TYPE_HISTOGRAM; } @@ -87,22 +77,29 @@ string Metrics::serialize() const ss.precision(20); lock_guard lock(mu); - for (const auto &name_and_type : types) { - if (name_and_type.second == TYPE_GAUGE) { - ss << "# TYPE nageru_" << name_and_type.first << " gauge\n"; - } else if (name_and_type.second == TYPE_HISTOGRAM) { - ss << "# TYPE nageru_" << name_and_type.first << " histogram\n"; + auto type_it = types.cbegin(); + for (const auto &key_and_metric : metrics) { + const string &name = key_and_metric.first.serialized; + const Metric &metric = key_and_metric.second; + + if (type_it != types.cend() && + key_and_metric.first.name == type_it->first) { + // It's the first time we print out any metric with this name, + // so add the type header. + if (type_it->second == TYPE_GAUGE) { + ss << "# TYPE nageru_" << type_it->first << " gauge\n"; + } else if (type_it->second == TYPE_HISTOGRAM) { + ss << "# TYPE nageru_" << type_it->first << " histogram\n"; + } + ++type_it; } - } - for (const Metric &metric : metrics) { - string name = serialize_name(metric.name, metric.labels); if (metric.data_type == DATA_TYPE_INT64) { ss << name << " " << metric.location_int64->load() << "\n"; } else if (metric.data_type == DATA_TYPE_DOUBLE) { ss << name << " " << metric.location_double->load() << "\n"; } else { - ss << metric.location_histogram->serialize(metric.name, metric.labels); + ss << metric.location_histogram->serialize(key_and_metric.first.name, key_and_metric.first.labels); } } @@ -167,13 +164,13 @@ string Histogram::serialize(const string &name, const vector> &labels); + enum DataType { DATA_TYPE_INT64, DATA_TYPE_DOUBLE, DATA_TYPE_HISTOGRAM, }; - + struct MetricKey { + MetricKey(const std::string &name, const std::vector> labels) + : name(name), labels(labels), serialized(serialize_name(name, labels)) + { + } + + bool operator< (const MetricKey &other) const + { + return serialized < other.serialized; + } + + const std::string name; + const std::vector> labels; + const std::string serialized; + }; struct Metric { DataType data_type; - std::string name; - std::vector> labels; union { std::atomic *location_int64; std::atomic *location_double; @@ -69,9 +83,11 @@ private: }; mutable std::mutex mu; - std::map types; - std::vector metrics; + std::map types; // Ordered the same as metrics, assuming no { signs in names (which are illegal). + std::map metrics; std::vector histograms; + + friend class Histogram; }; class Histogram {