Skip to content

Commit 715ac36

Browse files
authored
expfmt: format OpenMetrics 2.0 float values and validate units (#969)
- Use writeOpenMetricsFloat in writeOpenMetrics20Sample and writeExemplar20 so integral floats render with .0. - Validate in.Unit against newlines and carriage returns. - Update test cases to reflect float formatting and add unit newline error tests. Signed-off-by: David Ashpole <dashpole@google.com>
1 parent 87e7482 commit 715ac36

2 files changed

Lines changed: 38 additions & 11 deletions

File tree

expfmt/openmetrics_2_0_create.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ func MetricFamilyToOpenMetrics20(out io.Writer, in *dto.MetricFamily, options ..
4242
if containsRawNewline(name) {
4343
return 0, fmt.Errorf("MetricFamily name %q contains raw newlines", name)
4444
}
45+
if in.Unit != nil && containsRawNewline(*in.Unit) {
46+
return 0, fmt.Errorf("MetricFamily unit %q contains raw newlines", *in.Unit)
47+
}
4548

4649
// Try the interface upgrade. If it doesn't work, we'll use a
4750
// bufio.Writer from the sync.Pool.
@@ -222,7 +225,7 @@ func writeOpenMetrics20Sample(w enhancedWriter, name string, metric *dto.Metric,
222225
if useIntValue {
223226
n, err = writeUint(w, intValue)
224227
} else {
225-
n, err = writeFloat(w, floatValue)
228+
n, err = writeOpenMetricsFloat(w, floatValue)
226229
}
227230
written += n
228231
if err != nil {
@@ -305,7 +308,7 @@ func writeExemplar20(w enhancedWriter, e *dto.Exemplar) (int, error) {
305308
if err != nil {
306309
return written, err
307310
}
308-
n, err = writeFloat(w, e.GetValue())
311+
n, err = writeOpenMetricsFloat(w, e.GetValue())
309312
written += n
310313
if err != nil {
311314
return written, err

expfmt/openmetrics_2_0_create_test.go

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func TestCreateOpenMetrics20(t *testing.T) {
5252
},
5353
out: `# HELP http_requests_total Total number of HTTP requests.
5454
# TYPE http_requests_total counter
55-
http_requests_total{method="GET",code="200"} 1027 st@1234567890
55+
http_requests_total{method="GET",code="200"} 1027.0 st@1234567890
5656
`,
5757
},
5858
{
@@ -76,7 +76,7 @@ http_requests_total{method="GET",code="200"} 1027 st@1234567890
7676
},
7777
out: `# HELP http_requests_total Total number of HTTP requests.
7878
# TYPE http_requests_total counter
79-
http_requests_total{method="GET",code="200"} 1027 st@1234567890.987654321
79+
http_requests_total{method="GET",code="200"} 1027.0 st@1234567890.987654321
8080
`,
8181
},
8282
{
@@ -160,7 +160,7 @@ node_memory_active_bytes 1.2345e+09 1234567890
160160
},
161161
},
162162
out: `# TYPE http_requests_total counter
163-
http_requests_total 1027 1234567891 st@1234567890 # {trace_id="1234"} 1 1234567890.5
163+
http_requests_total 1027.0 1234567891 st@1234567890 # {trace_id="1234"} 1.0 1234567890.5
164164
`,
165165
},
166166
{
@@ -181,7 +181,7 @@ http_requests_total 1027 1234567891 st@1234567890 # {trace_id="1234"} 1 12345678
181181
},
182182
},
183183
out: `# TYPE http_requests_total counter
184-
http_requests_total 1027 # {} 1 1234567890.5
184+
http_requests_total 1027.0 # {} 1.0 1234567890.5
185185
`,
186186
},
187187
{
@@ -204,7 +204,7 @@ http_requests_total 1027 # {} 1 1234567890.5
204204
},
205205
},
206206
out: `# TYPE http_requests_total counter
207-
http_requests_total 1027
207+
http_requests_total 1027.0
208208
`,
209209
},
210210
{
@@ -228,7 +228,7 @@ http_requests_total 1027
228228
},
229229
},
230230
out: `# TYPE http_requests_total counter
231-
http_requests_total 1027 # {trace_id="1234"} NaN 1234567890
231+
http_requests_total 1027.0 # {trace_id="1234"} NaN 1234567890
232232
`,
233233
},
234234
{
@@ -262,7 +262,7 @@ test_metric 1.23
262262
},
263263
},
264264
out: `# TYPE http_requests_total counter
265-
http_requests_total 1027
265+
http_requests_total 1027.0
266266
`,
267267
},
268268
{
@@ -282,7 +282,7 @@ http_requests_total 1027
282282
},
283283
},
284284
out: `# TYPE "你好_total" counter
285-
{"你好_total","🌎"="🌍"} 1027
285+
{"你好_total","🌎"="🌍"} 1027.0
286286
`,
287287
},
288288
}
@@ -491,6 +491,30 @@ func TestCreateOpenMetrics20_Errors(t *testing.T) {
491491
},
492492
expectedErr: "contains raw newlines",
493493
},
494+
{
495+
name: "NewlineInUnit",
496+
in: &dto.MetricFamily{
497+
Name: proto.String("test_counter_total"),
498+
Type: dto.MetricType_COUNTER.Enum(),
499+
Unit: proto.String("seconds\n"),
500+
Metric: []*dto.Metric{
501+
{Counter: &dto.Counter{Value: proto.Float64(1.0)}},
502+
},
503+
},
504+
expectedErr: "contains raw newlines",
505+
},
506+
{
507+
name: "CarriageReturnInUnit",
508+
in: &dto.MetricFamily{
509+
Name: proto.String("test_counter_total"),
510+
Type: dto.MetricType_COUNTER.Enum(),
511+
Unit: proto.String("seconds\r"),
512+
Metric: []*dto.Metric{
513+
{Counter: &dto.Counter{Value: proto.Float64(1.0)}},
514+
},
515+
},
516+
expectedErr: "contains raw newlines",
517+
},
494518
{
495519
name: "NilMetric",
496520
in: &dto.MetricFamily{
@@ -614,7 +638,7 @@ func TestCreateOpenMetrics20_SimpleWriter(t *testing.T) {
614638
}
615639

616640
expected := `# TYPE http_requests_total counter
617-
http_requests_total 1027
641+
http_requests_total 1027.0
618642
`
619643
if buf.String() != expected {
620644
t.Errorf("expected %q, got %q", expected, buf.String())

0 commit comments

Comments
 (0)