| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 | 
							- #include "prometheus/text_serializer.h"
 
- #include <cmath>
 
- #include <iostream>
 
- #include <sstream>
 
- namespace prometheus {
 
- using namespace io::prometheus::client;
 
- namespace {
 
- // Write a double as a string, with proper formatting for infinity and NaN
 
- std::string ToString(double v) {
 
-   if (std::isnan(v)) {
 
-     return "Nan";
 
-   }
 
-   if (std::isinf(v)) {
 
-     return (v < 0 ? "-Inf" : "+Inf");
 
-   }
 
-   return std::to_string(v);
 
- }
 
- const std::string& EscapeLabelValue(const std::string& value,
 
-                                     std::string* tmp) {
 
-   bool copy = false;
 
-   for (size_t i = 0; i < value.size(); ++i) {
 
-     auto c = value[i];
 
-     if (c == '\\' || c == '"' || c == '\n') {
 
-       if (!copy) {
 
-         tmp->reserve(value.size() + 1);
 
-         tmp->assign(value, 0, i);
 
-         copy = true;
 
-       }
 
-       if (c == '\\') {
 
-         tmp->append("\\\\");
 
-       } else if (c == '"') {
 
-         tmp->append("\\\"");
 
-       } else {
 
-         tmp->append("\\\n");
 
-       }
 
-     } else if (copy) {
 
-       tmp->push_back(c);
 
-     }
 
-   }
 
-   return copy ? *tmp : value;
 
- }
 
- // Write a line header: metric name and labels
 
- void WriteHead(std::ostream& out, const MetricFamily& family,
 
-                const Metric& metric, const std::string& suffix = "",
 
-                const std::string& extraLabelName = "",
 
-                const std::string& extraLabelValue = "") {
 
-   out << family.name() << suffix;
 
-   if (metric.label_size() != 0 || !extraLabelName.empty()) {
 
-     out << "{";
 
-     const char* prefix = "";
 
-     std::string tmp;
 
-     for (auto& lp : metric.label()) {
 
-       out << prefix << lp.name() << "=\"" << EscapeLabelValue(lp.value(), &tmp)
 
-           << "\"";
 
-       prefix = ",";
 
-     }
 
-     if (!extraLabelName.empty()) {
 
-       out << prefix << extraLabelName << "=\""
 
-           << EscapeLabelValue(extraLabelValue, &tmp) << "\"";
 
-     }
 
-     out << "}";
 
-   }
 
-   out << " ";
 
- }
 
- // Write a line trailer: timestamp
 
- void WriteTail(std::ostream& out, const Metric& metric) {
 
-   if (metric.timestamp_ms() != 0) {
 
-     out << " " << metric.timestamp_ms();
 
-   }
 
-   out << "\n";
 
- }
 
- void SerializeCounter(std::ostream& out, const MetricFamily& family,
 
-                       const Metric& metric) {
 
-   WriteHead(out, family, metric);
 
-   out << ToString(metric.counter().value());
 
-   WriteTail(out, metric);
 
- }
 
- void SerializeGauge(std::ostream& out, const MetricFamily& family,
 
-                     const Metric& metric) {
 
-   WriteHead(out, family, metric);
 
-   out << ToString(metric.gauge().value());
 
-   WriteTail(out, metric);
 
- }
 
- void SerializeSummary(std::ostream& out, const MetricFamily& family,
 
-                       const Metric& metric) {
 
-   auto& sum = metric.summary();
 
-   WriteHead(out, family, metric, "_count");
 
-   out << sum.sample_count();
 
-   WriteTail(out, metric);
 
-   WriteHead(out, family, metric, "_sum");
 
-   out << ToString(sum.sample_sum());
 
-   WriteTail(out, metric);
 
-   for (auto& q : sum.quantile()) {
 
-     WriteHead(out, family, metric, "_quantile", "quantile",
 
-               ToString(q.quantile()));
 
-     out << ToString(q.value());
 
-     WriteTail(out, metric);
 
-   }
 
- }
 
- void SerializeUntyped(std::ostream& out, const MetricFamily& family,
 
-                       const Metric& metric) {
 
-   WriteHead(out, family, metric);
 
-   out << ToString(metric.untyped().value());
 
-   WriteTail(out, metric);
 
- }
 
- void SerializeHistogram(std::ostream& out, const MetricFamily& family,
 
-                         const Metric& metric) {
 
-   auto& hist = metric.histogram();
 
-   WriteHead(out, family, metric, "_count");
 
-   out << hist.sample_count();
 
-   WriteTail(out, metric);
 
-   WriteHead(out, family, metric, "_sum");
 
-   out << ToString(hist.sample_sum());
 
-   WriteTail(out, metric);
 
-   double last = -std::numeric_limits<double>::infinity();
 
-   for (auto& b : hist.bucket()) {
 
-     WriteHead(out, family, metric, "_bucket", "le", ToString(b.upper_bound()));
 
-     last = b.upper_bound();
 
-     out << b.cumulative_count();
 
-     WriteTail(out, metric);
 
-   }
 
-   if (last != std::numeric_limits<double>::infinity()) {
 
-     WriteHead(out, family, metric, "_bucket", "le", "+Inf");
 
-     out << hist.sample_count();
 
-     WriteTail(out, metric);
 
-   }
 
- }
 
- void SerializeFamily(std::ostream& out, const MetricFamily& family) {
 
-   if (!family.help().empty()) {
 
-     out << "# HELP " << family.name() << " " << family.help() << "\n";
 
-   }
 
-   switch (family.type()) {
 
-     case COUNTER:
 
-       out << "# TYPE " << family.name() << " counter\n";
 
-       for (auto& metric : family.metric()) {
 
-         SerializeCounter(out, family, metric);
 
-       }
 
-       break;
 
-     case GAUGE:
 
-       out << "# TYPE " << family.name() << " gauge\n";
 
-       for (auto& metric : family.metric()) {
 
-         SerializeGauge(out, family, metric);
 
-       }
 
-       break;
 
-     case SUMMARY:
 
-       out << "# TYPE " << family.name() << " summary\n";
 
-       for (auto& metric : family.metric()) {
 
-         SerializeSummary(out, family, metric);
 
-       }
 
-       break;
 
-     case UNTYPED:
 
-       out << "# TYPE " << family.name() << " untyped\n";
 
-       for (auto& metric : family.metric()) {
 
-         SerializeUntyped(out, family, metric);
 
-       }
 
-       break;
 
-     case HISTOGRAM:
 
-       out << "# TYPE " << family.name() << " histogram\n";
 
-       for (auto& metric : family.metric()) {
 
-         SerializeHistogram(out, family, metric);
 
-       }
 
-       break;
 
-     default:
 
-       break;
 
-   }
 
- }
 
- }
 
- std::string TextSerializer::Serialize(
 
-     const std::vector<io::prometheus::client::MetricFamily>& metrics) {
 
-   std::ostringstream ss;
 
-   for (auto& family : metrics) {
 
-     SerializeFamily(ss, family);
 
-   }
 
-   return ss.str();
 
- }
 
- }
 
 
  |