| 1 | #include "PrometheusMetricsWriter.h" |
| 2 | |
| 3 | #include <algorithm> |
| 4 | |
| 5 | #include <IO/WriteHelpers.h> |
| 6 | |
| 7 | namespace |
| 8 | { |
| 9 | |
| 10 | template <typename T> |
| 11 | void writeOutLine(DB::WriteBuffer & wb, T && val) |
| 12 | { |
| 13 | DB::writeText(std::forward<T>(val), wb); |
| 14 | DB::writeChar('\n', wb); |
| 15 | } |
| 16 | |
| 17 | template <typename T, typename... TArgs> |
| 18 | void writeOutLine(DB::WriteBuffer & wb, T && val, TArgs &&... args) |
| 19 | { |
| 20 | DB::writeText(std::forward<T>(val), wb); |
| 21 | DB::writeChar(' ', wb); |
| 22 | writeOutLine(wb, std::forward<TArgs>(args)...); |
| 23 | } |
| 24 | |
| 25 | void replaceInvalidChars(std::string & metric_name) |
| 26 | { |
| 27 | std::replace(metric_name.begin(), metric_name.end(), '.', '_'); |
| 28 | } |
| 29 | |
| 30 | } |
| 31 | |
| 32 | |
| 33 | namespace DB |
| 34 | { |
| 35 | |
| 36 | PrometheusMetricsWriter::PrometheusMetricsWriter( |
| 37 | const Poco::Util::AbstractConfiguration & config, const std::string & config_name, |
| 38 | const AsynchronousMetrics & async_metrics_) |
| 39 | : async_metrics(async_metrics_) |
| 40 | , send_events(config.getBool(config_name + ".events" , true)) |
| 41 | , send_metrics(config.getBool(config_name + ".metrics" , true)) |
| 42 | , send_asynchronous_metrics(config.getBool(config_name + ".asynchronous_metrics" , true)) |
| 43 | { |
| 44 | } |
| 45 | |
| 46 | void PrometheusMetricsWriter::write(WriteBuffer & wb) const |
| 47 | { |
| 48 | if (send_events) |
| 49 | { |
| 50 | for (size_t i = 0, end = ProfileEvents::end(); i < end; ++i) |
| 51 | { |
| 52 | const auto counter = ProfileEvents::global_counters[i].load(std::memory_order_relaxed); |
| 53 | |
| 54 | std::string metric_name{ProfileEvents::getName(static_cast<ProfileEvents::Event>(i))}; |
| 55 | std::string metric_doc{ProfileEvents::getDocumentation(static_cast<ProfileEvents::Event>(i))}; |
| 56 | |
| 57 | replaceInvalidChars(metric_name); |
| 58 | std::string key{profile_events_prefix + metric_name}; |
| 59 | |
| 60 | writeOutLine(wb, "# HELP" , key, metric_doc); |
| 61 | writeOutLine(wb, "# TYPE" , key, "counter" ); |
| 62 | writeOutLine(wb, key, counter); |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | if (send_metrics) |
| 67 | { |
| 68 | for (size_t i = 0, end = CurrentMetrics::end(); i < end; ++i) |
| 69 | { |
| 70 | const auto value = CurrentMetrics::values[i].load(std::memory_order_relaxed); |
| 71 | |
| 72 | std::string metric_name{CurrentMetrics::getName(static_cast<CurrentMetrics::Metric>(i))}; |
| 73 | std::string metric_doc{CurrentMetrics::getDocumentation(static_cast<CurrentMetrics::Metric>(i))}; |
| 74 | |
| 75 | replaceInvalidChars(metric_name); |
| 76 | std::string key{current_metrics_prefix + metric_name}; |
| 77 | |
| 78 | writeOutLine(wb, "# HELP" , key, metric_doc); |
| 79 | writeOutLine(wb, "# TYPE" , key, "gauge" ); |
| 80 | writeOutLine(wb, key, value); |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | if (send_asynchronous_metrics) |
| 85 | { |
| 86 | auto async_metrics_values = async_metrics.getValues(); |
| 87 | for (const auto & name_value : async_metrics_values) |
| 88 | { |
| 89 | std::string key{asynchronous_metrics_prefix + name_value.first}; |
| 90 | |
| 91 | replaceInvalidChars(key); |
| 92 | auto value = name_value.second; |
| 93 | |
| 94 | // TODO: add HELP section? asynchronous_metrics contains only key and value |
| 95 | writeOutLine(wb, "# TYPE" , key, "gauge" ); |
| 96 | writeOutLine(wb, key, value); |
| 97 | } |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | } |
| 102 | |