}
string Metrics::serialize_name(const string &name, const vector<pair<string, string>> &labels)
+{
+ return "nageru_" + name + serialize_labels(labels);
+}
+
+string Metrics::serialize_labels(const vector<pair<string, string>> &labels)
{
if (labels.empty()) {
- return "nageru_" + name;
+ return "";
}
string label_str;
}
label_str += label.first + "=\"" + label.second + "\"";
}
- return "nageru_" + name + "{" + label_str + "}";
+ return "{" + label_str + "}";
}
void Metrics::add(const string &name, const vector<pair<string, string>> &labels, atomic<int64_t> *location, Metrics::Type type)
types[name] = type;
}
-void Metrics::add(const string &name, const vector<pair<string, string>> &labels, Histogram *location)
+void Metrics::add(const string &name, const vector<pair<string, string>> &labels, Histogram *location, Laziness laziness)
{
Metric metric;
metric.data_type = DATA_TYPE_HISTOGRAM;
+ metric.laziness = laziness;
metric.location_histogram = location;
lock_guard<mutex> lock(mu);
types[name] = TYPE_HISTOGRAM;
}
+void Metrics::remove(const string &name, const vector<pair<string, string>> &labels)
+{
+ lock_guard<mutex> lock(mu);
+
+ auto it = metrics.find(MetricKey(name, labels));
+ assert(it != metrics.end());
+
+ // If this is the last metric with this name, remove the type as well.
+ if (!((it != metrics.begin() && prev(it)->first.name == name) ||
+ (it != metrics.end() && next(it)->first.name == name))) {
+ types.erase(name);
+ }
+
+ metrics.erase(it);
+}
+
string Metrics::serialize() const
{
stringstream ss;
lock_guard<mutex> lock(mu);
auto type_it = types.cbegin();
for (const auto &key_and_metric : metrics) {
- const string &name = key_and_metric.first.serialized;
+ string name = "nageru_" + key_and_metric.first.name + key_and_metric.first.serialized_labels;
const Metric &metric = key_and_metric.second;
if (type_it != types.cend() &&
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";
+ double val = metric.location_double->load();
+ if (isnan(val)) {
+ // Prometheus can't handle “-nan”.
+ ss << name << " NaN\n";
+ } else {
+ ss << name << " " << val << "\n";
+ }
} else {
- ss << metric.location_histogram->serialize(key_and_metric.first.name, key_and_metric.first.labels);
+ ss << metric.location_histogram->serialize(metric.laziness, key_and_metric.first.name, key_and_metric.first.labels);
}
}
sum = sum + val;
}
-string Histogram::serialize(const string &name, const vector<pair<string, string>> &labels) const
+string Histogram::serialize(Metrics::Laziness laziness, const string &name, const vector<pair<string, string>> &labels) const
{
+ // Check if the histogram is empty and should not be serialized.
+ if (laziness == Metrics::PRINT_WHEN_NONEMPTY && count_after_last_bucket.load() == 0) {
+ bool empty = true;
+ for (size_t bucket_idx = 0; bucket_idx < num_buckets; ++bucket_idx) {
+ if (buckets[bucket_idx].count.load() != 0) {
+ empty = false;
+ break;
+ }
+ }
+ if (empty) {
+ return "";
+ }
+ }
+
stringstream ss;
ss.imbue(locale("C"));
ss.precision(20);