| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 | #include "prometheus/text_serializer.h"#include <cmath>#include <iomanip>#include <limits>#include <locale>#include <ostream>namespace prometheus {namespace {// Write a double as a string, with proper formatting for infinity and NaNvoid WriteValue(std::ostream& out, double value) {  if (std::isnan(value)) {    out << "Nan";  } else if (std::isinf(value)) {    out << (value < 0 ? "-Inf" : "+Inf");  } else {    std::ios oldState{nullptr};    oldState.copyfmt(out);    out.setf(std::ios::fixed, std::ios::floatfield);    out << std::setprecision(std::numeric_limits<double>::max_digits10);    out << value;    out.copyfmt(oldState);  }}void WriteValue(std::ostream& out, const std::string& value) {  for (auto c : value) {    switch (c) {      case '\n':        out << '\\' << 'n';        break;      case '\\':        out << '\\' << c;        break;      case '"':        out << '\\' << c;        break;      default:        out << c;        break;    }  }}// Write a line header: metric name and labelstemplate <typename T = std::string>void WriteHead(std::ostream& out, const MetricFamily& family,               const ClientMetric& metric, const std::string& suffix = "",               const std::string& extraLabelName = "",               const T& extraLabelValue = T()) {  out << family.name << suffix;  if (!metric.label.empty() || !extraLabelName.empty()) {    out << "{";    const char* prefix = "";    for (auto& lp : metric.label) {      out << prefix << lp.name << "=\"";      WriteValue(out, lp.value);      out << "\"";      prefix = ",";    }    if (!extraLabelName.empty()) {      out << prefix << extraLabelName << "=\"";      WriteValue(out, extraLabelValue);      out << "\"";    }    out << "}";  }  out << " ";}// Write a line trailer: timestampvoid WriteTail(std::ostream& out, const ClientMetric& metric) {  if (metric.timestamp_ms != 0) {    out << " " << metric.timestamp_ms;  }  out << "\n";}void SerializeCounter(std::ostream& out, const MetricFamily& family,                      const ClientMetric& metric) {  WriteHead(out, family, metric);  WriteValue(out, metric.counter.value);  WriteTail(out, metric);}void SerializeGauge(std::ostream& out, const MetricFamily& family,                    const ClientMetric& metric) {  WriteHead(out, family, metric);  WriteValue(out, metric.gauge.value);  WriteTail(out, metric);}void SerializeSummary(std::ostream& out, const MetricFamily& family,                      const ClientMetric& metric) {  auto& sum = metric.summary;  WriteHead(out, family, metric, "_count");  out << sum.sample_count;  WriteTail(out, metric);  WriteHead(out, family, metric, "_sum");  WriteValue(out, sum.sample_sum);  WriteTail(out, metric);  for (auto& q : sum.quantile) {    WriteHead(out, family, metric, "", "quantile", q.quantile);    WriteValue(out, q.value);    WriteTail(out, metric);  }}void SerializeUntyped(std::ostream& out, const MetricFamily& family,                      const ClientMetric& metric) {  WriteHead(out, family, metric);  WriteValue(out, metric.untyped.value);  WriteTail(out, metric);}void SerializeHistogram(std::ostream& out, const MetricFamily& family,                        const ClientMetric& metric) {  auto& hist = metric.histogram;  WriteHead(out, family, metric, "_count");  out << hist.sample_count;  WriteTail(out, metric);  WriteHead(out, family, metric, "_sum");  WriteValue(out, hist.sample_sum);  WriteTail(out, metric);  double last = -std::numeric_limits<double>::infinity();  for (auto& b : hist.bucket) {    WriteHead(out, family, metric, "_bucket", "le", 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 MetricType::Counter:      out << "# TYPE " << family.name << " counter\n";      for (auto& metric : family.metric) {        SerializeCounter(out, family, metric);      }      break;    case MetricType::Gauge:      out << "# TYPE " << family.name << " gauge\n";      for (auto& metric : family.metric) {        SerializeGauge(out, family, metric);      }      break;    case MetricType::Summary:      out << "# TYPE " << family.name << " summary\n";      for (auto& metric : family.metric) {        SerializeSummary(out, family, metric);      }      break;    case MetricType::Untyped:      out << "# TYPE " << family.name << " untyped\n";      for (auto& metric : family.metric) {        SerializeUntyped(out, family, metric);      }      break;    case MetricType::Histogram:      out << "# TYPE " << family.name << " histogram\n";      for (auto& metric : family.metric) {        SerializeHistogram(out, family, metric);      }      break;  }}}  // namespacevoid TextSerializer::Serialize(std::ostream& out,                               const std::vector<MetricFamily>& metrics) const {  std::locale saved_locale = out.getloc();  out.imbue(std::locale::classic());  for (auto& family : metrics) {    SerializeFamily(out, family);  }  out.imbue(saved_locale);}}  // namespace prometheus
 |