]> git.sesse.net Git - nageru/commitdiff
Rework metrics serialization.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Fri, 9 Jun 2017 19:09:07 +0000 (21:09 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Fri, 9 Jun 2017 19:09:07 +0000 (21:09 +0200)
metrics.cpp
metrics.h
mixer.cpp
mixer.h

index b721214a1ba3117f31ed06a07e8acbb4c8dec93d..ffa6b57b5dec2c9fe641e1af799b8afd2b98ba6d 100644 (file)
@@ -1,5 +1,7 @@
 #include "metrics.h"
 
+#include <assert.h>
+
 #include <locale>
 #include <sstream>
 
@@ -7,38 +9,68 @@ using namespace std;
 
 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();
index 3991d2084b48b9d590e6661c12e2e366699369ca..519cb80f694c03756aaa34d5d809eaa1c569a722 100644 (file)
--- a/metrics.h
+++ b/metrics.h
@@ -9,7 +9,8 @@
 #include <atomic>
 #include <mutex>
 #include <string>
-#include <unordered_map>
+#include <map>
+#include <vector>
 
 class Metrics {
 public:
@@ -18,20 +19,40 @@ 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;
index 70b0de91d36a951a4935aef201a11b92da0368d7..c551354e794ab87ed1307b940933978e11553c4c 100644 (file)
--- 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<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)
@@ -472,33 +472,37 @@ void Mixer::configure_card(unsigned card_index, CaptureInterface *capture, CardT
        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)
diff --git a/mixer.h b/mixer.h
index dd44f74bd74906b88c622dd8ff5e819d703daf87..57552879a95ddac9014a6fc2ce056d48335a0b80 100644 (file)
--- 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<std::pair<std::string, std::string>> &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; }