master
go 1,998 lines 56.8 KB
Raw
1 package prometheus
2
3 import (
4 "bytes"
5 "fmt"
6 "math"
7 "os"
8 "testing"
9
10 "github.com/prometheus/common/model"
11 "github.com/prometheus/prometheus/model/labels"
12 "github.com/stretchr/testify/assert"
13 "github.com/stretchr/testify/require"
14
15 "github.com/netdata/netdata/go/plugins/pkg/prometheus/selector"
16 )
17
18 var (
19 dataMultilineHelp, _ = os.ReadFile("testdata/multiline-help.txt")
20
21 dataGaugeMeta, _ = os.ReadFile("testdata/gauge-meta.txt")
22 dataGaugeNoMeta, _ = os.ReadFile("testdata/gauge-no-meta.txt")
23 dataCounterMeta, _ = os.ReadFile("testdata/counter-meta.txt")
24 dataCounterNoMeta, _ = os.ReadFile("testdata/counter-no-meta.txt")
25 dataSummaryMeta, _ = os.ReadFile("testdata/summary-meta.txt")
26 dataSummaryNoMeta, _ = os.ReadFile("testdata/summary-no-meta.txt")
27 dataHistogramMeta, _ = os.ReadFile("testdata/histogram-meta.txt")
28 dataHistogramNoMeta, _ = os.ReadFile("testdata/histogram-no-meta.txt")
29 dataAllTypes = joinData(
30 dataGaugeMeta, dataGaugeNoMeta, dataCounterMeta, dataCounterNoMeta,
31 dataSummaryMeta, dataSummaryNoMeta, dataHistogramMeta, dataHistogramNoMeta,
32 )
33 )
34
35 func Test_testParseDataIsValid(t *testing.T) {
36 for name, data := range map[string][]byte{
37 "dataMultilineHelp": dataMultilineHelp,
38 "dataGaugeMeta": dataGaugeMeta,
39 "dataGaugeNoMeta": dataGaugeNoMeta,
40 "dataCounterMeta": dataCounterMeta,
41 "dataCounterNoMeta": dataCounterNoMeta,
42 "dataSummaryMeta": dataSummaryMeta,
43 "dataSummaryNoMeta": dataSummaryNoMeta,
44 "dataHistogramMeta": dataHistogramMeta,
45 "dataHistogramNoMeta": dataHistogramNoMeta,
46 "dataAllTypes": dataAllTypes,
47 } {
48 require.NotNilf(t, data, name)
49 }
50 }
51
52 func TestPromTextParser_parseToMetricFamilies(t *testing.T) {
53 tests := map[string]struct {
54 input []byte
55 want MetricFamilies
56 }{
57 "summary _sum/_count before # TYPE fold into one summary": {
58 input: []byte(`my_summary_sum{label1="value1"} 10
59 my_summary_count{label1="value1"} 2
60 # TYPE my_summary summary
61 my_summary{label1="value1",quantile="0.5"} 0.5
62 `),
63 want: MetricFamilies{
64 "my_summary": {
65 name: "my_summary",
66 typ: model.MetricTypeSummary,
67 metrics: []Metric{
68 {
69 labels: labels.Labels{{Name: "label1", Value: "value1"}},
70 summary: &Summary{
71 sum: 10,
72 count: 2,
73 quantiles: []Quantile{{quantile: 0.5, value: 0.5}},
74 },
75 },
76 },
77 },
78 },
79 },
80 "histogram _sum/_count before _bucket (no # TYPE) fold into one histogram": {
81 input: []byte(`my_hist_sum{label1="value1"} 5
82 my_hist_count{label1="value1"} 3
83 my_hist_bucket{label1="value1",le="0.1"} 1
84 my_hist_bucket{label1="value1",le="+Inf"} 3
85 `),
86 want: MetricFamilies{
87 "my_hist": {
88 name: "my_hist",
89 typ: model.MetricTypeHistogram,
90 metrics: []Metric{
91 {
92 labels: labels.Labels{{Name: "label1", Value: "value1"}},
93 histogram: &Histogram{
94 sum: 5,
95 count: 3,
96 buckets: []Bucket{
97 {upperBound: 0.1, cumulativeCount: 1},
98 {upperBound: math.Inf(1), cumulativeCount: 3},
99 },
100 },
101 },
102 },
103 },
104 },
105 },
106 "metric name found by lookup, not first label": {
107 input: []byte(`
108 # HELP DCGM_FI_DEV_GPU_UTIL GPU utilization
109 # TYPE DCGM_FI_DEV_GPU_UTIL gauge
110 DCGM_FI_DEV_GPU_UTIL{UUID="GPU-aaa",gpu="0"} 80
111 `),
112 want: MetricFamilies{
113 "DCGM_FI_DEV_GPU_UTIL": {
114 name: "DCGM_FI_DEV_GPU_UTIL",
115 help: "GPU utilization",
116 typ: model.MetricTypeGauge,
117 metrics: []Metric{
118 {
119 labels: labels.Labels{{Name: "UUID", Value: "GPU-aaa"}, {Name: "gpu", Value: "0"}},
120 gauge: &Gauge{value: 80},
121 },
122 },
123 },
124 },
125 },
126 "valid _bucket (has le) folds into the histogram family": {
127 input: []byte("# TYPE h histogram\nh_bucket{le=\"1\",label=\"x\"} 1\n"),
128 want: MetricFamilies{
129 "h": {
130 name: "h",
131 typ: model.MetricTypeHistogram,
132 metrics: []Metric{
133 {
134 labels: labels.Labels{{Name: "label", Value: "x"}},
135 histogram: &Histogram{buckets: []Bucket{{upperBound: 1, cumulativeCount: 1}}},
136 },
137 },
138 },
139 },
140 },
141 "_bucket without le is a plain metric, not a histogram bucket": {
142 input: []byte("# TYPE h histogram\nh_bucket{label=\"x\"} 1\n"),
143 want: MetricFamilies{
144 "h_bucket": {
145 name: "h_bucket",
146 typ: model.MetricTypeUnknown,
147 metrics: []Metric{
148 {
149 labels: labels.Labels{{Name: "label", Value: "x"}},
150 untyped: &Untyped{value: 1},
151 },
152 },
153 },
154 },
155 },
156 "Gauge with multiline HELP": {
157 input: dataMultilineHelp,
158 want: MetricFamilies{
159 "test_gauge_metric_1": {
160 name: "test_gauge_metric_1",
161 help: "First line. Second line.",
162 typ: model.MetricTypeGauge,
163 metrics: []Metric{
164 {
165 labels: labels.Labels{{Name: "label1", Value: "value1"}},
166 gauge: &Gauge{value: 11},
167 },
168 },
169 },
170 },
171 },
172 "Gauge with meta parsed as Gauge": {
173 input: dataGaugeMeta,
174 want: MetricFamilies{
175 "test_gauge_metric_1": {
176 name: "test_gauge_metric_1",
177 help: "Test Gauge Metric 1",
178 typ: model.MetricTypeGauge,
179 metrics: []Metric{
180 {
181 labels: labels.Labels{{Name: "label1", Value: "value1"}},
182 gauge: &Gauge{value: 11},
183 },
184 {
185 labels: labels.Labels{{Name: "label1", Value: "value2"}},
186 gauge: &Gauge{value: 12},
187 },
188 {
189 labels: labels.Labels{{Name: "label1", Value: "value3"}},
190 gauge: &Gauge{value: 13},
191 },
192 {
193 labels: labels.Labels{{Name: "label1", Value: "value4"}},
194 gauge: &Gauge{value: 14},
195 },
196 },
197 },
198 "test_gauge_metric_2": {
199 name: "test_gauge_metric_2",
200 typ: model.MetricTypeGauge,
201 metrics: []Metric{
202 {
203 labels: labels.Labels{{Name: "label1", Value: "value1"}},
204 gauge: &Gauge{value: 11},
205 },
206 {
207 labels: labels.Labels{{Name: "label1", Value: "value2"}},
208 gauge: &Gauge{value: 12},
209 },
210 {
211 labels: labels.Labels{{Name: "label1", Value: "value3"}},
212 gauge: &Gauge{value: 13},
213 },
214 {
215 labels: labels.Labels{{Name: "label1", Value: "value4"}},
216 gauge: &Gauge{value: 14},
217 },
218 },
219 },
220 },
221 },
222 "Counter with meta parsed as Counter": {
223 input: dataCounterMeta,
224 want: MetricFamilies{
225 "test_counter_metric_1_total": {
226 name: "test_counter_metric_1_total",
227 help: "Test Counter Metric 1",
228 typ: model.MetricTypeCounter,
229 metrics: []Metric{
230 {
231 labels: labels.Labels{{Name: "label1", Value: "value1"}},
232 counter: &Counter{value: 11},
233 },
234 {
235 labels: labels.Labels{{Name: "label1", Value: "value2"}},
236 counter: &Counter{value: 12},
237 },
238 {
239 labels: labels.Labels{{Name: "label1", Value: "value3"}},
240 counter: &Counter{value: 13},
241 },
242 {
243 labels: labels.Labels{{Name: "label1", Value: "value4"}},
244 counter: &Counter{value: 14},
245 },
246 },
247 },
248 "test_counter_metric_2_total": {
249 name: "test_counter_metric_2_total",
250 typ: model.MetricTypeCounter,
251 metrics: []Metric{
252 {
253 labels: labels.Labels{{Name: "label1", Value: "value1"}},
254 counter: &Counter{value: 11},
255 },
256 {
257 labels: labels.Labels{{Name: "label1", Value: "value2"}},
258 counter: &Counter{value: 12},
259 },
260 {
261 labels: labels.Labels{{Name: "label1", Value: "value3"}},
262 counter: &Counter{value: 13},
263 },
264 {
265 labels: labels.Labels{{Name: "label1", Value: "value4"}},
266 counter: &Counter{value: 14},
267 },
268 },
269 },
270 },
271 },
272 "Summary with meta parsed as Summary": {
273 input: dataSummaryMeta,
274 want: MetricFamilies{
275 "test_summary_1_duration_microseconds": {
276 name: "test_summary_1_duration_microseconds",
277 help: "Test Summary Metric 1",
278 typ: model.MetricTypeSummary,
279 metrics: []Metric{
280 {
281 labels: labels.Labels{{Name: "label1", Value: "value1"}},
282 summary: &Summary{
283 sum: 283201.29,
284 count: 31,
285 quantiles: []Quantile{
286 {quantile: 0.5, value: 4931.921},
287 {quantile: 0.9, value: 4932.921},
288 {quantile: 0.99, value: 4933.921},
289 },
290 },
291 },
292 {
293 labels: labels.Labels{{Name: "label1", Value: "value2"}},
294 summary: &Summary{
295 sum: 283201.29,
296 count: 31,
297 quantiles: []Quantile{
298 {quantile: 0.5, value: 4931.921},
299 {quantile: 0.9, value: 4932.921},
300 {quantile: 0.99, value: 4933.921},
301 },
302 },
303 },
304 {
305 labels: labels.Labels{{Name: "label1", Value: "value3"}},
306 summary: &Summary{
307 sum: 283201.29,
308 count: 31,
309 quantiles: []Quantile{
310 {quantile: 0.5, value: 4931.921},
311 {quantile: 0.9, value: 4932.921},
312 {quantile: 0.99, value: 4933.921},
313 },
314 },
315 },
316 {
317 labels: labels.Labels{{Name: "label1", Value: "value4"}},
318 summary: &Summary{
319 sum: 283201.29,
320 count: 31,
321 quantiles: []Quantile{
322 {quantile: 0.5, value: 4931.921},
323 {quantile: 0.9, value: 4932.921},
324 {quantile: 0.99, value: 4933.921},
325 },
326 },
327 },
328 },
329 },
330 "test_summary_2_duration_microseconds": {
331 name: "test_summary_2_duration_microseconds",
332 typ: model.MetricTypeSummary,
333 metrics: []Metric{
334 {
335 labels: labels.Labels{{Name: "label1", Value: "value1"}},
336 summary: &Summary{
337 sum: 383201.29,
338 count: 41,
339 quantiles: []Quantile{
340 {quantile: 0.5, value: 5931.921},
341 {quantile: 0.9, value: 5932.921},
342 {quantile: 0.99, value: 5933.921},
343 },
344 },
345 },
346 {
347 labels: labels.Labels{{Name: "label1", Value: "value2"}},
348 summary: &Summary{
349 sum: 383201.29,
350 count: 41,
351 quantiles: []Quantile{
352 {quantile: 0.5, value: 5931.921},
353 {quantile: 0.9, value: 5932.921},
354 {quantile: 0.99, value: 5933.921},
355 },
356 },
357 },
358 {
359 labels: labels.Labels{{Name: "label1", Value: "value3"}},
360 summary: &Summary{
361 sum: 383201.29,
362 count: 41,
363 quantiles: []Quantile{
364 {quantile: 0.5, value: 5931.921},
365 {quantile: 0.9, value: 5932.921},
366 {quantile: 0.99, value: 5933.921},
367 },
368 },
369 },
370 {
371 labels: labels.Labels{{Name: "label1", Value: "value4"}},
372 summary: &Summary{
373 sum: 383201.29,
374 count: 41,
375 quantiles: []Quantile{
376 {quantile: 0.5, value: 5931.921},
377 {quantile: 0.9, value: 5932.921},
378 {quantile: 0.99, value: 5933.921},
379 },
380 },
381 },
382 },
383 },
384 },
385 },
386 "Histogram with meta parsed as Histogram": {
387 input: dataHistogramMeta,
388 want: MetricFamilies{
389 "test_histogram_1_duration_seconds": {
390 name: "test_histogram_1_duration_seconds",
391 help: "Test Histogram Metric 1",
392 typ: model.MetricTypeHistogram,
393 metrics: []Metric{
394 {
395 labels: labels.Labels{{Name: "label1", Value: "value1"}},
396 histogram: &Histogram{
397 sum: 0.00147889,
398 count: 6,
399 buckets: []Bucket{
400 {upperBound: 0.1, cumulativeCount: 4},
401 {upperBound: 0.5, cumulativeCount: 5},
402 {upperBound: math.Inf(1), cumulativeCount: 6},
403 },
404 },
405 },
406 {
407 labels: labels.Labels{{Name: "label1", Value: "value2"}},
408 histogram: &Histogram{
409 sum: 0.00147889,
410 count: 6,
411 buckets: []Bucket{
412 {upperBound: 0.1, cumulativeCount: 4},
413 {upperBound: 0.5, cumulativeCount: 5},
414 {upperBound: math.Inf(1), cumulativeCount: 6},
415 },
416 },
417 },
418 {
419 labels: labels.Labels{{Name: "label1", Value: "value3"}},
420 histogram: &Histogram{
421 sum: 0.00147889,
422 count: 6,
423 buckets: []Bucket{
424 {upperBound: 0.1, cumulativeCount: 4},
425 {upperBound: 0.5, cumulativeCount: 5},
426 {upperBound: math.Inf(1), cumulativeCount: 6},
427 },
428 },
429 },
430 {
431 labels: labels.Labels{{Name: "label1", Value: "value4"}},
432 histogram: &Histogram{
433 sum: 0.00147889,
434 count: 6,
435 buckets: []Bucket{
436 {upperBound: 0.1, cumulativeCount: 4},
437 {upperBound: 0.5, cumulativeCount: 5},
438 {upperBound: math.Inf(1), cumulativeCount: 6},
439 },
440 },
441 },
442 },
443 },
444 "test_histogram_2_duration_seconds": {
445 name: "test_histogram_2_duration_seconds",
446 typ: model.MetricTypeHistogram,
447 metrics: []Metric{
448 {
449 labels: labels.Labels{{Name: "label1", Value: "value1"}},
450 histogram: &Histogram{
451 sum: 0.00247889,
452 count: 9,
453 buckets: []Bucket{
454 {upperBound: 0.1, cumulativeCount: 7},
455 {upperBound: 0.5, cumulativeCount: 8},
456 {upperBound: math.Inf(1), cumulativeCount: 9},
457 },
458 },
459 },
460 {
461 labels: labels.Labels{{Name: "label1", Value: "value2"}},
462 histogram: &Histogram{
463 sum: 0.00247889,
464 count: 9,
465 buckets: []Bucket{
466 {upperBound: 0.1, cumulativeCount: 7},
467 {upperBound: 0.5, cumulativeCount: 8},
468 {upperBound: math.Inf(1), cumulativeCount: 9},
469 },
470 },
471 },
472 {
473 labels: labels.Labels{{Name: "label1", Value: "value3"}},
474 histogram: &Histogram{
475 sum: 0.00247889,
476 count: 9,
477 buckets: []Bucket{
478 {upperBound: 0.1, cumulativeCount: 7},
479 {upperBound: 0.5, cumulativeCount: 8},
480 {upperBound: math.Inf(1), cumulativeCount: 9},
481 },
482 },
483 },
484 {
485 labels: labels.Labels{{Name: "label1", Value: "value4"}},
486 histogram: &Histogram{
487 sum: 0.00247889,
488 count: 9,
489 buckets: []Bucket{
490 {upperBound: 0.1, cumulativeCount: 7},
491 {upperBound: 0.5, cumulativeCount: 8},
492 {upperBound: math.Inf(1), cumulativeCount: 9},
493 },
494 },
495 },
496 },
497 },
498 },
499 },
500 "Gauge no meta parsed as Untyped": {
501 input: dataGaugeNoMeta,
502 want: MetricFamilies{
503 "test_gauge_no_meta_metric_1": {
504 name: "test_gauge_no_meta_metric_1",
505 typ: model.MetricTypeUnknown,
506 metrics: []Metric{
507 {
508 labels: labels.Labels{{Name: "label1", Value: "value1"}},
509 untyped: &Untyped{value: 11},
510 },
511 {
512 labels: labels.Labels{{Name: "label1", Value: "value2"}},
513 untyped: &Untyped{value: 12},
514 },
515 {
516 labels: labels.Labels{{Name: "label1", Value: "value3"}},
517 untyped: &Untyped{value: 13},
518 },
519 {
520 labels: labels.Labels{{Name: "label1", Value: "value4"}},
521 untyped: &Untyped{value: 14},
522 },
523 },
524 },
525 "test_gauge_no_meta_metric_2": {
526 name: "test_gauge_no_meta_metric_2",
527 typ: model.MetricTypeUnknown,
528 metrics: []Metric{
529 {
530 labels: labels.Labels{{Name: "label1", Value: "value1"}},
531 untyped: &Untyped{value: 11},
532 },
533 {
534 labels: labels.Labels{{Name: "label1", Value: "value2"}},
535 untyped: &Untyped{value: 12},
536 },
537 {
538 labels: labels.Labels{{Name: "label1", Value: "value3"}},
539 untyped: &Untyped{value: 13},
540 },
541 {
542 labels: labels.Labels{{Name: "label1", Value: "value4"}},
543 untyped: &Untyped{value: 14},
544 },
545 },
546 },
547 },
548 },
549 "Counter no meta parsed as Untyped": {
550 input: dataCounterNoMeta,
551 want: MetricFamilies{
552 "test_counter_no_meta_metric_1_total": {
553 name: "test_counter_no_meta_metric_1_total",
554 typ: model.MetricTypeUnknown,
555 metrics: []Metric{
556 {
557 labels: labels.Labels{{Name: "label1", Value: "value1"}},
558 untyped: &Untyped{value: 11},
559 },
560 {
561 labels: labels.Labels{{Name: "label1", Value: "value2"}},
562 untyped: &Untyped{value: 12},
563 },
564 {
565 labels: labels.Labels{{Name: "label1", Value: "value3"}},
566 untyped: &Untyped{value: 13},
567 },
568 {
569 labels: labels.Labels{{Name: "label1", Value: "value4"}},
570 untyped: &Untyped{value: 14},
571 },
572 },
573 },
574 "test_counter_no_meta_metric_2_total": {
575 name: "test_counter_no_meta_metric_2_total",
576 typ: model.MetricTypeUnknown,
577 metrics: []Metric{
578 {
579 labels: labels.Labels{{Name: "label1", Value: "value1"}},
580 untyped: &Untyped{value: 11},
581 },
582 {
583 labels: labels.Labels{{Name: "label1", Value: "value2"}},
584 untyped: &Untyped{value: 12},
585 },
586 {
587 labels: labels.Labels{{Name: "label1", Value: "value3"}},
588 untyped: &Untyped{value: 13},
589 },
590 {
591 labels: labels.Labels{{Name: "label1", Value: "value4"}},
592 untyped: &Untyped{value: 14},
593 },
594 },
595 },
596 },
597 },
598 "Summary no meta parsed as Summary": {
599 input: dataSummaryNoMeta,
600 want: MetricFamilies{
601 "test_summary_no_meta_1_duration_microseconds": {
602 name: "test_summary_no_meta_1_duration_microseconds",
603 typ: model.MetricTypeSummary,
604 metrics: []Metric{
605 {
606 labels: labels.Labels{{Name: "label1", Value: "value1"}},
607 summary: &Summary{
608 sum: 283201.29,
609 count: 31,
610 quantiles: []Quantile{
611 {quantile: 0.5, value: 4931.921},
612 {quantile: 0.9, value: 4932.921},
613 {quantile: 0.99, value: 4933.921},
614 },
615 },
616 },
617 {
618 labels: labels.Labels{{Name: "label1", Value: "value2"}},
619 summary: &Summary{
620 sum: 283201.29,
621 count: 31,
622 quantiles: []Quantile{
623 {quantile: 0.5, value: 4931.921},
624 {quantile: 0.9, value: 4932.921},
625 {quantile: 0.99, value: 4933.921},
626 },
627 },
628 },
629 {
630 labels: labels.Labels{{Name: "label1", Value: "value3"}},
631 summary: &Summary{
632 sum: 283201.29,
633 count: 31,
634 quantiles: []Quantile{
635 {quantile: 0.5, value: 4931.921},
636 {quantile: 0.9, value: 4932.921},
637 {quantile: 0.99, value: 4933.921},
638 },
639 },
640 },
641 {
642 labels: labels.Labels{{Name: "label1", Value: "value4"}},
643 summary: &Summary{
644 sum: 283201.29,
645 count: 31,
646 quantiles: []Quantile{
647 {quantile: 0.5, value: 4931.921},
648 {quantile: 0.9, value: 4932.921},
649 {quantile: 0.99, value: 4933.921},
650 },
651 },
652 },
653 },
654 },
655 "test_summary_no_meta_2_duration_microseconds": {
656 name: "test_summary_no_meta_2_duration_microseconds",
657 typ: model.MetricTypeSummary,
658 metrics: []Metric{
659 {
660 labels: labels.Labels{{Name: "label1", Value: "value1"}},
661 summary: &Summary{
662 sum: 383201.29,
663 count: 41,
664 quantiles: []Quantile{
665 {quantile: 0.5, value: 5931.921},
666 {quantile: 0.9, value: 5932.921},
667 {quantile: 0.99, value: 5933.921},
668 },
669 },
670 },
671 {
672 labels: labels.Labels{{Name: "label1", Value: "value2"}},
673 summary: &Summary{
674 sum: 383201.29,
675 count: 41,
676 quantiles: []Quantile{
677 {quantile: 0.5, value: 5931.921},
678 {quantile: 0.9, value: 5932.921},
679 {quantile: 0.99, value: 5933.921},
680 },
681 },
682 },
683 {
684 labels: labels.Labels{{Name: "label1", Value: "value3"}},
685 summary: &Summary{
686 sum: 383201.29,
687 count: 41,
688 quantiles: []Quantile{
689 {quantile: 0.5, value: 5931.921},
690 {quantile: 0.9, value: 5932.921},
691 {quantile: 0.99, value: 5933.921},
692 },
693 },
694 },
695 {
696 labels: labels.Labels{{Name: "label1", Value: "value4"}},
697 summary: &Summary{
698 sum: 383201.29,
699 count: 41,
700 quantiles: []Quantile{
701 {quantile: 0.5, value: 5931.921},
702 {quantile: 0.9, value: 5932.921},
703 {quantile: 0.99, value: 5933.921},
704 },
705 },
706 },
707 },
708 },
709 },
710 },
711 "Histogram no meta parsed as Histogram": {
712 input: dataHistogramNoMeta,
713 want: MetricFamilies{
714 "test_histogram_no_meta_1_duration_seconds": {
715 name: "test_histogram_no_meta_1_duration_seconds",
716 typ: model.MetricTypeHistogram,
717 metrics: []Metric{
718 {
719 labels: labels.Labels{{Name: "label1", Value: "value1"}},
720 histogram: &Histogram{
721 sum: 0.00147889,
722 count: 6,
723 buckets: []Bucket{
724 {upperBound: 0.1, cumulativeCount: 4},
725 {upperBound: 0.5, cumulativeCount: 5},
726 {upperBound: math.Inf(1), cumulativeCount: 6},
727 },
728 },
729 },
730 {
731 labels: labels.Labels{{Name: "label1", Value: "value2"}},
732 histogram: &Histogram{
733 sum: 0.00147889,
734 count: 6,
735 buckets: []Bucket{
736 {upperBound: 0.1, cumulativeCount: 4},
737 {upperBound: 0.5, cumulativeCount: 5},
738 {upperBound: math.Inf(1), cumulativeCount: 6},
739 },
740 },
741 },
742 {
743 labels: labels.Labels{{Name: "label1", Value: "value3"}},
744 histogram: &Histogram{
745 sum: 0.00147889,
746 count: 6,
747 buckets: []Bucket{
748 {upperBound: 0.1, cumulativeCount: 4},
749 {upperBound: 0.5, cumulativeCount: 5},
750 {upperBound: math.Inf(1), cumulativeCount: 6},
751 },
752 },
753 },
754 {
755 labels: labels.Labels{{Name: "label1", Value: "value4"}},
756 histogram: &Histogram{
757 sum: 0.00147889,
758 count: 6,
759 buckets: []Bucket{
760 {upperBound: 0.1, cumulativeCount: 4},
761 {upperBound: 0.5, cumulativeCount: 5},
762 {upperBound: math.Inf(1), cumulativeCount: 6},
763 },
764 },
765 },
766 },
767 },
768 "test_histogram_no_meta_2_duration_seconds": {
769 name: "test_histogram_no_meta_2_duration_seconds",
770 typ: model.MetricTypeHistogram,
771 metrics: []Metric{
772 {
773 labels: labels.Labels{{Name: "label1", Value: "value1"}},
774 histogram: &Histogram{
775 sum: 0.00247889,
776 count: 9,
777 buckets: []Bucket{
778 {upperBound: 0.1, cumulativeCount: 7},
779 {upperBound: 0.5, cumulativeCount: 8},
780 {upperBound: math.Inf(1), cumulativeCount: 9},
781 },
782 },
783 },
784 {
785 labels: labels.Labels{{Name: "label1", Value: "value2"}},
786 histogram: &Histogram{
787 sum: 0.00247889,
788 count: 9,
789 buckets: []Bucket{
790 {upperBound: 0.1, cumulativeCount: 7},
791 {upperBound: 0.5, cumulativeCount: 8},
792 {upperBound: math.Inf(1), cumulativeCount: 9},
793 },
794 },
795 },
796 {
797 labels: labels.Labels{{Name: "label1", Value: "value3"}},
798 histogram: &Histogram{
799 sum: 0.00247889,
800 count: 9,
801 buckets: []Bucket{
802 {upperBound: 0.1, cumulativeCount: 7},
803 {upperBound: 0.5, cumulativeCount: 8},
804 {upperBound: math.Inf(1), cumulativeCount: 9},
805 },
806 },
807 },
808 {
809 labels: labels.Labels{{Name: "label1", Value: "value4"}},
810 histogram: &Histogram{
811 sum: 0.00247889,
812 count: 9,
813 buckets: []Bucket{
814 {upperBound: 0.1, cumulativeCount: 7},
815 {upperBound: 0.5, cumulativeCount: 8},
816 {upperBound: math.Inf(1), cumulativeCount: 9},
817 },
818 },
819 },
820 },
821 },
822 },
823 },
824 "All types": {
825 input: dataAllTypes,
826 want: MetricFamilies{
827 "test_gauge_metric_1": {
828 name: "test_gauge_metric_1",
829 help: "Test Gauge Metric 1",
830 typ: model.MetricTypeGauge,
831 metrics: []Metric{
832 {
833 labels: labels.Labels{{Name: "label1", Value: "value1"}},
834 gauge: &Gauge{value: 11},
835 },
836 {
837 labels: labels.Labels{{Name: "label1", Value: "value2"}},
838 gauge: &Gauge{value: 12},
839 },
840 {
841 labels: labels.Labels{{Name: "label1", Value: "value3"}},
842 gauge: &Gauge{value: 13},
843 },
844 {
845 labels: labels.Labels{{Name: "label1", Value: "value4"}},
846 gauge: &Gauge{value: 14},
847 },
848 },
849 },
850 "test_gauge_metric_2": {
851 name: "test_gauge_metric_2",
852 typ: model.MetricTypeGauge,
853 metrics: []Metric{
854 {
855 labels: labels.Labels{{Name: "label1", Value: "value1"}},
856 gauge: &Gauge{value: 11},
857 },
858 {
859 labels: labels.Labels{{Name: "label1", Value: "value2"}},
860 gauge: &Gauge{value: 12},
861 },
862 {
863 labels: labels.Labels{{Name: "label1", Value: "value3"}},
864 gauge: &Gauge{value: 13},
865 },
866 {
867 labels: labels.Labels{{Name: "label1", Value: "value4"}},
868 gauge: &Gauge{value: 14},
869 },
870 },
871 },
872 "test_counter_metric_1_total": {
873 name: "test_counter_metric_1_total",
874 help: "Test Counter Metric 1",
875 typ: model.MetricTypeCounter,
876 metrics: []Metric{
877 {
878 labels: labels.Labels{{Name: "label1", Value: "value1"}},
879 counter: &Counter{value: 11},
880 },
881 {
882 labels: labels.Labels{{Name: "label1", Value: "value2"}},
883 counter: &Counter{value: 12},
884 },
885 {
886 labels: labels.Labels{{Name: "label1", Value: "value3"}},
887 counter: &Counter{value: 13},
888 },
889 {
890 labels: labels.Labels{{Name: "label1", Value: "value4"}},
891 counter: &Counter{value: 14},
892 },
893 },
894 },
895 "test_counter_metric_2_total": {
896 name: "test_counter_metric_2_total",
897 typ: model.MetricTypeCounter,
898 metrics: []Metric{
899 {
900 labels: labels.Labels{{Name: "label1", Value: "value1"}},
901 counter: &Counter{value: 11},
902 },
903 {
904 labels: labels.Labels{{Name: "label1", Value: "value2"}},
905 counter: &Counter{value: 12},
906 },
907 {
908 labels: labels.Labels{{Name: "label1", Value: "value3"}},
909 counter: &Counter{value: 13},
910 },
911 {
912 labels: labels.Labels{{Name: "label1", Value: "value4"}},
913 counter: &Counter{value: 14},
914 },
915 },
916 },
917 "test_summary_1_duration_microseconds": {
918 name: "test_summary_1_duration_microseconds",
919 help: "Test Summary Metric 1",
920 typ: model.MetricTypeSummary,
921 metrics: []Metric{
922 {
923 labels: labels.Labels{{Name: "label1", Value: "value1"}},
924 summary: &Summary{
925 sum: 283201.29,
926 count: 31,
927 quantiles: []Quantile{
928 {quantile: 0.5, value: 4931.921},
929 {quantile: 0.9, value: 4932.921},
930 {quantile: 0.99, value: 4933.921},
931 },
932 },
933 },
934 {
935 labels: labels.Labels{{Name: "label1", Value: "value2"}},
936 summary: &Summary{
937 sum: 283201.29,
938 count: 31,
939 quantiles: []Quantile{
940 {quantile: 0.5, value: 4931.921},
941 {quantile: 0.9, value: 4932.921},
942 {quantile: 0.99, value: 4933.921},
943 },
944 },
945 },
946 {
947 labels: labels.Labels{{Name: "label1", Value: "value3"}},
948 summary: &Summary{
949 sum: 283201.29,
950 count: 31,
951 quantiles: []Quantile{
952 {quantile: 0.5, value: 4931.921},
953 {quantile: 0.9, value: 4932.921},
954 {quantile: 0.99, value: 4933.921},
955 },
956 },
957 },
958 {
959 labels: labels.Labels{{Name: "label1", Value: "value4"}},
960 summary: &Summary{
961 sum: 283201.29,
962 count: 31,
963 quantiles: []Quantile{
964 {quantile: 0.5, value: 4931.921},
965 {quantile: 0.9, value: 4932.921},
966 {quantile: 0.99, value: 4933.921},
967 },
968 },
969 },
970 },
971 },
972 "test_summary_2_duration_microseconds": {
973 name: "test_summary_2_duration_microseconds",
974 typ: model.MetricTypeSummary,
975 metrics: []Metric{
976 {
977 labels: labels.Labels{{Name: "label1", Value: "value1"}},
978 summary: &Summary{
979 sum: 383201.29,
980 count: 41,
981 quantiles: []Quantile{
982 {quantile: 0.5, value: 5931.921},
983 {quantile: 0.9, value: 5932.921},
984 {quantile: 0.99, value: 5933.921},
985 },
986 },
987 },
988 {
989 labels: labels.Labels{{Name: "label1", Value: "value2"}},
990 summary: &Summary{
991 sum: 383201.29,
992 count: 41,
993 quantiles: []Quantile{
994 {quantile: 0.5, value: 5931.921},
995 {quantile: 0.9, value: 5932.921},
996 {quantile: 0.99, value: 5933.921},
997 },
998 },
999 },
1000 {
1001 labels: labels.Labels{{Name: "label1", Value: "value3"}},
1002 summary: &Summary{
1003 sum: 383201.29,
1004 count: 41,
1005 quantiles: []Quantile{
1006 {quantile: 0.5, value: 5931.921},
1007 {quantile: 0.9, value: 5932.921},
1008 {quantile: 0.99, value: 5933.921},
1009 },
1010 },
1011 },
1012 {
1013 labels: labels.Labels{{Name: "label1", Value: "value4"}},
1014 summary: &Summary{
1015 sum: 383201.29,
1016 count: 41,
1017 quantiles: []Quantile{
1018 {quantile: 0.5, value: 5931.921},
1019 {quantile: 0.9, value: 5932.921},
1020 {quantile: 0.99, value: 5933.921},
1021 },
1022 },
1023 },
1024 },
1025 },
1026 "test_histogram_1_duration_seconds": {
1027 name: "test_histogram_1_duration_seconds",
1028 help: "Test Histogram Metric 1",
1029 typ: model.MetricTypeHistogram,
1030 metrics: []Metric{
1031 {
1032 labels: labels.Labels{{Name: "label1", Value: "value1"}},
1033 histogram: &Histogram{
1034 sum: 0.00147889,
1035 count: 6,
1036 buckets: []Bucket{
1037 {upperBound: 0.1, cumulativeCount: 4},
1038 {upperBound: 0.5, cumulativeCount: 5},
1039 {upperBound: math.Inf(1), cumulativeCount: 6},
1040 },
1041 },
1042 },
1043 {
1044 labels: labels.Labels{{Name: "label1", Value: "value2"}},
1045 histogram: &Histogram{
1046 sum: 0.00147889,
1047 count: 6,
1048 buckets: []Bucket{
1049 {upperBound: 0.1, cumulativeCount: 4},
1050 {upperBound: 0.5, cumulativeCount: 5},
1051 {upperBound: math.Inf(1), cumulativeCount: 6},
1052 },
1053 },
1054 },
1055 {
1056 labels: labels.Labels{{Name: "label1", Value: "value3"}},
1057 histogram: &Histogram{
1058 sum: 0.00147889,
1059 count: 6,
1060 buckets: []Bucket{
1061 {upperBound: 0.1, cumulativeCount: 4},
1062 {upperBound: 0.5, cumulativeCount: 5},
1063 {upperBound: math.Inf(1), cumulativeCount: 6},
1064 },
1065 },
1066 },
1067 {
1068 labels: labels.Labels{{Name: "label1", Value: "value4"}},
1069 histogram: &Histogram{
1070 sum: 0.00147889,
1071 count: 6,
1072 buckets: []Bucket{
1073 {upperBound: 0.1, cumulativeCount: 4},
1074 {upperBound: 0.5, cumulativeCount: 5},
1075 {upperBound: math.Inf(1), cumulativeCount: 6},
1076 },
1077 },
1078 },
1079 },
1080 },
1081 "test_histogram_2_duration_seconds": {
1082 name: "test_histogram_2_duration_seconds",
1083 typ: model.MetricTypeHistogram,
1084 metrics: []Metric{
1085 {
1086 labels: labels.Labels{{Name: "label1", Value: "value1"}},
1087 histogram: &Histogram{
1088 sum: 0.00247889,
1089 count: 9,
1090 buckets: []Bucket{
1091 {upperBound: 0.1, cumulativeCount: 7},
1092 {upperBound: 0.5, cumulativeCount: 8},
1093 {upperBound: math.Inf(1), cumulativeCount: 9},
1094 },
1095 },
1096 },
1097 {
1098 labels: labels.Labels{{Name: "label1", Value: "value2"}},
1099 histogram: &Histogram{
1100 sum: 0.00247889,
1101 count: 9,
1102 buckets: []Bucket{
1103 {upperBound: 0.1, cumulativeCount: 7},
1104 {upperBound: 0.5, cumulativeCount: 8},
1105 {upperBound: math.Inf(1), cumulativeCount: 9},
1106 },
1107 },
1108 },
1109 {
1110 labels: labels.Labels{{Name: "label1", Value: "value3"}},
1111 histogram: &Histogram{
1112 sum: 0.00247889,
1113 count: 9,
1114 buckets: []Bucket{
1115 {upperBound: 0.1, cumulativeCount: 7},
1116 {upperBound: 0.5, cumulativeCount: 8},
1117 {upperBound: math.Inf(1), cumulativeCount: 9},
1118 },
1119 },
1120 },
1121 {
1122 labels: labels.Labels{{Name: "label1", Value: "value4"}},
1123 histogram: &Histogram{
1124 sum: 0.00247889,
1125 count: 9,
1126 buckets: []Bucket{
1127 {upperBound: 0.1, cumulativeCount: 7},
1128 {upperBound: 0.5, cumulativeCount: 8},
1129 {upperBound: math.Inf(1), cumulativeCount: 9},
1130 },
1131 },
1132 },
1133 },
1134 },
1135 "test_gauge_no_meta_metric_1": {
1136 name: "test_gauge_no_meta_metric_1",
1137 typ: model.MetricTypeUnknown,
1138 metrics: []Metric{
1139 {
1140 labels: labels.Labels{{Name: "label1", Value: "value1"}},
1141 untyped: &Untyped{value: 11},
1142 },
1143 {
1144 labels: labels.Labels{{Name: "label1", Value: "value2"}},
1145 untyped: &Untyped{value: 12},
1146 },
1147 {
1148 labels: labels.Labels{{Name: "label1", Value: "value3"}},
1149 untyped: &Untyped{value: 13},
1150 },
1151 {
1152 labels: labels.Labels{{Name: "label1", Value: "value4"}},
1153 untyped: &Untyped{value: 14},
1154 },
1155 },
1156 },
1157 "test_gauge_no_meta_metric_2": {
1158 name: "test_gauge_no_meta_metric_2",
1159 typ: model.MetricTypeUnknown,
1160 metrics: []Metric{
1161 {
1162 labels: labels.Labels{{Name: "label1", Value: "value1"}},
1163 untyped: &Untyped{value: 11},
1164 },
1165 {
1166 labels: labels.Labels{{Name: "label1", Value: "value2"}},
1167 untyped: &Untyped{value: 12},
1168 },
1169 {
1170 labels: labels.Labels{{Name: "label1", Value: "value3"}},
1171 untyped: &Untyped{value: 13},
1172 },
1173 {
1174 labels: labels.Labels{{Name: "label1", Value: "value4"}},
1175 untyped: &Untyped{value: 14},
1176 },
1177 },
1178 },
1179 "test_counter_no_meta_metric_1_total": {
1180 name: "test_counter_no_meta_metric_1_total",
1181 typ: model.MetricTypeUnknown,
1182 metrics: []Metric{
1183 {
1184 labels: labels.Labels{{Name: "label1", Value: "value1"}},
1185 untyped: &Untyped{value: 11},
1186 },
1187 {
1188 labels: labels.Labels{{Name: "label1", Value: "value2"}},
1189 untyped: &Untyped{value: 12},
1190 },
1191 {
1192 labels: labels.Labels{{Name: "label1", Value: "value3"}},
1193 untyped: &Untyped{value: 13},
1194 },
1195 {
1196 labels: labels.Labels{{Name: "label1", Value: "value4"}},
1197 untyped: &Untyped{value: 14},
1198 },
1199 },
1200 },
1201 "test_counter_no_meta_metric_2_total": {
1202 name: "test_counter_no_meta_metric_2_total",
1203 typ: model.MetricTypeUnknown,
1204 metrics: []Metric{
1205 {
1206 labels: labels.Labels{{Name: "label1", Value: "value1"}},
1207 untyped: &Untyped{value: 11},
1208 },
1209 {
1210 labels: labels.Labels{{Name: "label1", Value: "value2"}},
1211 untyped: &Untyped{value: 12},
1212 },
1213 {
1214 labels: labels.Labels{{Name: "label1", Value: "value3"}},
1215 untyped: &Untyped{value: 13},
1216 },
1217 {
1218 labels: labels.Labels{{Name: "label1", Value: "value4"}},
1219 untyped: &Untyped{value: 14},
1220 },
1221 },
1222 },
1223 "test_summary_no_meta_1_duration_microseconds": {
1224 name: "test_summary_no_meta_1_duration_microseconds",
1225 typ: model.MetricTypeSummary,
1226 metrics: []Metric{
1227 {
1228 labels: labels.Labels{{Name: "label1", Value: "value1"}},
1229 summary: &Summary{
1230 sum: 283201.29,
1231 count: 31,
1232 quantiles: []Quantile{
1233 {quantile: 0.5, value: 4931.921},
1234 {quantile: 0.9, value: 4932.921},
1235 {quantile: 0.99, value: 4933.921},
1236 },
1237 },
1238 },
1239 {
1240 labels: labels.Labels{{Name: "label1", Value: "value2"}},
1241 summary: &Summary{
1242 sum: 283201.29,
1243 count: 31,
1244 quantiles: []Quantile{
1245 {quantile: 0.5, value: 4931.921},
1246 {quantile: 0.9, value: 4932.921},
1247 {quantile: 0.99, value: 4933.921},
1248 },
1249 },
1250 },
1251 {
1252 labels: labels.Labels{{Name: "label1", Value: "value3"}},
1253 summary: &Summary{
1254 sum: 283201.29,
1255 count: 31,
1256 quantiles: []Quantile{
1257 {quantile: 0.5, value: 4931.921},
1258 {quantile: 0.9, value: 4932.921},
1259 {quantile: 0.99, value: 4933.921},
1260 },
1261 },
1262 },
1263 {
1264 labels: labels.Labels{{Name: "label1", Value: "value4"}},
1265 summary: &Summary{
1266 sum: 283201.29,
1267 count: 31,
1268 quantiles: []Quantile{
1269 {quantile: 0.5, value: 4931.921},
1270 {quantile: 0.9, value: 4932.921},
1271 {quantile: 0.99, value: 4933.921},
1272 },
1273 },
1274 },
1275 },
1276 },
1277 "test_summary_no_meta_2_duration_microseconds": {
1278 name: "test_summary_no_meta_2_duration_microseconds",
1279 typ: model.MetricTypeSummary,
1280 metrics: []Metric{
1281 {
1282 labels: labels.Labels{{Name: "label1", Value: "value1"}},
1283 summary: &Summary{
1284 sum: 383201.29,
1285 count: 41,
1286 quantiles: []Quantile{
1287 {quantile: 0.5, value: 5931.921},
1288 {quantile: 0.9, value: 5932.921},
1289 {quantile: 0.99, value: 5933.921},
1290 },
1291 },
1292 },
1293 {
1294 labels: labels.Labels{{Name: "label1", Value: "value2"}},
1295 summary: &Summary{
1296 sum: 383201.29,
1297 count: 41,
1298 quantiles: []Quantile{
1299 {quantile: 0.5, value: 5931.921},
1300 {quantile: 0.9, value: 5932.921},
1301 {quantile: 0.99, value: 5933.921},
1302 },
1303 },
1304 },
1305 {
1306 labels: labels.Labels{{Name: "label1", Value: "value3"}},
1307 summary: &Summary{
1308 sum: 383201.29,
1309 count: 41,
1310 quantiles: []Quantile{
1311 {quantile: 0.5, value: 5931.921},
1312 {quantile: 0.9, value: 5932.921},
1313 {quantile: 0.99, value: 5933.921},
1314 },
1315 },
1316 },
1317 {
1318 labels: labels.Labels{{Name: "label1", Value: "value4"}},
1319 summary: &Summary{
1320 sum: 383201.29,
1321 count: 41,
1322 quantiles: []Quantile{
1323 {quantile: 0.5, value: 5931.921},
1324 {quantile: 0.9, value: 5932.921},
1325 {quantile: 0.99, value: 5933.921},
1326 },
1327 },
1328 },
1329 },
1330 },
1331 "test_histogram_no_meta_1_duration_seconds": {
1332 name: "test_histogram_no_meta_1_duration_seconds",
1333 typ: model.MetricTypeHistogram,
1334 metrics: []Metric{
1335 {
1336 labels: labels.Labels{{Name: "label1", Value: "value1"}},
1337 histogram: &Histogram{
1338 sum: 0.00147889,
1339 count: 6,
1340 buckets: []Bucket{
1341 {upperBound: 0.1, cumulativeCount: 4},
1342 {upperBound: 0.5, cumulativeCount: 5},
1343 {upperBound: math.Inf(1), cumulativeCount: 6},
1344 },
1345 },
1346 },
1347 {
1348 labels: labels.Labels{{Name: "label1", Value: "value2"}},
1349 histogram: &Histogram{
1350 sum: 0.00147889,
1351 count: 6,
1352 buckets: []Bucket{
1353 {upperBound: 0.1, cumulativeCount: 4},
1354 {upperBound: 0.5, cumulativeCount: 5},
1355 {upperBound: math.Inf(1), cumulativeCount: 6},
1356 },
1357 },
1358 },
1359 {
1360 labels: labels.Labels{{Name: "label1", Value: "value3"}},
1361 histogram: &Histogram{
1362 sum: 0.00147889,
1363 count: 6,
1364 buckets: []Bucket{
1365 {upperBound: 0.1, cumulativeCount: 4},
1366 {upperBound: 0.5, cumulativeCount: 5},
1367 {upperBound: math.Inf(1), cumulativeCount: 6},
1368 },
1369 },
1370 },
1371 {
1372 labels: labels.Labels{{Name: "label1", Value: "value4"}},
1373 histogram: &Histogram{
1374 sum: 0.00147889,
1375 count: 6,
1376 buckets: []Bucket{
1377 {upperBound: 0.1, cumulativeCount: 4},
1378 {upperBound: 0.5, cumulativeCount: 5},
1379 {upperBound: math.Inf(1), cumulativeCount: 6},
1380 },
1381 },
1382 },
1383 },
1384 },
1385 "test_histogram_no_meta_2_duration_seconds": {
1386 name: "test_histogram_no_meta_2_duration_seconds",
1387 typ: model.MetricTypeHistogram,
1388 metrics: []Metric{
1389 {
1390 labels: labels.Labels{{Name: "label1", Value: "value1"}},
1391 histogram: &Histogram{
1392 sum: 0.00247889,
1393 count: 9,
1394 buckets: []Bucket{
1395 {upperBound: 0.1, cumulativeCount: 7},
1396 {upperBound: 0.5, cumulativeCount: 8},
1397 {upperBound: math.Inf(1), cumulativeCount: 9},
1398 },
1399 },
1400 },
1401 {
1402 labels: labels.Labels{{Name: "label1", Value: "value2"}},
1403 histogram: &Histogram{
1404 sum: 0.00247889,
1405 count: 9,
1406 buckets: []Bucket{
1407 {upperBound: 0.1, cumulativeCount: 7},
1408 {upperBound: 0.5, cumulativeCount: 8},
1409 {upperBound: math.Inf(1), cumulativeCount: 9},
1410 },
1411 },
1412 },
1413 {
1414 labels: labels.Labels{{Name: "label1", Value: "value3"}},
1415 histogram: &Histogram{
1416 sum: 0.00247889,
1417 count: 9,
1418 buckets: []Bucket{
1419 {upperBound: 0.1, cumulativeCount: 7},
1420 {upperBound: 0.5, cumulativeCount: 8},
1421 {upperBound: math.Inf(1), cumulativeCount: 9},
1422 },
1423 },
1424 },
1425 {
1426 labels: labels.Labels{{Name: "label1", Value: "value4"}},
1427 histogram: &Histogram{
1428 sum: 0.00247889,
1429 count: 9,
1430 buckets: []Bucket{
1431 {upperBound: 0.1, cumulativeCount: 7},
1432 {upperBound: 0.5, cumulativeCount: 8},
1433 {upperBound: math.Inf(1), cumulativeCount: 9},
1434 },
1435 },
1436 },
1437 },
1438 },
1439 },
1440 },
1441 }
1442
1443 for name, test := range tests {
1444 t.Run(name, func(t *testing.T) {
1445 var p promTextParser
1446
1447 for i := range 10 {
1448 t.Run(fmt.Sprintf("parse num %d", i+1), func(t *testing.T) {
1449 mfs, err := p.parseToMetricFamilies(test.input, nil)
1450 if len(test.want) > 0 {
1451 assert.Equal(t, test.want, mfs)
1452 } else {
1453 assert.Error(t, err)
1454 }
1455 })
1456 }
1457 })
1458 }
1459 }
1460
1461 func TestPromTextParser_parseToMetricFamiliesWithSelector(t *testing.T) {
1462 sr, err := selector.Parse(`test_gauge_metric_1{label1="value2"}`)
1463 require.NoError(t, err)
1464
1465 p := promTextParser{sr: sr}
1466
1467 txt := []byte(`
1468 test_gauge_metric_1{label1="value1"} 1
1469 test_gauge_metric_1{label1="value2"} 1
1470 test_gauge_metric_2{label1="value1"} 1
1471 test_gauge_metric_2{label1="value2"} 1
1472 `)
1473
1474 want := MetricFamilies{
1475 "test_gauge_metric_1": &MetricFamily{
1476 name: "test_gauge_metric_1",
1477 typ: model.MetricTypeUnknown,
1478 metrics: []Metric{
1479 {labels: labels.Labels{{Name: "label1", Value: "value2"}}, untyped: &Untyped{value: 1}},
1480 },
1481 },
1482 }
1483
1484 mfs, err := p.parseToMetricFamilies(txt, nil)
1485
1486 require.NoError(t, err)
1487 assert.Equal(t, want, mfs)
1488 }
1489
1490 func TestPromTextParser_parseToSeries(t *testing.T) {
1491 tests := map[string]struct {
1492 input []byte
1493 want Series
1494 }{
1495 "label order matches textparse (__name__ not forced first)": {
1496 input: []byte("m{UUID=\"x\",gpu=\"0\"} 5\n"),
1497 want: Series{SeriesSample{
1498 Labels: labels.Labels{
1499 {Name: "UUID", Value: "x"},
1500 {Name: "__name__", Value: "m"},
1501 {Name: "gpu", Value: "0"},
1502 },
1503 Value: 5,
1504 }},
1505 },
1506 "All types": {
1507 input: []byte(`
1508 # HELP test_gauge_metric_1 Test Gauge Metric 1
1509 # TYPE test_gauge_metric_1 gauge
1510 test_gauge_metric_1{label1="value1"} 11
1511 test_gauge_no_meta_metric_1{label1="value1"} 11
1512 # HELP test_counter_metric_1_total Test Counter Metric 1
1513 # TYPE test_counter_metric_1_total counter
1514 test_counter_metric_1_total{label1="value1"} 11
1515 test_counter_no_meta_metric_1_total{label1="value1"} 11
1516 # HELP test_summary_1_duration_microseconds Test Summary Metric 1
1517 # TYPE test_summary_1_duration_microseconds summary
1518 test_summary_1_duration_microseconds{label1="value1",quantile="0.5"} 4931.921
1519 test_summary_1_duration_microseconds{label1="value1",quantile="0.9"} 4932.921
1520 test_summary_1_duration_microseconds{label1="value1",quantile="0.99"} 4933.921
1521 test_summary_1_duration_microseconds_sum{label1="value1"} 283201.29
1522 test_summary_1_duration_microseconds_count{label1="value1"} 31
1523 test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.5"} 4931.921
1524 test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.9"} 4932.921
1525 test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.99"} 4933.921
1526 test_summary_no_meta_1_duration_microseconds_sum{label1="value1"} 283201.29
1527 test_summary_no_meta_1_duration_microseconds_count{label1="value1"} 31
1528 # HELP test_histogram_1_duration_seconds Test Histogram Metric 1
1529 # TYPE test_histogram_1_duration_seconds histogram
1530 test_histogram_1_duration_seconds_bucket{label1="value1",le="0.1"} 4
1531 test_histogram_1_duration_seconds_bucket{label1="value1",le="0.5"} 5
1532 test_histogram_1_duration_seconds_bucket{label1="value1",le="+Inf"} 6
1533 test_histogram_1_duration_seconds_sum{label1="value1"} 0.00147889
1534 test_histogram_1_duration_seconds_count{label1="value1"} 6
1535 test_histogram_no_meta_1_duration_seconds_bucket{label1="value1",le="0.1"} 4
1536 test_histogram_no_meta_1_duration_seconds_bucket{label1="value1",le="0.5"} 5
1537 test_histogram_no_meta_1_duration_seconds_bucket{label1="value1",le="+Inf"} 6
1538 test_histogram_no_meta_1_duration_seconds_sum{label1="value1"} 0.00147889
1539 test_histogram_no_meta_1_duration_seconds_count{label1="value1"} 6
1540 `),
1541 want: Series{
1542 // Gauge
1543 {
1544 Labels: labels.Labels{
1545 {Name: "__name__", Value: "test_gauge_metric_1"},
1546 {Name: "label1", Value: "value1"},
1547 },
1548 Value: 11,
1549 },
1550 {
1551 Labels: labels.Labels{
1552 {Name: "__name__", Value: "test_gauge_no_meta_metric_1"},
1553 {Name: "label1", Value: "value1"},
1554 },
1555 Value: 11,
1556 },
1557 // Counter
1558 {
1559 Labels: labels.Labels{
1560 {Name: "__name__", Value: "test_counter_metric_1_total"},
1561 {Name: "label1", Value: "value1"},
1562 },
1563 Value: 11,
1564 },
1565 {
1566 Labels: labels.Labels{
1567 {Name: "__name__", Value: "test_counter_no_meta_metric_1_total"},
1568 {Name: "label1", Value: "value1"},
1569 },
1570 Value: 11,
1571 },
1572 //// Summary
1573 {
1574 Labels: labels.Labels{
1575 {Name: "__name__", Value: "test_summary_1_duration_microseconds"},
1576 {Name: "label1", Value: "value1"},
1577 {Name: "quantile", Value: "0.5"},
1578 },
1579 Value: 4931.921,
1580 },
1581 {
1582 Labels: labels.Labels{
1583 {Name: "__name__", Value: "test_summary_1_duration_microseconds"},
1584 {Name: "label1", Value: "value1"},
1585 {Name: "quantile", Value: "0.9"},
1586 },
1587 Value: 4932.921,
1588 },
1589 {
1590 Labels: labels.Labels{
1591 {Name: "__name__", Value: "test_summary_1_duration_microseconds"},
1592 {Name: "label1", Value: "value1"},
1593 {Name: "quantile", Value: "0.99"},
1594 },
1595 Value: 4933.921,
1596 },
1597 {
1598 Labels: labels.Labels{
1599 {Name: "__name__", Value: "test_summary_1_duration_microseconds_sum"},
1600 {Name: "label1", Value: "value1"},
1601 },
1602 Value: 283201.29,
1603 },
1604 {
1605 Labels: labels.Labels{
1606 {Name: "__name__", Value: "test_summary_1_duration_microseconds_count"},
1607 {Name: "label1", Value: "value1"},
1608 },
1609 Value: 31,
1610 },
1611 {
1612 Labels: labels.Labels{
1613 {Name: "__name__", Value: "test_summary_no_meta_1_duration_microseconds"},
1614 {Name: "label1", Value: "value1"},
1615 {Name: "quantile", Value: "0.5"},
1616 },
1617 Value: 4931.921,
1618 },
1619 {
1620 Labels: labels.Labels{
1621 {Name: "__name__", Value: "test_summary_no_meta_1_duration_microseconds"},
1622 {Name: "label1", Value: "value1"},
1623 {Name: "quantile", Value: "0.9"},
1624 },
1625 Value: 4932.921,
1626 },
1627 {
1628 Labels: labels.Labels{
1629 {Name: "__name__", Value: "test_summary_no_meta_1_duration_microseconds"},
1630 {Name: "label1", Value: "value1"},
1631 {Name: "quantile", Value: "0.99"},
1632 },
1633 Value: 4933.921,
1634 },
1635 {
1636 Labels: labels.Labels{
1637 {Name: "__name__", Value: "test_summary_no_meta_1_duration_microseconds_sum"},
1638 {Name: "label1", Value: "value1"},
1639 },
1640 Value: 283201.29,
1641 },
1642 {
1643 Labels: labels.Labels{
1644 {Name: "__name__", Value: "test_summary_no_meta_1_duration_microseconds_count"},
1645 {Name: "label1", Value: "value1"},
1646 },
1647 Value: 31,
1648 },
1649 // Histogram
1650 {
1651 Labels: labels.Labels{
1652 {Name: "__name__", Value: "test_histogram_1_duration_seconds_bucket"},
1653 {Name: "label1", Value: "value1"},
1654 {Name: "le", Value: "0.1"},
1655 },
1656 Value: 4,
1657 },
1658 {
1659 Labels: labels.Labels{
1660 {Name: "__name__", Value: "test_histogram_1_duration_seconds_bucket"},
1661 {Name: "label1", Value: "value1"},
1662 {Name: "le", Value: "0.5"},
1663 },
1664 Value: 5,
1665 },
1666 {
1667 Labels: labels.Labels{
1668 {Name: "__name__", Value: "test_histogram_1_duration_seconds_bucket"},
1669 {Name: "label1", Value: "value1"},
1670 {Name: "le", Value: "+Inf"},
1671 },
1672 Value: 6,
1673 },
1674 {
1675 Labels: labels.Labels{
1676 {Name: "__name__", Value: "test_histogram_1_duration_seconds_sum"},
1677 {Name: "label1", Value: "value1"},
1678 },
1679 Value: 0.00147889,
1680 },
1681 {
1682 Labels: labels.Labels{
1683 {Name: "__name__", Value: "test_histogram_1_duration_seconds_count"},
1684 {Name: "label1", Value: "value1"},
1685 },
1686 Value: 6,
1687 },
1688
1689 {
1690 Labels: labels.Labels{
1691 {Name: "__name__", Value: "test_histogram_no_meta_1_duration_seconds_bucket"},
1692 {Name: "label1", Value: "value1"},
1693 {Name: "le", Value: "0.1"},
1694 },
1695 Value: 4,
1696 },
1697 {
1698 Labels: labels.Labels{
1699 {Name: "__name__", Value: "test_histogram_no_meta_1_duration_seconds_bucket"},
1700 {Name: "label1", Value: "value1"},
1701 {Name: "le", Value: "0.5"},
1702 },
1703 Value: 5,
1704 },
1705 {
1706 Labels: labels.Labels{
1707 {Name: "__name__", Value: "test_histogram_no_meta_1_duration_seconds_bucket"},
1708 {Name: "label1", Value: "value1"},
1709 {Name: "le", Value: "+Inf"},
1710 },
1711 Value: 6,
1712 },
1713 {
1714 Labels: labels.Labels{
1715 {Name: "__name__", Value: "test_histogram_no_meta_1_duration_seconds_sum"},
1716 {Name: "label1", Value: "value1"},
1717 },
1718 Value: 0.00147889,
1719 },
1720 {
1721 Labels: labels.Labels{
1722 {Name: "__name__", Value: "test_histogram_no_meta_1_duration_seconds_count"},
1723 {Name: "label1", Value: "value1"},
1724 },
1725 Value: 6,
1726 },
1727 },
1728 },
1729 }
1730
1731 for name, test := range tests {
1732 t.Run(name, func(t *testing.T) {
1733 var p promTextParser
1734
1735 for i := range 10 {
1736 t.Run(fmt.Sprintf("parse num %d", i+1), func(t *testing.T) {
1737 series, err := p.parseToSeries(test.input)
1738
1739 if len(test.want) > 0 {
1740 test.want.Sort()
1741 assert.Equal(t, test.want, series)
1742 } else {
1743 assert.Error(t, err)
1744 }
1745 })
1746 }
1747 })
1748 }
1749 }
1750
1751 func TestPromTextParser_parseToSeriesWithSelector(t *testing.T) {
1752 sr, err := selector.Parse(`test_gauge_metric_1{label1="value2"}`)
1753 require.NoError(t, err)
1754
1755 p := promTextParser{sr: sr}
1756
1757 txt := []byte(`
1758 test_gauge_metric_1{label1="value1"} 1
1759 test_gauge_metric_1{label1="value2"} 1
1760 test_gauge_metric_2{label1="value1"} 1
1761 test_gauge_metric_2{label1="value2"} 1
1762 `)
1763
1764 want := Series{SeriesSample{
1765 Labels: labels.Labels{
1766 {Name: "__name__", Value: "test_gauge_metric_1"},
1767 {Name: "label1", Value: "value2"},
1768 },
1769 Value: 1,
1770 }}
1771
1772 series, err := p.parseToSeries(txt)
1773
1774 require.NoError(t, err)
1775 assert.Equal(t, want, series)
1776 }
1777
1778 func TestPromTextParser_parseToMetricFamilies_failsOnInvalidSeriesValue(t *testing.T) {
1779 var p promTextParser
1780
1781 txt := []byte(`
1782 # HELP DCGM_FI_DEV_GPU_UTIL GPU utilization
1783 # TYPE DCGM_FI_DEV_GPU_UTIL gauge
1784 DCGM_FI_DEV_GPU_UTIL{UUID="GPU-aaa",gpu="0"} 80
1785 # HELP DCGM_FI_DEV_REQUESTED_POWER_PROFILE_MASK Requested power profile mask
1786 # TYPE DCGM_FI_DEV_REQUESTED_POWER_PROFILE_MASK gauge
1787 DCGM_FI_DEV_REQUESTED_POWER_PROFILE_MASK{UUID="GPU-aaa",gpu="0"} ERROR - FAILED TO CONVERT TO STRING
1788 `)
1789
1790 _, err := p.parseToMetricFamilies(txt, nil)
1791 require.Error(t, err)
1792 assert.Contains(t, err.Error(), "failed to parse prometheus metrics")
1793 }
1794
1795 func TestPromTextParser_parseToSeries_failsOnInvalidSeriesValue(t *testing.T) {
1796 var p promTextParser
1797
1798 txt := []byte(`
1799 DCGM_FI_DEV_GPU_UTIL{UUID="GPU-aaa",gpu="0"} 80
1800 DCGM_FI_DEV_REQUESTED_POWER_PROFILE_MASK{UUID="GPU-aaa",gpu="0"} ERROR - FAILED TO CONVERT TO STRING
1801 `)
1802
1803 _, err := p.parseToSeries(txt)
1804 require.Error(t, err)
1805 assert.Contains(t, err.Error(), "failed to parse prometheus metrics")
1806 }
1807
1808 func joinData(data ...[]byte) []byte {
1809 var buf bytes.Buffer
1810 for _, v := range data {
1811 _, _ = buf.Write(v)
1812 _ = buf.WriteByte('\n')
1813 }
1814 return buf.Bytes()
1815 }
1816
1817 func TestPromTextParser_parseSamples(t *testing.T) {
1818 type wantSample struct {
1819 name string
1820 labels string
1821 value float64
1822 kind SampleKind
1823 familyType model.MetricType
1824 }
1825
1826 tests := map[string]struct {
1827 input []byte
1828 wantHelp []string
1829 want []wantSample
1830 }{
1831 "deferred _sum emits after a later unrelated metric (cross-metric reorder)": {
1832 input: []byte("a_sum 1\nb 2\n# TYPE a summary\na{quantile=\"0.5\"} 3\n"),
1833 want: []wantSample{
1834 {"b", `{}`, 2, SampleKindScalar, model.MetricTypeUnknown},
1835 {"a_sum", `{}`, 1, SampleKindSummarySum, model.MetricTypeSummary},
1836 {"a", `{quantile="0.5"}`, 3, SampleKindSummaryQuantile, model.MetricTypeSummary},
1837 },
1838 },
1839 "all metric types are classified in exposition order": {
1840 input: []byte(`# HELP test_gauge A gauge metric.
1841 # TYPE test_gauge gauge
1842 test_gauge{label="a"} 1
1843 # TYPE test_counter_total counter
1844 test_counter_total 5
1845 # TYPE test_hist histogram
1846 test_hist_bucket{le="0.1"} 1
1847 test_hist_bucket{le="+Inf"} 2
1848 test_hist_sum 3
1849 test_hist_count 2
1850 # TYPE test_summary summary
1851 test_summary{quantile="0.5"} 0.2
1852 test_summary_sum 1
1853 test_summary_count 10
1854 `),
1855 wantHelp: []string{"test_gauge=A gauge metric."},
1856 want: []wantSample{
1857 {"test_gauge", `{label="a"}`, 1, SampleKindScalar, model.MetricTypeGauge},
1858 {"test_counter_total", `{}`, 5, SampleKindScalar, model.MetricTypeCounter},
1859 {"test_hist_bucket", `{le="0.1"}`, 1, SampleKindHistogramBucket, model.MetricTypeHistogram},
1860 {"test_hist_bucket", `{le="+Inf"}`, 2, SampleKindHistogramBucket, model.MetricTypeHistogram},
1861 {"test_hist_sum", `{}`, 3, SampleKindHistogramSum, model.MetricTypeHistogram},
1862 {"test_hist_count", `{}`, 2, SampleKindHistogramCount, model.MetricTypeHistogram},
1863 {"test_summary", `{quantile="0.5"}`, 0.2, SampleKindSummaryQuantile, model.MetricTypeSummary},
1864 {"test_summary_sum", `{}`, 1, SampleKindSummarySum, model.MetricTypeSummary},
1865 {"test_summary_count", `{}`, 10, SampleKindSummaryCount, model.MetricTypeSummary},
1866 },
1867 },
1868 "__name__ is delivered via Name and excluded from Labels": {
1869 input: []byte("# TYPE m gauge\nm{a=\"1\",b=\"2\"} 7\n"),
1870 want: []wantSample{
1871 {"m", `{a="1", b="2"}`, 7, SampleKindScalar, model.MetricTypeGauge},
1872 },
1873 },
1874 "deferred sum/count before # TYPE are buffered and back-resolved": {
1875 input: []byte(`my_summary_sum 10
1876 my_summary_count 2
1877 # TYPE my_summary summary
1878 my_summary{quantile="0.5"} 0.5
1879 `),
1880 want: []wantSample{
1881 {"my_summary_sum", `{}`, 10, SampleKindSummarySum, model.MetricTypeSummary},
1882 {"my_summary_count", `{}`, 2, SampleKindSummaryCount, model.MetricTypeSummary},
1883 {"my_summary", `{quantile="0.5"}`, 0.5, SampleKindSummaryQuantile, model.MetricTypeSummary},
1884 },
1885 },
1886 }
1887
1888 for name, test := range tests {
1889 t.Run(name, func(t *testing.T) {
1890 var p promTextParser
1891
1892 for i := range 10 {
1893 t.Run(fmt.Sprintf("parse num %d", i+1), func(t *testing.T) {
1894 var got []wantSample
1895 var help []string
1896
1897 err := p.driver.parseSamples(test.input, true,
1898 func(name, h string) { help = append(help, name+"="+h) },
1899 func(s Sample) error {
1900 assert.Falsef(t, s.Labels.Has(labels.MetricName),
1901 "sample %q must not carry __name__ in Labels", s.Name)
1902 got = append(got, wantSample{s.Name, s.Labels.String(), s.Value, s.Kind, s.FamilyType})
1903 return nil
1904 },
1905 )
1906 require.NoError(t, err)
1907 assert.Equal(t, test.want, got)
1908 for _, h := range test.wantHelp {
1909 assert.Contains(t, help, h)
1910 }
1911 })
1912 }
1913 })
1914 }
1915 }
1916
1917 // The stream supports Prometheus-style relabeling on __name__/le/quantile.
1918 // ownLabels=true isolates each sample's labels, so a transform can rename via
1919 // Name and mutate Labels in place without affecting later samples.
1920 func TestPromTextParser_parseSamples_relabelStyle(t *testing.T) {
1921 data := []byte(`# TYPE req_seconds histogram
1922 req_seconds_bucket{le="0.1",path="/a"} 1
1923 req_seconds_bucket{le="+Inf",path="/a"} 3
1924 # TYPE rpc summary
1925 rpc{quantile="0.99",path="/a"} 0.5
1926 `)
1927
1928 type out struct {
1929 name string
1930 le string
1931 quantile string
1932 labels string
1933 }
1934
1935 var p promTextParser
1936 var got []out
1937 err := p.driver.parseSamples(data, true, nil, func(s Sample) error {
1938 o := out{
1939 name: s.Name + ":relabeled", // __name__ is mutable via Name
1940 le: s.Labels.Get(bucketLabel),
1941 quantile: s.Labels.Get(quantileLabel),
1942 }
1943 // Drop the "path" target label in place (this sample owns its labels).
1944 kept := s.Labels[:0]
1945 for _, l := range s.Labels {
1946 if l.Name == "path" {
1947 continue
1948 }
1949 kept = append(kept, l)
1950 }
1951 o.labels = labels.Labels(kept).String()
1952 got = append(got, o)
1953 return nil
1954 })
1955 require.NoError(t, err)
1956
1957 assert.Equal(t, []out{
1958 {name: "req_seconds_bucket:relabeled", le: "0.1", quantile: "", labels: `{le="0.1"}`},
1959 {name: "req_seconds_bucket:relabeled", le: "+Inf", quantile: "", labels: `{le="+Inf"}`},
1960 {name: "rpc:relabeled", le: "", quantile: "0.99", labels: `{quantile="0.99"}`},
1961 }, got)
1962 }
1963
1964 // A transform's mutations — a renamed Name and changed Labels — are what the
1965 // assembler folds: parseToMetricFamilies must assemble the TRANSFORMED sample, not
1966 // the original. Mutating Labels in place also exercises ownLabels=true.
1967 func TestPromTextParser_parseToMetricFamilies_transformMutatesAssembledOutput(t *testing.T) {
1968 input := []byte("# TYPE old_name gauge\nold_name{keep=\"yes\",drop=\"me\"} 42\n")
1969
1970 // Rename the metric and drop the "drop" label in place (the sample owns its labels).
1971 transform := func(s Sample) (Sample, bool, error) {
1972 s.Name = "new_name"
1973 kept := s.Labels[:0]
1974 for _, l := range s.Labels {
1975 if l.Name == "drop" {
1976 continue
1977 }
1978 kept = append(kept, l)
1979 }
1980 s.Labels = kept
1981 return s, true, nil
1982 }
1983
1984 want := MetricFamilies{
1985 "new_name": {
1986 name: "new_name",
1987 typ: model.MetricTypeGauge,
1988 metrics: []Metric{
1989 {labels: labels.Labels{{Name: "keep", Value: "yes"}}, gauge: &Gauge{value: 42}},
1990 },
1991 },
1992 }
1993
1994 var p promTextParser
1995 mfs, err := p.parseToMetricFamilies(input, transform)
1996 require.NoError(t, err)
1997 assert.Equal(t, want, mfs)
1998 }