12 using namespace std::chrono;
14 Metrics global_metrics;
16 double get_timestamp_for_metrics()
18 return duration<double>(system_clock::now().time_since_epoch()).count();
23 string serialize_name(const string &name, const vector<pair<string, string>> &labels)
26 return "nageru_" + name;
30 for (const pair<string, string> &label : labels) {
31 if (!label_str.empty()) {
34 label_str += label.first + "=\"" + label.second + "\"";
36 return "nageru_" + name + "{" + label_str + "}";
41 void Metrics::add(const string &name, const vector<pair<string, string>> &labels, atomic<int64_t> *location, Metrics::Type type)
44 metric.data_type = DATA_TYPE_INT64;
46 metric.labels = labels;
47 metric.location_int64 = location;
49 lock_guard<mutex> lock(mu);
50 metrics.push_back(metric);
51 assert(types.count(name) == 0 || types[name] == type);
55 void Metrics::add(const string &name, const vector<pair<string, string>> &labels, atomic<double> *location, Metrics::Type type)
58 metric.data_type = DATA_TYPE_DOUBLE;
60 metric.labels = labels;
61 metric.location_double = location;
63 lock_guard<mutex> lock(mu);
64 metrics.push_back(metric);
65 assert(types.count(name) == 0 || types[name] == type);
69 void Metrics::add(const string &name, const vector<pair<string, string>> &labels, Histogram *location)
72 metric.data_type = DATA_TYPE_HISTOGRAM;
74 metric.labels = labels;
75 metric.location_histogram = location;
77 lock_guard<mutex> lock(mu);
78 metrics.push_back(metric);
79 assert(types.count(name) == 0 || types[name] == TYPE_HISTOGRAM);
80 types[name] = TYPE_HISTOGRAM;
83 string Metrics::serialize() const
86 ss.imbue(locale("C"));
89 lock_guard<mutex> lock(mu);
90 for (const auto &name_and_type : types) {
91 if (name_and_type.second == TYPE_GAUGE) {
92 ss << "# TYPE nageru_" << name_and_type.first << " gauge\n";
93 } else if (name_and_type.second == TYPE_HISTOGRAM) {
94 ss << "# TYPE nageru_" << name_and_type.first << " histogram\n";
97 for (const Metric &metric : metrics) {
98 string name = serialize_name(metric.name, metric.labels);
100 if (metric.data_type == DATA_TYPE_INT64) {
101 ss << name << " " << metric.location_int64->load() << "\n";
102 } else if (metric.data_type == DATA_TYPE_DOUBLE) {
103 ss << name << " " << metric.location_double->load() << "\n";
105 ss << metric.location_histogram->serialize(metric.name, metric.labels);
112 void Histogram::init(const vector<double> &bucket_vals)
114 this->num_buckets = bucket_vals.size();
115 buckets.reset(new Bucket[num_buckets]);
116 for (size_t i = 0; i < num_buckets; ++i) {
117 buckets[i].val = bucket_vals[i];
121 void Histogram::init_uniform(size_t num_buckets)
123 this->num_buckets = num_buckets;
124 buckets.reset(new Bucket[num_buckets]);
125 for (size_t i = 0; i < num_buckets; ++i) {
130 void Histogram::init_geometric(double min, double max, size_t num_buckets)
132 this->num_buckets = num_buckets;
133 buckets.reset(new Bucket[num_buckets]);
134 for (size_t i = 0; i < num_buckets; ++i) {
135 buckets[i].val = min * pow(max / min, double(i) / (num_buckets - 1));
139 void Histogram::count_event(double val)
142 ref_bucket.val = val;
143 auto it = lower_bound(buckets.get(), buckets.get() + num_buckets, ref_bucket,
144 [](const Bucket &a, const Bucket &b) { return a.val < b.val; });
145 if (it == buckets.get() + num_buckets) {
146 ++count_after_last_bucket;
150 // Non-atomic add, but that's fine, since there are no concurrent writers.
154 string Histogram::serialize(const string &name, const vector<pair<string, string>> &labels) const
157 ss.imbue(locale("C"));
161 for (size_t bucket_idx = 0; bucket_idx < num_buckets; ++bucket_idx) {
163 le_ss.imbue(locale("C"));
165 le_ss << buckets[bucket_idx].val;
166 vector<pair<string, string>> bucket_labels = labels;
167 bucket_labels.emplace_back("le", le_ss.str());
169 count += buckets[bucket_idx].count.load();
170 ss << serialize_name(name + "_bucket", bucket_labels) << " " << count << "\n";
173 count += count_after_last_bucket.load();
175 ss << serialize_name(name + "_sum", labels) << " " << sum.load() << "\n";
176 ss << serialize_name(name + "_count", labels) << " " << count << "\n";