From fc65b01785b439f1ce0e8b04a33ad8abd5b4091e Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Fri, 9 Jun 2017 21:09:07 +0200 Subject: [PATCH] Rework metrics serialization. --- metrics.cpp | 60 ++++++++++++++++++++++++++++++++++++++++------------- metrics.h | 37 ++++++++++++++++++++++++++------- mixer.cpp | 44 +++++++++++++++++++++------------------ mixer.h | 2 +- 4 files changed, 100 insertions(+), 43 deletions(-) diff --git a/metrics.cpp b/metrics.cpp index b721214..ffa6b57 100644 --- a/metrics.cpp +++ b/metrics.cpp @@ -1,5 +1,7 @@ #include "metrics.h" +#include + #include #include @@ -7,38 +9,68 @@ using namespace std; Metrics global_metrics; -void Metrics::add(const string &name, atomic *location, Metrics::Type type) +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); - int_metrics.emplace(name, Metric{ type, location }); + metrics.push_back(metric); + assert(types.count(name) == 0 || types[name] == type); + types[name] = type; } -void Metrics::add(const string &name, atomic *location, Metrics::Type type) +void Metrics::add(const string &name, const vector> &labels, atomic *location, Metrics::Type type) { + Metric metric; + metric.data_type = DATA_TYPE_DOUBLE; + metric.name = name; + metric.labels = labels; + metric.location_double = location; + lock_guard lock(mu); - double_metrics.emplace(name, Metric{ 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 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 &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(); diff --git a/metrics.h b/metrics.h index 3991d20..519cb80 100644 --- a/metrics.h +++ b/metrics.h @@ -9,7 +9,8 @@ #include #include #include -#include +#include +#include class Metrics { public: @@ -18,20 +19,40 @@ public: TYPE_GAUGE, }; - void add(const std::string &name, std::atomic *location, Type type = TYPE_COUNTER); - void add(const std::string &name, std::atomic *location, Type type = TYPE_COUNTER); + void add(const std::string &name, std::atomic *location, Type type = TYPE_COUNTER) + { + add(name, {}, location, type); + } + + void add(const std::string &name, std::atomic *location, Type type = TYPE_COUNTER) + { + add(name, {}, location, type); + } + + void add(const std::string &name, const std::vector> &labels, std::atomic *location, Type type = TYPE_COUNTER); + void add(const std::string &name, const std::vector> &labels, std::atomic *location, Type type = TYPE_COUNTER); + std::string serialize() const; private: - template + enum DataType { + DATA_TYPE_INT64, + DATA_TYPE_DOUBLE, + }; + struct Metric { - Type type; - std::atomic *location; + DataType data_type; + std::string name; + std::vector> labels; + union { + std::atomic *location_int64; + std::atomic *location_double; + }; }; mutable std::mutex mu; - std::unordered_map> int_metrics; - std::unordered_map> double_metrics; + std::map types; + std::vector metrics; }; extern Metrics global_metrics; diff --git a/mixer.cpp b/mixer.cpp index 70b0de9..c551354 100644 --- a/mixer.cpp +++ b/mixer.cpp @@ -198,11 +198,11 @@ void upload_texture(GLuint tex, GLuint width, GLuint height, GLuint stride, bool } // namespace -void QueueLengthPolicy::register_metrics(const string &card_name) +void QueueLengthPolicy::register_metrics(const vector> &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) @@ -472,33 +472,37 @@ void Mixer::configure_card(unsigned card_index, CaptureInterface *capture, CardT audio_mixer.trigger_state_changed_callback(); // Register metrics. + vector> 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) diff --git a/mixer.h b/mixer.h index dd44f74..5755287 100644 --- a/mixer.h +++ b/mixer.h @@ -88,7 +88,7 @@ public: been_at_safe_point_since_last_starvation = false; } - void register_metrics(const std::string &card_name); + void register_metrics(const std::vector> &labels); void update_policy(unsigned queue_length); // Call before picking out a frame, so 0 means starvation. unsigned get_safe_queue_length() const { return safe_queue_length; } -- 2.39.2