• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jupp0r / prometheus-cpp / 7350751887

28 Dec 2023 07:46PM UTC coverage: 98.458%. Remained the same
7350751887

push

github

gjasny
feat: don't create temporary objects for serialization

Fix: #646

116 of 118 new or added lines in 6 files covered. (98.31%)

4 existing lines in 2 files now uncovered.

894 of 908 relevant lines covered (98.46%)

96521.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.01
/core/src/text_serializer.cc
1
#include "prometheus/text_serializer.h"
2

3
#include <cmath>
4
#include <limits>
5
#include <locale>
6
#include <ostream>
7
#include <sstream>
8
#include <string>
9

10
#include "prometheus/client_metric.h"
11
#include "prometheus/metric_family.h"
12
#include "prometheus/metric_type.h"
13

14
namespace prometheus {
15

16
namespace {
17

18
// Write a double as a string, with proper formatting for infinity and NaN
19
void WriteValue(std::ostream& out, double value) {
192✔
20
  if (std::isnan(value)) {
192✔
21
    out << "Nan";
50✔
22
  } else if (std::isinf(value)) {
142✔
23
    out << (value < 0 ? "-Inf" : "+Inf");
6✔
24
  } else {
25
    out << value;
136✔
26
  }
27
}
192✔
28

29
void WriteValue(std::ostream& out, const std::string& value) {
8✔
30
  for (auto c : value) {
34✔
31
    switch (c) {
26✔
32
      case '\n':
2✔
33
        out << '\\' << 'n';
2✔
34
        break;
2✔
35

36
      case '\\':
2✔
37
        out << '\\' << c;
2✔
38
        break;
2✔
39

40
      case '"':
2✔
41
        out << '\\' << c;
2✔
42
        break;
2✔
43

44
      default:
20✔
45
        out << c;
20✔
46
        break;
20✔
47
    }
48
  }
49
}
8✔
50

51
// Write a line header: metric name and labels
52
template <typename T = std::string>
53
void WriteHead(std::ostream& out, const MetricFamily& family,
110✔
54
               const ClientMetric& metric, const std::string& suffix = "",
55
               const std::string& extraLabelName = "",
56
               const T& extraLabelValue = T()) {
57
  out << family.name << suffix;
110✔
58
  if (!metric.label.empty() || !extraLabelName.empty()) {
110✔
59
    out << "{";
6✔
60
    const char* prefix = "";
6✔
61

62
    for (auto& lp : metric.label) {
12✔
63
      out << prefix << lp.name << "=\"";
6✔
64
      WriteValue(out, lp.value);
6✔
65
      out << "\"";
6✔
66
      prefix = ",";
6✔
67
    }
68
    if (!extraLabelName.empty()) {
6✔
UNCOV
69
      out << prefix << extraLabelName << "=\"";
×
70
      WriteValue(out, extraLabelValue);
×
71
      out << "\"";
×
72
    }
73
    out << "}";
6✔
74
  }
75
  out << " ";
110✔
76
}
110✔
77

78
// Write a line trailer: timestamp
79
void WriteTail(std::ostream& out, const ClientMetric& metric) {
166✔
80
  if (metric.timestamp_ms != 0) {
166✔
81
    out << " " << metric.timestamp_ms;
2✔
82
  }
83
  out << "\n";
166✔
84
}
166✔
85

86
void SerializeCounter(std::ostream& out, const MetricFamily& family,
50✔
87
                      const ClientMetric& metric) {
88
  WriteHead(out, family, metric);
50✔
89
  WriteValue(out, metric.counter.value);
50✔
90
  WriteTail(out, metric);
50✔
91
}
50✔
92

93
void SerializeGauge(std::ostream& out, const MetricFamily& family,
12✔
94
                    const ClientMetric& metric) {
95
  WriteHead(out, family, metric);
12✔
96
  WriteValue(out, metric.gauge.value);
12✔
97
  WriteTail(out, metric);
12✔
98
}
12✔
99

100
void SerializeInfo(std::ostream& out, const MetricFamily& family,
2✔
101
                   const ClientMetric& metric) {
102
  WriteHead(out, family, metric, "_info");
2✔
103
  WriteValue(out, metric.info.value);
2✔
104
  WriteTail(out, metric);
2✔
105
}
2✔
106

107
void SerializeSummary(std::ostream& out, const MetricFamily& family,
18✔
108
                      const ClientMetric& metric) {
109
  auto& sum = metric.summary;
18✔
110
  WriteHead(out, family, metric, "_count");
18✔
111
  out << sum.sample_count;
18✔
112
  WriteTail(out, metric);
18✔
113

114
  WriteHead(out, family, metric, "_sum");
18✔
115
  WriteValue(out, sum.sample_sum);
18✔
116
  WriteTail(out, metric);
18✔
117

118
  for (auto& q : sum.quantile) {
68✔
119
    WriteHead(out, family, metric, "", "quantile", q.quantile);
50✔
120
    WriteValue(out, q.value);
50✔
121
    WriteTail(out, metric);
50✔
122
  }
123
}
18✔
124

125
void SerializeUntyped(std::ostream& out, const MetricFamily& family,
2✔
126
                      const ClientMetric& metric) {
127
  WriteHead(out, family, metric);
2✔
128
  WriteValue(out, metric.untyped.value);
2✔
129
  WriteTail(out, metric);
2✔
130
}
2✔
131

132
void SerializeHistogram(std::ostream& out, const MetricFamily& family,
4✔
133
                        const ClientMetric& metric) {
134
  auto& hist = metric.histogram;
4✔
135
  WriteHead(out, family, metric, "_count");
4✔
136
  out << hist.sample_count;
4✔
137
  WriteTail(out, metric);
4✔
138

139
  WriteHead(out, family, metric, "_sum");
4✔
140
  WriteValue(out, hist.sample_sum);
4✔
141
  WriteTail(out, metric);
4✔
142

143
  double last = -std::numeric_limits<double>::infinity();
4✔
144
  for (auto& b : hist.bucket) {
8✔
145
    WriteHead(out, family, metric, "_bucket", "le", b.upper_bound);
4✔
146
    last = b.upper_bound;
4✔
147
    out << b.cumulative_count;
4✔
148
    WriteTail(out, metric);
4✔
149
  }
150

151
  if (last != std::numeric_limits<double>::infinity()) {
4✔
152
    WriteHead(out, family, metric, "_bucket", "le", "+Inf");
2✔
153
    out << hist.sample_count;
2✔
154
    WriteTail(out, metric);
2✔
155
  }
156
}
4✔
157
}  // namespace
158

159
TextSerializer::TextSerializer(IOVector& ioVector) : ioVector_(ioVector) {}
42✔
160

161
void TextSerializer::SerializeHelp(const MetricFamily& family) const {
88✔
162
  std::ostringstream out;
176✔
163

164
  if (!family.help.empty()) {
88✔
165
    out << "# HELP " << family.name << " " << family.help << "\n";
74✔
166
  }
167
  switch (family.type) {
88✔
168
    case MetricType::Counter:
50✔
169
      out << "# TYPE " << family.name << " counter\n";
50✔
170
      break;
50✔
171
    case MetricType::Gauge:
12✔
172
      out << "# TYPE " << family.name << " gauge\n";
12✔
173
      break;
12✔
174
    // info is not handled by prometheus, we use gauge as workaround
175
    // (https://github.com/OpenObservability/OpenMetrics/blob/98ae26c87b1c3bcf937909a880b32c8be643cc9b/specification/OpenMetrics.md#info-1)
176
    case MetricType::Info:
2✔
177
      out << "# TYPE " << family.name << " gauge\n";
2✔
178
      break;
2✔
179
    case MetricType::Summary:
18✔
180
      out << "# TYPE " << family.name << " summary\n";
18✔
181
      break;
18✔
182
    case MetricType::Untyped:
2✔
183
      out << "# TYPE " << family.name << " untyped\n";
2✔
184
      break;
2✔
185
    case MetricType::Histogram:
4✔
186
      out << "# TYPE " << family.name << " histogram\n";
4✔
187
      break;
4✔
188
  }
189

190
  Add(out);
88✔
191
}
88✔
192

193
void TextSerializer::SerializeMetrics(const MetricFamily& family,
88✔
194
                                      const ClientMetric& metric) const {
195
  std::ostringstream out;
176✔
196

197
  out.imbue(std::locale::classic());
88✔
198
  out.precision(std::numeric_limits<double>::max_digits10 - 1);
88✔
199

200
  switch (family.type) {
88✔
201
    case MetricType::Counter:
50✔
202
      SerializeCounter(out, family, metric);
50✔
203
      break;
50✔
204
    case MetricType::Gauge:
12✔
205
      SerializeGauge(out, family, metric);
12✔
206
      break;
12✔
207
    // info is not handled by prometheus, we use gauge as workaround
208
    // (https://github.com/OpenObservability/OpenMetrics/blob/98ae26c87b1c3bcf937909a880b32c8be643cc9b/specification/OpenMetrics.md#info-1)
209
    case MetricType::Info:
2✔
210
      SerializeInfo(out, family, metric);
2✔
211
      break;
2✔
212
    case MetricType::Summary:
18✔
213
      SerializeSummary(out, family, metric);
18✔
214
      break;
18✔
215
    case MetricType::Untyped:
2✔
216
      SerializeUntyped(out, family, metric);
2✔
217
      break;
2✔
218
    case MetricType::Histogram:
4✔
219
      SerializeHistogram(out, family, metric);
4✔
220
      break;
4✔
221
  }
222

223
  Add(out);
88✔
224
}
88✔
225

226
void TextSerializer::Add(const std::ostringstream& stream) const {
176✔
227
  ioVector_.add(stream.str(), chunkSize_);
176✔
228
}
176✔
229

230
}  // namespace prometheus
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc