22 #include "metrics_processor.h"
24 #include "aspect/metrics_manager.h"
26 #include <logging/logger.h>
27 #include <webview/page_reply.h>
28 #include <webview/request.h>
31 #if GOOGLE_PROTOBUF_VERSION >= 3000000
32 # include <google/protobuf/util/json_util.h>
33 # include <google/protobuf/util/message_differencer.h>
35 #include <google/protobuf/io/coded_stream.h>
36 #include <google/protobuf/io/zero_copy_stream_impl.h>
55 const std::string &baseurl)
56 : metrics_manager_(metrics_manager), logger_(logger), base_url_(baseurl)
72 std::string accepted_encoding =
"text/plain";
74 accepted_encoding = request->
header(
"Accept");
80 std::list<io::prometheus::client::MetricFamily> metrics(
83 if (accepted_encoding.find(
"application/vnd.google.protobuf") != std::string::npos) {
85 "application/vnd.google.protobuf; "
86 "proto=io.prometheus.client.MetricFamily; "
87 "encoding=delimited");
88 std::ostringstream ss;
89 for (
auto &&metric : metrics) {
91 google::protobuf::io::OstreamOutputStream raw_output{&ss};
92 google::protobuf::io::CodedOutputStream output(&raw_output);
94 const int size = metric.ByteSize();
95 output.WriteVarint32(size);
99 metric.SerializeToString(&buffer);
104 }
else if (accepted_encoding.find(
"application/json") != std::string::npos) {
105 #if GOOGLE_PROTOBUF_VERSION >= 3000000
106 reply->
add_header(
"Content-type",
"application/json");
107 std::stringstream ss;
110 for (
auto &&metric : metrics) {
112 google::protobuf::util::MessageToJsonString(metric,
114 google::protobuf::util::JsonPrintOptions());
116 if (!google::protobuf::util::MessageDifferencer::Equals(metric, metrics.back())) {
123 reply->
set_code(WebReply::HTTP_NOT_IMPLEMENTED);
124 reply->
add_header(
"Content-type",
"text/plain");
125 reply->
append_body(
"JSON output only supported with protobuf 3");
128 reply->
add_header(
"Content-type",
"text/plain; version=0.0.4");
130 for (
auto &&metric : metrics) {
131 if (metric.metric_size() > 0) {
133 if (metric.has_help()) {
134 reply->
append_body(
"# HELP %s %s\n", metric.name().c_str(), metric.help().c_str());
136 if (metric.has_type()) {
137 const char *typestr = NULL;
138 switch (metric.type()) {
139 case io::prometheus::client::COUNTER: typestr =
"counter";
break;
140 case io::prometheus::client::GAUGE: typestr =
"gauge";
break;
141 case io::prometheus::client::UNTYPED: typestr =
"untyped";
break;
142 case io::prometheus::client::HISTOGRAM: typestr =
"histogram";
break;
143 case io::prometheus::client::SUMMARY: typestr =
"summary";
break;
145 if (typestr != NULL) {
146 reply->
append_body(
"# TYPE %s %s\n", metric.name().c_str(), typestr);
149 for (
int i = 0; i < metric.metric_size(); ++i) {
150 const io::prometheus::client::Metric &m = metric.metric(i);
153 if (m.label_size() > 0) {
154 std::ostringstream ss;
156 ss << m.label(0).name() <<
"=" << m.label(0).value();
157 for (
int l = 1; l < m.label_size(); ++l) {
158 const io::prometheus::client::LabelPair &label = m.label(l);
159 ss <<
"," << label.name() <<
"=" << label.value();
164 std::string timestamp;
165 if (m.has_timestamp_ms()) {
166 timestamp =
" " + std::to_string(m.timestamp_ms());
169 switch (metric.type()) {
170 case io::prometheus::client::COUNTER:
171 if (m.has_counter()) {
173 metric.name().c_str(),
179 metric.name().c_str(),
184 case io::prometheus::client::GAUGE:
187 metric.name().c_str(),
193 metric.name().c_str(),
198 case io::prometheus::client::UNTYPED:
199 if (m.has_untyped()) {
201 metric.name().c_str(),
207 metric.name().c_str(),
212 case io::prometheus::client::SUMMARY:
213 if (m.has_summary()) {
214 const io::prometheus::client::Summary &summary = m.summary();
215 for (
int q = 0; q < summary.quantile_size(); ++q) {
216 const io::prometheus::client::Quantile &quantile = summary.quantile(q);
218 if (labels.empty()) {
219 q_label =
" {quantile=" + std::to_string(quantile.quantile()) +
"}";
221 q_label = labels.substr(0, labels.size() - 1)
222 +
",quantile=" + std::to_string(quantile.quantile()) +
"}";
225 metric.name().c_str(),
231 metric.name().c_str(),
233 summary.sample_sum(),
236 metric.name().c_str(),
238 summary.sample_count(),
242 metric.name().c_str(),
247 case io::prometheus::client::HISTOGRAM:
248 if (m.has_histogram()) {
249 const io::prometheus::client::Histogram &histogram = m.histogram();
250 for (
int b = 0; b < histogram.bucket_size(); ++b) {
251 const io::prometheus::client::Bucket &bucket = histogram.bucket(b);
253 if (labels.empty()) {
254 b_label =
" {le=" + std::to_string(bucket.upper_bound()) +
"}";
256 b_label = labels.substr(0, labels.size() - 1)
257 +
",le=" + std::to_string(bucket.upper_bound()) +
"}";
260 metric.name().c_str(),
262 bucket.cumulative_count(),
266 metric.name().c_str(),
268 histogram.sample_sum(),
271 metric.name().c_str(),
273 histogram.sample_count(),
277 metric.name().c_str(),