1
2
3
4
5
6
7
8
9
10
11
12
13
14 package expfmt
15
16 import (
17 "bytes"
18 "math"
19 "strings"
20 "testing"
21 "time"
22
23 "google.golang.org/protobuf/proto"
24 "google.golang.org/protobuf/types/known/timestamppb"
25
26 dto "github.com/prometheus/client_model/go"
27
28 "github.com/prometheus/common/model"
29 )
30
31 func TestCreateOpenMetrics(t *testing.T) {
32 openMetricsTimestamp := timestamppb.New(time.Unix(12345, 600000000))
33 if err := openMetricsTimestamp.CheckValid(); err != nil {
34 t.Error(err)
35 }
36
37 oldDefaultScheme := model.NameEscapingScheme
38 model.NameEscapingScheme = model.NoEscaping
39 defer func() {
40 model.NameEscapingScheme = oldDefaultScheme
41 }()
42
43 scenarios := []struct {
44 in *dto.MetricFamily
45 options []EncoderOption
46 out string
47 }{
48
49 {
50 in: &dto.MetricFamily{
51 Name: proto.String("name"),
52 Help: proto.String("two-line\n doc str\\ing"),
53 Type: dto.MetricType_COUNTER.Enum(),
54 Metric: []*dto.Metric{
55 {
56 Label: []*dto.LabelPair{
57 {
58 Name: proto.String("labelname"),
59 Value: proto.String("val1"),
60 },
61 {
62 Name: proto.String("basename"),
63 Value: proto.String("basevalue"),
64 },
65 },
66 Counter: &dto.Counter{
67 Value: proto.Float64(42),
68 },
69 },
70 {
71 Label: []*dto.LabelPair{
72 {
73 Name: proto.String("labelname"),
74 Value: proto.String("val2"),
75 },
76 {
77 Name: proto.String("basename"),
78 Value: proto.String("basevalue"),
79 },
80 },
81 Counter: &dto.Counter{
82 Value: proto.Float64(.23),
83 },
84 TimestampMs: proto.Int64(1234567890),
85 },
86 },
87 },
88 out: `# HELP name two-line\n doc str\\ing
89 # TYPE name unknown
90 name{labelname="val1",basename="basevalue"} 42.0
91 name{labelname="val2",basename="basevalue"} 0.23 1.23456789e+06
92 `,
93 },
94
95 {
96 in: &dto.MetricFamily{
97 Name: proto.String("name.with.dots"),
98 Help: proto.String("boring help"),
99 Type: dto.MetricType_COUNTER.Enum(),
100 Metric: []*dto.Metric{
101 {
102 Label: []*dto.LabelPair{
103 {
104 Name: proto.String("labelname"),
105 Value: proto.String("val1"),
106 },
107 {
108 Name: proto.String("basename"),
109 Value: proto.String("basevalue"),
110 },
111 },
112 Counter: &dto.Counter{
113 Value: proto.Float64(42),
114 },
115 },
116 {
117 Label: []*dto.LabelPair{
118 {
119 Name: proto.String("labelname"),
120 Value: proto.String("val2"),
121 },
122 {
123 Name: proto.String("basename"),
124 Value: proto.String("basevalue"),
125 },
126 },
127 Counter: &dto.Counter{
128 Value: proto.Float64(.23),
129 },
130 TimestampMs: proto.Int64(1234567890),
131 },
132 },
133 },
134 out: `# HELP "name.with.dots" boring help
135 # TYPE "name.with.dots" unknown
136 {"name.with.dots",labelname="val1",basename="basevalue"} 42.0
137 {"name.with.dots",labelname="val2",basename="basevalue"} 0.23 1.23456789e+06
138 `,
139 },
140
141 {
142 in: &dto.MetricFamily{
143 Name: proto.String("name.with.dots"),
144 Help: proto.String("boring help"),
145 Type: dto.MetricType_COUNTER.Enum(),
146 Metric: []*dto.Metric{
147 {
148 Counter: &dto.Counter{
149 Value: proto.Float64(42),
150 },
151 },
152 {
153 Counter: &dto.Counter{
154 Value: proto.Float64(.23),
155 },
156 TimestampMs: proto.Int64(1234567890),
157 },
158 },
159 },
160 out: `# HELP "name.with.dots" boring help
161 # TYPE "name.with.dots" unknown
162 {"name.with.dots"} 42.0
163 {"name.with.dots"} 0.23 1.23456789e+06
164 `,
165 },
166
167 {
168 in: &dto.MetricFamily{
169 Name: proto.String("gauge_name"),
170 Help: proto.String("gauge\ndoc\nstr\"ing"),
171 Type: dto.MetricType_GAUGE.Enum(),
172 Metric: []*dto.Metric{
173 {
174 Label: []*dto.LabelPair{
175 {
176 Name: proto.String("name_1"),
177 Value: proto.String("val with\nnew line"),
178 },
179 {
180 Name: proto.String("name_2"),
181 Value: proto.String("val with \\backslash and \"quotes\""),
182 },
183 },
184 Gauge: &dto.Gauge{
185 Value: proto.Float64(math.Inf(+1)),
186 },
187 },
188 {
189 Label: []*dto.LabelPair{
190 {
191 Name: proto.String("name_1"),
192 Value: proto.String("Björn"),
193 },
194 {
195 Name: proto.String("name_2"),
196 Value: proto.String("佖佥"),
197 },
198 },
199 Gauge: &dto.Gauge{
200 Value: proto.Float64(3.14e42),
201 },
202 },
203 },
204 },
205 out: `# HELP gauge_name gauge\ndoc\nstr\"ing
206 # TYPE gauge_name gauge
207 gauge_name{name_1="val with\nnew line",name_2="val with \\backslash and \"quotes\""} +Inf
208 gauge_name{name_1="Björn",name_2="佖佥"} 3.14e+42
209 `,
210 },
211
212 {
213 in: &dto.MetricFamily{
214 Name: proto.String("gauge.name\""),
215 Help: proto.String("gauge\ndoc\nstr\"ing"),
216 Type: dto.MetricType_GAUGE.Enum(),
217 Metric: []*dto.Metric{
218 {
219 Label: []*dto.LabelPair{
220 {
221 Name: proto.String("name.1"),
222 Value: proto.String("val with\nnew line"),
223 },
224 {
225 Name: proto.String("name*2"),
226 Value: proto.String("val with \\backslash and \"quotes\""),
227 },
228 },
229 Gauge: &dto.Gauge{
230 Value: proto.Float64(math.Inf(+1)),
231 },
232 },
233 {
234 Label: []*dto.LabelPair{
235 {
236 Name: proto.String("name.1"),
237 Value: proto.String("Björn"),
238 },
239 {
240 Name: proto.String("name*2"),
241 Value: proto.String("佖佥"),
242 },
243 },
244 Gauge: &dto.Gauge{
245 Value: proto.Float64(3.14e42),
246 },
247 },
248 },
249 },
250 out: `# HELP "gauge.name\"" gauge\ndoc\nstr\"ing
251 # TYPE "gauge.name\"" gauge
252 {"gauge.name\"","name.1"="val with\nnew line","name*2"="val with \\backslash and \"quotes\""} +Inf
253 {"gauge.name\"","name.1"="Björn","name*2"="佖佥"} 3.14e+42
254 `,
255 },
256
257 {
258 in: &dto.MetricFamily{
259 Name: proto.String("unknown_name"),
260 Type: dto.MetricType_UNTYPED.Enum(),
261 Metric: []*dto.Metric{
262 {
263 Untyped: &dto.Untyped{
264 Value: proto.Float64(math.Inf(-1)),
265 },
266 },
267 {
268 Label: []*dto.LabelPair{
269 {
270 Name: proto.String("name_1"),
271 Value: proto.String("value 1"),
272 },
273 },
274 Untyped: &dto.Untyped{
275 Value: proto.Float64(-1.23e-45),
276 },
277 },
278 },
279 },
280 out: `# TYPE unknown_name unknown
281 unknown_name -Inf
282 unknown_name{name_1="value 1"} -1.23e-45
283 `,
284 },
285
286 {
287 in: &dto.MetricFamily{
288 Name: proto.String("summary_name"),
289 Help: proto.String("summary docstring"),
290 Type: dto.MetricType_SUMMARY.Enum(),
291 Metric: []*dto.Metric{
292 {
293 Summary: &dto.Summary{
294 SampleCount: proto.Uint64(42),
295 SampleSum: proto.Float64(-3.4567),
296 Quantile: []*dto.Quantile{
297 {
298 Quantile: proto.Float64(0.5),
299 Value: proto.Float64(-1.23),
300 },
301 {
302 Quantile: proto.Float64(0.9),
303 Value: proto.Float64(.2342354),
304 },
305 {
306 Quantile: proto.Float64(0.99),
307 Value: proto.Float64(0),
308 },
309 },
310 CreatedTimestamp: openMetricsTimestamp,
311 },
312 },
313 {
314 Label: []*dto.LabelPair{
315 {
316 Name: proto.String("name_1"),
317 Value: proto.String("value 1"),
318 },
319 {
320 Name: proto.String("name_2"),
321 Value: proto.String("value 2"),
322 },
323 },
324 Summary: &dto.Summary{
325 SampleCount: proto.Uint64(4711),
326 SampleSum: proto.Float64(2010.1971),
327 Quantile: []*dto.Quantile{
328 {
329 Quantile: proto.Float64(0.5),
330 Value: proto.Float64(1),
331 },
332 {
333 Quantile: proto.Float64(0.9),
334 Value: proto.Float64(2),
335 },
336 {
337 Quantile: proto.Float64(0.99),
338 Value: proto.Float64(3),
339 },
340 },
341 CreatedTimestamp: openMetricsTimestamp,
342 },
343 },
344 },
345 },
346 options: []EncoderOption{WithCreatedLines()},
347 out: `# HELP summary_name summary docstring
348 # TYPE summary_name summary
349 summary_name{quantile="0.5"} -1.23
350 summary_name{quantile="0.9"} 0.2342354
351 summary_name{quantile="0.99"} 0.0
352 summary_name_sum -3.4567
353 summary_name_count 42
354 summary_name_created 12345.6
355 summary_name{name_1="value 1",name_2="value 2",quantile="0.5"} 1.0
356 summary_name{name_1="value 1",name_2="value 2",quantile="0.9"} 2.0
357 summary_name{name_1="value 1",name_2="value 2",quantile="0.99"} 3.0
358 summary_name_sum{name_1="value 1",name_2="value 2"} 2010.1971
359 summary_name_count{name_1="value 1",name_2="value 2"} 4711
360 summary_name_created{name_1="value 1",name_2="value 2"} 12345.6
361 `,
362 },
363
364 {
365 in: &dto.MetricFamily{
366 Name: proto.String("request_duration_microseconds"),
367 Help: proto.String("The response latency."),
368 Type: dto.MetricType_HISTOGRAM.Enum(),
369 Unit: proto.String("microseconds"),
370 Metric: []*dto.Metric{
371 {
372 Histogram: &dto.Histogram{
373 SampleCount: proto.Uint64(2693),
374 SampleSum: proto.Float64(1756047.3),
375 Bucket: []*dto.Bucket{
376 {
377 UpperBound: proto.Float64(100),
378 CumulativeCount: proto.Uint64(123),
379 },
380 {
381 UpperBound: proto.Float64(120),
382 CumulativeCount: proto.Uint64(412),
383 },
384 {
385 UpperBound: proto.Float64(144),
386 CumulativeCount: proto.Uint64(592),
387 },
388 {
389 UpperBound: proto.Float64(172.8),
390 CumulativeCount: proto.Uint64(1524),
391 },
392 {
393 UpperBound: proto.Float64(math.Inf(+1)),
394 CumulativeCount: proto.Uint64(2693),
395 },
396 },
397 CreatedTimestamp: openMetricsTimestamp,
398 },
399 },
400 },
401 },
402 options: []EncoderOption{WithCreatedLines(), WithUnit()},
403 out: `# HELP request_duration_microseconds The response latency.
404 # TYPE request_duration_microseconds histogram
405 # UNIT request_duration_microseconds microseconds
406 request_duration_microseconds_bucket{le="100.0"} 123
407 request_duration_microseconds_bucket{le="120.0"} 412
408 request_duration_microseconds_bucket{le="144.0"} 592
409 request_duration_microseconds_bucket{le="172.8"} 1524
410 request_duration_microseconds_bucket{le="+Inf"} 2693
411 request_duration_microseconds_sum 1.7560473e+06
412 request_duration_microseconds_count 2693
413 request_duration_microseconds_created 12345.6
414 `,
415 },
416
417 {
418 in: &dto.MetricFamily{
419 Name: proto.String("request_duration_microseconds"),
420 Help: proto.String("The response latency."),
421 Type: dto.MetricType_HISTOGRAM.Enum(),
422 Unit: proto.String("microseconds"),
423 Metric: []*dto.Metric{
424 {
425 Histogram: &dto.Histogram{
426 SampleCount: proto.Uint64(2693),
427 SampleSum: proto.Float64(1756047.3),
428 Bucket: []*dto.Bucket{
429 {
430 UpperBound: proto.Float64(100),
431 CumulativeCount: proto.Uint64(123),
432 },
433 {
434 UpperBound: proto.Float64(120),
435 CumulativeCount: proto.Uint64(412),
436 },
437 {
438 UpperBound: proto.Float64(144),
439 CumulativeCount: proto.Uint64(592),
440 },
441 {
442 UpperBound: proto.Float64(172.8),
443 CumulativeCount: proto.Uint64(1524),
444 },
445 },
446 },
447 },
448 },
449 },
450 out: `# HELP request_duration_microseconds The response latency.
451 # TYPE request_duration_microseconds histogram
452 request_duration_microseconds_bucket{le="100.0"} 123
453 request_duration_microseconds_bucket{le="120.0"} 412
454 request_duration_microseconds_bucket{le="144.0"} 592
455 request_duration_microseconds_bucket{le="172.8"} 1524
456 request_duration_microseconds_bucket{le="+Inf"} 2693
457 request_duration_microseconds_sum 1.7560473e+06
458 request_duration_microseconds_count 2693
459 `,
460 },
461
462 {
463 in: &dto.MetricFamily{
464 Name: proto.String("request_duration_microseconds"),
465 Help: proto.String("The response latency."),
466 Type: dto.MetricType_HISTOGRAM.Enum(),
467 Metric: []*dto.Metric{
468 {
469 Histogram: &dto.Histogram{
470 SampleCount: proto.Uint64(2693),
471 SampleSum: proto.Float64(1756047.3),
472 Bucket: []*dto.Bucket{
473 {
474 UpperBound: proto.Float64(100),
475 CumulativeCount: proto.Uint64(123),
476 },
477 {
478 UpperBound: proto.Float64(120),
479 CumulativeCount: proto.Uint64(412),
480 Exemplar: &dto.Exemplar{
481 Label: []*dto.LabelPair{
482 {
483 Name: proto.String("foo"),
484 Value: proto.String("bar"),
485 },
486 },
487 Value: proto.Float64(119.9),
488 Timestamp: openMetricsTimestamp,
489 },
490 },
491 {
492 UpperBound: proto.Float64(144),
493 CumulativeCount: proto.Uint64(592),
494 Exemplar: &dto.Exemplar{
495 Label: []*dto.LabelPair{
496 {
497 Name: proto.String("foo"),
498 Value: proto.String("baz"),
499 },
500 {
501 Name: proto.String("dings"),
502 Value: proto.String("bums"),
503 },
504 },
505 Value: proto.Float64(140.14),
506 },
507 },
508 {
509 UpperBound: proto.Float64(172.8),
510 CumulativeCount: proto.Uint64(1524),
511 },
512 },
513 },
514 },
515 },
516 },
517 out: `# HELP request_duration_microseconds The response latency.
518 # TYPE request_duration_microseconds histogram
519 request_duration_microseconds_bucket{le="100.0"} 123
520 request_duration_microseconds_bucket{le="120.0"} 412 # {foo="bar"} 119.9 12345.6
521 request_duration_microseconds_bucket{le="144.0"} 592 # {foo="baz",dings="bums"} 140.14
522 request_duration_microseconds_bucket{le="172.8"} 1524
523 request_duration_microseconds_bucket{le="+Inf"} 2693
524 request_duration_microseconds_sum 1.7560473e+06
525 request_duration_microseconds_count 2693
526 `,
527 },
528
529 {
530 in: &dto.MetricFamily{
531 Name: proto.String("foos_total"),
532 Help: proto.String("Number of foos."),
533 Type: dto.MetricType_COUNTER.Enum(),
534 Metric: []*dto.Metric{
535 {
536 Counter: &dto.Counter{
537 Value: proto.Float64(42),
538 CreatedTimestamp: openMetricsTimestamp,
539 },
540 },
541 },
542 },
543 options: []EncoderOption{WithCreatedLines()},
544 out: `# HELP foos Number of foos.
545 # TYPE foos counter
546 foos_total 42.0
547 foos_created 12345.6
548 `,
549 },
550
551 {
552 in: &dto.MetricFamily{
553 Name: proto.String("foos_total"),
554 Help: proto.String("Number of foos."),
555 Type: dto.MetricType_COUNTER.Enum(),
556 Metric: []*dto.Metric{
557 {
558 Counter: &dto.Counter{
559 Value: proto.Float64(42),
560 CreatedTimestamp: openMetricsTimestamp,
561 },
562 },
563 },
564 },
565 out: `# HELP foos Number of foos.
566 # TYPE foos counter
567 foos_total 42.0
568 `,
569 },
570
571 {
572 in: &dto.MetricFamily{
573 Name: proto.String("name_total"),
574 Help: proto.String("doc string"),
575 Type: dto.MetricType_COUNTER.Enum(),
576 Metric: []*dto.Metric{},
577 },
578 out: `# HELP name doc string
579 # TYPE name counter
580 `,
581 },
582
583
584 {
585 in: &dto.MetricFamily{
586 Name: proto.String("foos_total"),
587 Help: proto.String("Number of foos."),
588 Type: dto.MetricType_COUNTER.Enum(),
589 Metric: []*dto.Metric{
590 {
591 Counter: &dto.Counter{
592 Value: proto.Float64(42),
593 Exemplar: &dto.Exemplar{
594 Label: []*dto.LabelPair{},
595 Value: proto.Float64(1),
596 Timestamp: openMetricsTimestamp,
597 },
598 },
599 },
600 },
601 },
602 out: `# HELP foos Number of foos.
603 # TYPE foos counter
604 foos_total 42.0
605 `,
606 },
607
608 {
609 in: &dto.MetricFamily{
610 Name: proto.String("name_seconds_total"),
611 Help: proto.String("doc string"),
612 Type: dto.MetricType_COUNTER.Enum(),
613 Unit: proto.String("seconds"),
614 Metric: []*dto.Metric{},
615 },
616 options: []EncoderOption{WithUnit()},
617 out: `# HELP name_seconds doc string
618 # TYPE name_seconds counter
619 # UNIT name_seconds seconds
620 `,
621 },
622
623 {
624 in: &dto.MetricFamily{
625 Name: proto.String("request_duration_microseconds"),
626 Help: proto.String("The response latency."),
627 Type: dto.MetricType_HISTOGRAM.Enum(),
628 Unit: proto.String("microseconds"),
629 Metric: []*dto.Metric{
630 {
631 Histogram: &dto.Histogram{
632 SampleCount: proto.Uint64(2693),
633 SampleSum: proto.Float64(1756047.3),
634 Bucket: []*dto.Bucket{
635 {
636 UpperBound: proto.Float64(100),
637 CumulativeCount: proto.Uint64(123),
638 },
639 {
640 UpperBound: proto.Float64(120),
641 CumulativeCount: proto.Uint64(412),
642 },
643 {
644 UpperBound: proto.Float64(144),
645 CumulativeCount: proto.Uint64(592),
646 },
647 {
648 UpperBound: proto.Float64(172.8),
649 CumulativeCount: proto.Uint64(1524),
650 },
651 {
652 UpperBound: proto.Float64(math.Inf(+1)),
653 CumulativeCount: proto.Uint64(2693),
654 },
655 },
656 },
657 },
658 },
659 },
660 out: `# HELP request_duration_microseconds The response latency.
661 # TYPE request_duration_microseconds histogram
662 request_duration_microseconds_bucket{le="100.0"} 123
663 request_duration_microseconds_bucket{le="120.0"} 412
664 request_duration_microseconds_bucket{le="144.0"} 592
665 request_duration_microseconds_bucket{le="172.8"} 1524
666 request_duration_microseconds_bucket{le="+Inf"} 2693
667 request_duration_microseconds_sum 1.7560473e+06
668 request_duration_microseconds_count 2693
669 `,
670 },
671
672 {
673 in: &dto.MetricFamily{
674 Name: proto.String("name_total"),
675 Help: proto.String("doc string"),
676 Type: dto.MetricType_COUNTER.Enum(),
677 Unit: proto.String("seconds"),
678 Metric: []*dto.Metric{},
679 },
680 options: []EncoderOption{WithUnit()},
681 out: `# HELP name_seconds doc string
682 # TYPE name_seconds counter
683 # UNIT name_seconds seconds
684 `,
685 },
686
687 {
688 in: &dto.MetricFamily{
689 Name: proto.String("name_total"),
690 Help: proto.String("doc string"),
691 Type: dto.MetricType_COUNTER.Enum(),
692 Metric: []*dto.Metric{},
693 },
694 options: []EncoderOption{WithUnit()},
695 out: `# HELP name doc string
696 # TYPE name counter
697 `,
698 },
699
700 {
701 in: &dto.MetricFamily{
702 Name: proto.String("some_measure_total"),
703 Help: proto.String("some testing measurement"),
704 Type: dto.MetricType_COUNTER.Enum(),
705 Unit: proto.String("seconds"),
706 Metric: []*dto.Metric{
707 {
708 Label: []*dto.LabelPair{
709 {
710 Name: proto.String("labelname"),
711 Value: proto.String("val1"),
712 },
713 {
714 Name: proto.String("basename"),
715 Value: proto.String("basevalue"),
716 },
717 },
718 Counter: &dto.Counter{
719 Value: proto.Float64(42),
720 },
721 },
722 {
723 Label: []*dto.LabelPair{
724 {
725 Name: proto.String("labelname"),
726 Value: proto.String("val2"),
727 },
728 {
729 Name: proto.String("basename"),
730 Value: proto.String("basevalue"),
731 },
732 },
733 Counter: &dto.Counter{
734 Value: proto.Float64(.23),
735 },
736 TimestampMs: proto.Int64(1234567890),
737 },
738 },
739 },
740 options: []EncoderOption{WithUnit()},
741 out: `# HELP some_measure_seconds some testing measurement
742 # TYPE some_measure_seconds counter
743 # UNIT some_measure_seconds seconds
744 some_measure_seconds_total{labelname="val1",basename="basevalue"} 42.0
745 some_measure_seconds_total{labelname="val2",basename="basevalue"} 0.23 1.23456789e+06
746 `,
747 },
748 }
749
750 for i, scenario := range scenarios {
751 out := bytes.NewBuffer(make([]byte, 0, len(scenario.out)))
752 n, err := MetricFamilyToOpenMetrics(out, scenario.in, scenario.options...)
753 if err != nil {
754 t.Errorf("%d. error: %s", i, err)
755 continue
756 }
757 if expected, got := len(scenario.out), n; expected != got {
758 t.Errorf(
759 "%d. expected %d bytes written, got %d",
760 i, expected, got,
761 )
762 }
763 if expected, got := scenario.out, out.String(); expected != got {
764 t.Errorf(
765 "%d. expected out=%q, got %q",
766 i, expected, got,
767 )
768 }
769 }
770 }
771
772 func BenchmarkOpenMetricsCreate(b *testing.B) {
773 mf := &dto.MetricFamily{
774 Name: proto.String("request_duration_microseconds"),
775 Help: proto.String("The response latency."),
776 Type: dto.MetricType_HISTOGRAM.Enum(),
777 Metric: []*dto.Metric{
778 {
779 Label: []*dto.LabelPair{
780 {
781 Name: proto.String("name_1"),
782 Value: proto.String("val with\nnew line"),
783 },
784 {
785 Name: proto.String("name_2"),
786 Value: proto.String("val with \\backslash and \"quotes\""),
787 },
788 {
789 Name: proto.String("name_3"),
790 Value: proto.String("Just a quite long label value to test performance."),
791 },
792 },
793 Histogram: &dto.Histogram{
794 SampleCount: proto.Uint64(2693),
795 SampleSum: proto.Float64(1756047.3),
796 Bucket: []*dto.Bucket{
797 {
798 UpperBound: proto.Float64(100),
799 CumulativeCount: proto.Uint64(123),
800 },
801 {
802 UpperBound: proto.Float64(120),
803 CumulativeCount: proto.Uint64(412),
804 },
805 {
806 UpperBound: proto.Float64(144),
807 CumulativeCount: proto.Uint64(592),
808 },
809 {
810 UpperBound: proto.Float64(172.8),
811 CumulativeCount: proto.Uint64(1524),
812 },
813 {
814 UpperBound: proto.Float64(math.Inf(+1)),
815 CumulativeCount: proto.Uint64(2693),
816 },
817 },
818 },
819 },
820 {
821 Label: []*dto.LabelPair{
822 {
823 Name: proto.String("name_1"),
824 Value: proto.String("Björn"),
825 },
826 {
827 Name: proto.String("name_2"),
828 Value: proto.String("佖佥"),
829 },
830 {
831 Name: proto.String("name_3"),
832 Value: proto.String("Just a quite long label value to test performance."),
833 },
834 },
835 Histogram: &dto.Histogram{
836 SampleCount: proto.Uint64(5699),
837 SampleSum: proto.Float64(49484343543.4343),
838 Bucket: []*dto.Bucket{
839 {
840 UpperBound: proto.Float64(100),
841 CumulativeCount: proto.Uint64(120),
842 },
843 {
844 UpperBound: proto.Float64(120),
845 CumulativeCount: proto.Uint64(412),
846 },
847 {
848 UpperBound: proto.Float64(144),
849 CumulativeCount: proto.Uint64(596),
850 },
851 {
852 UpperBound: proto.Float64(172.8),
853 CumulativeCount: proto.Uint64(1535),
854 },
855 },
856 },
857 TimestampMs: proto.Int64(1234567890),
858 },
859 },
860 }
861 out := bytes.NewBuffer(make([]byte, 0, 1024))
862
863 for i := 0; i < b.N; i++ {
864 _, err := MetricFamilyToOpenMetrics(out, mf)
865 if err != nil {
866 b.Fatal(err)
867 }
868 out.Reset()
869 }
870 }
871
872 func TestOpenMetricsCreateError(t *testing.T) {
873 scenarios := []struct {
874 in *dto.MetricFamily
875 err string
876 }{
877
878 {
879 in: &dto.MetricFamily{
880 Help: proto.String("doc string"),
881 Type: dto.MetricType_UNTYPED.Enum(),
882 Metric: []*dto.Metric{
883 {
884 Untyped: &dto.Untyped{
885 Value: proto.Float64(math.Inf(-1)),
886 },
887 },
888 },
889 },
890 err: "MetricFamily has no name",
891 },
892
893 {
894 in: &dto.MetricFamily{
895 Name: proto.String("name"),
896 Help: proto.String("doc string"),
897 Type: dto.MetricType_COUNTER.Enum(),
898 Metric: []*dto.Metric{
899 {
900 Untyped: &dto.Untyped{
901 Value: proto.Float64(math.Inf(-1)),
902 },
903 },
904 },
905 },
906 err: "expected counter in metric",
907 },
908 }
909
910 for i, scenario := range scenarios {
911 var out bytes.Buffer
912 _, err := MetricFamilyToOpenMetrics(&out, scenario.in)
913 if err == nil {
914 t.Errorf("%d. expected error, got nil", i)
915 continue
916 }
917 if expected, got := scenario.err, err.Error(); strings.Index(got, expected) != 0 {
918 t.Errorf(
919 "%d. expected error starting with %q, got %q",
920 i, expected, got,
921 )
922 }
923 }
924 }
925
View as plain text