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 | |