#include "metrics.h"
+#include <assert.h>
+
#include <locale>
#include <sstream>
Metrics global_metrics;
-void Metrics::add(const string &name, atomic<int64_t> *location, Metrics::Type type)
+void Metrics::add(const string &name, const vector<pair<string, string>> &labels, atomic<int64_t> *location, Metrics::Type type)
{
+ Metric metric;
+ metric.data_type = DATA_TYPE_INT64;
+ metric.name = name;
+ metric.labels = labels;
+ metric.location_int64 = location;
+
lock_guard<mutex> lock(mu);
- int_metrics.emplace(name, Metric<int64_t>{ type, location });
+ metrics.push_back(metric);
+ assert(types.count(name) == 0 || types[name] == type);
+ types[name] = type;
}
-void Metrics::add(const string &name, atomic<double> *location, Metrics::Type type)
+void Metrics::add(const string &name, const vector<pair<string, string>> &labels, atomic<double> *location, Metrics::Type type)
{
+ Metric metric;
+ metric.data_type = DATA_TYPE_DOUBLE;
+ metric.name = name;
+ metric.labels = labels;
+ metric.location_double = location;
+
lock_guard<mutex> lock(mu);
- double_metrics.emplace(name, Metric<double>{ type, location });
+ metrics.push_back(metric);
+ assert(types.count(name) == 0 || types[name] == type);
+ types[name] = type;
}
string Metrics::serialize() const
{
stringstream ss;
ss.imbue(locale("C"));
+ ss.precision(20);
lock_guard<mutex> lock(mu);
- for (const auto &key_and_value : int_metrics) {
- if (key_and_value.second.type == TYPE_GAUGE) {
- ss << "# TYPE nageru_" << key_and_value.first << " gauge\n";
+ for (const auto &name_and_type : types) {
+ if (name_and_type.second == TYPE_GAUGE) {
+ ss << "# TYPE nageru_" << name_and_type.first << " gauge\n";
}
- ss << "nageru_" << key_and_value.first << " " << key_and_value.second.location->load() << "\n";
}
+ for (const Metric &metric : metrics) {
+ string name;
+ if (metric.labels.empty()) {
+ name = "nageru_" + metric.name;
+ } else {
+ name = "nageru_" + metric.name + "{";
+ bool first = true;
+ for (const pair<string, string> &label : metric.labels) {
+ if (!first) {
+ name += ",";
+ }
+ first = false;
+ name += label.first + "=\"" + label.second + "\"";
+ }
+ name += "}";
+ }
-// ss.precision(20);
-// ss << scientific;
- for (const auto &key_and_value : double_metrics) {
- if (key_and_value.second.type == TYPE_GAUGE) {
- ss << "# TYPE nageru_" << key_and_value.first << " gauge\n";
+ if (metric.data_type == DATA_TYPE_INT64) {
+ ss << "nageru_" << name << " " << metric.location_int64->load() << "\n";
+ } else {
+ ss << "nageru_" << name << " " << metric.location_double->load() << "\n";
}
- ss << "nageru_" << key_and_value.first << " " << key_and_value.second.location->load() << "\n";
}
return ss.str();
#include <atomic>
#include <mutex>
#include <string>
-#include <unordered_map>
+#include <map>
+#include <vector>
class Metrics {
public:
TYPE_GAUGE,
};
- void add(const std::string &name, std::atomic<int64_t> *location, Type type = TYPE_COUNTER);
- void add(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, 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);
+
std::string serialize() const;
private:
- template<class T>
+ enum DataType {
+ DATA_TYPE_INT64,
+ DATA_TYPE_DOUBLE,
+ };
+
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;
+ };
};
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;
};
extern Metrics global_metrics;
} // namespace
-void QueueLengthPolicy::register_metrics(const string &card_name)
+void QueueLengthPolicy::register_metrics(const vector<pair<string, string>> &labels)
{
- global_metrics.add("input_queue_length_frames{" + card_name + "}", &metric_input_queue_length_frames, Metrics::TYPE_GAUGE);
- global_metrics.add("input_queue_safe_length_frames{" + card_name + "}", &metric_input_queue_safe_length_frames, Metrics::TYPE_GAUGE);
- global_metrics.add("input_queue_duped_frames{" + card_name + "}", &metric_input_duped_frames);
+ global_metrics.add("input_queue_length_frames", labels, &metric_input_queue_length_frames, Metrics::TYPE_GAUGE);
+ global_metrics.add("input_queue_safe_length_frames", labels, &metric_input_queue_safe_length_frames, Metrics::TYPE_GAUGE);
+ global_metrics.add("input_queue_duped_frames", labels, &metric_input_duped_frames);
}
void QueueLengthPolicy::update_policy(unsigned queue_length)
audio_mixer.trigger_state_changed_callback();
// Register metrics.
+ vector<pair<string, string>> labels;
char card_name[64];
+ snprintf(card_name, sizeof(card_name), "%d", card_index);
+ labels.emplace_back("card", card_name);
+
switch (card_type) {
case CardType::LIVE_CARD:
- snprintf(card_name, sizeof(card_name), "card=\"%d\",cardtype=\"live\"", card_index);
+ labels.emplace_back("cardtype", "live");
break;
case CardType::FAKE_CAPTURE:
- snprintf(card_name, sizeof(card_name), "card=\"%d\",cardtype=\"fake\"", card_index);
+ labels.emplace_back("cardtype", "fake");
break;
case CardType::FFMPEG_INPUT:
- snprintf(card_name, sizeof(card_name), "card=\"%d\",cardtype=\"ffmpeg\"", card_index);
+ labels.emplace_back("cardtype", "ffmpeg");
break;
default:
assert(false);
}
- card->queue_length_policy.register_metrics(card_name);
- global_metrics.add(string("input_dropped_frames_jitter{") + card_name + "}", &card->metric_input_dropped_frames_jitter);
- global_metrics.add(string("input_dropped_frames_error{") + card_name + "}", &card->metric_input_dropped_frames_error);
- global_metrics.add(string("input_dropped_frames_resets{") + card_name + "}", &card->metric_input_resets);
-
- global_metrics.add(string("input_has_signal_bool{") + card_name + "}", &card->metric_input_has_signal_bool, Metrics::TYPE_GAUGE);
- global_metrics.add(string("input_is_connected_bool{") + card_name + "}", &card->metric_input_is_connected_bool, Metrics::TYPE_GAUGE);
- global_metrics.add(string("input_interlaced_bool{") + card_name + "}", &card->metric_input_interlaced_bool, Metrics::TYPE_GAUGE);
- global_metrics.add(string("input_width_pixels{") + card_name + "}", &card->metric_input_width_pixels, Metrics::TYPE_GAUGE);
- global_metrics.add(string("input_height_pixels{") + card_name + "}", &card->metric_input_height_pixels, Metrics::TYPE_GAUGE);
- global_metrics.add(string("input_frame_rate_nom{") + card_name + "}", &card->metric_input_frame_rate_nom, Metrics::TYPE_GAUGE);
- global_metrics.add(string("input_frame_rate_den{") + card_name + "}", &card->metric_input_frame_rate_den, Metrics::TYPE_GAUGE);
- global_metrics.add(string("input_sample_rate_hz{") + card_name + "}", &card->metric_input_sample_rate_hz, Metrics::TYPE_GAUGE);
+ card->queue_length_policy.register_metrics(labels);
+ global_metrics.add("input_dropped_frames_jitter", labels, &card->metric_input_dropped_frames_jitter);
+ global_metrics.add("input_dropped_frames_error", labels, &card->metric_input_dropped_frames_error);
+ global_metrics.add("input_dropped_frames_resets", labels, &card->metric_input_resets);
+
+ global_metrics.add("input_has_signal_bool", labels, &card->metric_input_has_signal_bool, Metrics::TYPE_GAUGE);
+ global_metrics.add("input_is_connected_bool", labels, &card->metric_input_is_connected_bool, Metrics::TYPE_GAUGE);
+ global_metrics.add("input_interlaced_bool", labels, &card->metric_input_interlaced_bool, Metrics::TYPE_GAUGE);
+ global_metrics.add("input_width_pixels", labels, &card->metric_input_width_pixels, Metrics::TYPE_GAUGE);
+ global_metrics.add("input_height_pixels", labels, &card->metric_input_height_pixels, Metrics::TYPE_GAUGE);
+ global_metrics.add("input_frame_rate_nom", labels, &card->metric_input_frame_rate_nom, Metrics::TYPE_GAUGE);
+ global_metrics.add("input_frame_rate_den", labels, &card->metric_input_frame_rate_den, Metrics::TYPE_GAUGE);
+ global_metrics.add("input_sample_rate_hz", labels, &card->metric_input_sample_rate_hz, Metrics::TYPE_GAUGE);
}
void Mixer::set_output_card_internal(int card_index)