| 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 NaNstd::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 labelsvoid 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: timestampvoid 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();}}
 |