16 #include "tensorflow_serving/util/prometheus_exporter.h"
21 #include "absl/strings/match.h"
22 #include "absl/strings/str_cat.h"
23 #include "absl/strings/str_format.h"
24 #include "absl/strings/str_join.h"
27 namespace tensorflow {
32 string SanitizeLabelValue(
const string& value) {
34 string new_value = value;
36 RE2::GlobalReplace(&new_value,
"\\\\",
"\\\\\\\\");
38 RE2::GlobalReplace(&new_value,
"\"",
"\\\\\"");
42 string SanatizeLabelName(
const string& name) {
44 string new_name = name;
45 RE2::GlobalReplace(&new_name,
"[^a-zA-Z0-9]",
"_");
46 if (RE2::FullMatch(new_name,
"^[0-9].*")) {
48 new_name = absl::StrCat(
"_", new_name);
53 string GetPrometheusMetricName(
54 const monitoring::MetricDescriptor& metric_descriptor) {
56 string new_name = metric_descriptor.name;
57 RE2::GlobalReplace(&new_name,
"[^a-zA-Z0-9_]",
":");
58 if (RE2::FullMatch(new_name,
"^[0-9].*")) {
60 new_name = absl::StrCat(
"_", new_name);
65 void SerializeHistogram(
const monitoring::MetricDescriptor& metric_descriptor,
66 const monitoring::PointSet& point_set,
67 std::vector<string>* lines) {
74 string prom_metric_name = GetPrometheusMetricName(metric_descriptor);
76 lines->push_back(absl::StrFormat(
"# TYPE %s histogram", prom_metric_name));
77 for (
const auto& point : point_set.points) {
79 std::vector<string> labels = {};
80 labels.reserve(point->labels.size());
81 for (
const auto& label : point->labels) {
82 labels.push_back(absl::StrFormat(
"%s=\"%s\"",
83 SanatizeLabelName(label.name),
84 SanitizeLabelValue(label.value)));
86 int64_t cumulative_count = 0;
87 string bucket_prefix =
88 absl::StrCat(prom_metric_name,
"_bucket{", absl::StrJoin(labels,
","));
89 if (!labels.empty()) {
90 absl::StrAppend(&bucket_prefix,
",");
93 for (
int i = 0; i < point->histogram_value.bucket_size(); i++) {
94 cumulative_count += point->histogram_value.bucket(i);
96 (i < point->histogram_value.bucket_size() - 1)
97 ? absl::StrCat(point->histogram_value.bucket_limit(i))
99 lines->push_back(absl::StrCat(
100 bucket_prefix, absl::StrFormat(
"le=\"%s\"} ", bucket_limit),
104 lines->push_back(absl::StrCat(prom_metric_name,
"_sum{",
105 absl::StrJoin(labels,
","),
"} ",
106 point->histogram_value.sum()));
107 lines->push_back(absl::StrCat(prom_metric_name,
"_count{",
108 absl::StrJoin(labels,
","),
"} ",
113 void SerializeScalar(
const monitoring::MetricDescriptor& metric_descriptor,
114 const monitoring::PointSet& point_set,
115 std::vector<string>* lines) {
119 string prom_metric_name = GetPrometheusMetricName(metric_descriptor);
120 string metric_type_str =
"untyped";
121 if (metric_descriptor.metric_kind == monitoring::MetricKind::kCumulative) {
122 metric_type_str =
"counter";
123 }
else if (metric_descriptor.metric_kind == monitoring::MetricKind::kGauge) {
124 metric_type_str =
"gauge";
128 absl::StrFormat(
"# TYPE %s %s", prom_metric_name, metric_type_str));
129 for (
const auto& point : point_set.points) {
131 string name_bracket = absl::StrCat(prom_metric_name,
"{");
132 std::vector<string> labels = {};
133 labels.reserve(point->labels.size());
134 for (
const auto& label : point->labels) {
135 labels.push_back(absl::StrFormat(
"%s=\"%s\"",
136 SanatizeLabelName(label.name),
137 SanitizeLabelValue(label.value)));
139 lines->push_back(absl::StrCat(name_bracket, absl::StrJoin(labels,
","),
140 absl::StrFormat(
"} %d", point->int64_value)));
144 void SerializeMetric(
const monitoring::MetricDescriptor& metric_descriptor,
145 const monitoring::PointSet& point_set,
146 std::vector<string>* lines) {
147 if (metric_descriptor.value_type == monitoring::ValueType::kHistogram) {
148 SerializeHistogram(metric_descriptor, point_set, lines);
150 SerializeScalar(metric_descriptor, point_set, lines);
156 const char*
const PrometheusExporter::kPrometheusPath =
157 "/monitoring/prometheus/metrics";
159 PrometheusExporter::PrometheusExporter()
160 : collection_registry_(monitoring::CollectionRegistry::Default()) {}
162 Status PrometheusExporter::GeneratePage(
string* http_page) {
163 if (http_page ==
nullptr) {
165 static_cast<absl::StatusCode
>(absl::StatusCode::kInvalidArgument),
166 "Http page pointer is null");
168 monitoring::CollectionRegistry::CollectMetricsOptions collect_options;
169 collect_options.collect_metric_descriptors =
true;
170 const std::unique_ptr<monitoring::CollectedMetrics> collected_metrics =
171 collection_registry_->CollectMetrics(collect_options);
173 const auto& descriptor_map = collected_metrics->metric_descriptor_map;
174 const auto& metric_map = collected_metrics->point_set_map;
176 std::vector<string> lines;
177 for (
const auto& name_and_metric_descriptor : descriptor_map) {
178 const string& metric_name = name_and_metric_descriptor.first;
179 auto metric_iterator = metric_map.find(metric_name);
180 if (metric_iterator == metric_map.end()) {
184 SerializeMetric(*name_and_metric_descriptor.second,
185 *(metric_iterator->second), &lines);
187 *http_page = absl::StrJoin(lines,
"\n");
188 absl::StrAppend(http_page,
"\n");
189 return absl::OkStatus();