1#[allow(missing_docs, clippy::derive_partial_eq_without_eq)]
27pub mod openmetrics_data_model {
30 include!(concat!(env!("OUT_DIR"), "/openmetrics.rs"));
31}
32
33use std::{borrow::Cow, collections::HashMap};
34
35use crate::metrics::MetricType;
36use crate::registry::{Registry, Unit};
37use crate::{metrics::exemplar::Exemplar, registry::Prefix};
38
39use super::{EncodeCounterValue, EncodeExemplarValue, EncodeGaugeValue, EncodeLabelSet};
40
41pub fn encode(registry: &Registry) -> Result<openmetrics_data_model::MetricSet, std::fmt::Error> {
44 let mut metric_set = openmetrics_data_model::MetricSet::default();
45 let mut descriptor_encoder = DescriptorEncoder::new(&mut metric_set.metric_families).into();
46 registry.encode(&mut descriptor_encoder)?;
47 Ok(metric_set)
48}
49
50impl From<MetricType> for openmetrics_data_model::MetricType {
51 fn from(m: MetricType) -> Self {
52 match m {
53 MetricType::Counter => openmetrics_data_model::MetricType::Counter,
54 MetricType::Gauge => openmetrics_data_model::MetricType::Gauge,
55 MetricType::Histogram => openmetrics_data_model::MetricType::Histogram,
56 MetricType::Info => openmetrics_data_model::MetricType::Info,
57 MetricType::Unknown => openmetrics_data_model::MetricType::Unknown,
58 }
59 }
60}
61
62#[derive(Debug)]
66pub(crate) struct DescriptorEncoder<'a> {
67 metric_families: &'a mut Vec<openmetrics_data_model::MetricFamily>,
68 prefix: Option<&'a Prefix>,
69 labels: &'a [(Cow<'static, str>, Cow<'static, str>)],
70}
71
72impl DescriptorEncoder<'_> {
73 pub(crate) fn new(
74 metric_families: &mut Vec<openmetrics_data_model::MetricFamily>,
75 ) -> DescriptorEncoder {
76 DescriptorEncoder {
77 metric_families,
78 prefix: Default::default(),
79 labels: Default::default(),
80 }
81 }
82
83 pub(crate) fn with_prefix_and_labels<'s>(
84 &'s mut self,
85 prefix: Option<&'s Prefix>,
86 labels: &'s [(Cow<'static, str>, Cow<'static, str>)],
87 ) -> DescriptorEncoder<'s> {
88 DescriptorEncoder {
89 prefix,
90 labels,
91 metric_families: self.metric_families,
92 }
93 }
94
95 pub fn encode_descriptor<'s>(
96 &'s mut self,
97 name: &str,
98 help: &str,
99 unit: Option<&Unit>,
100 metric_type: MetricType,
101 ) -> Result<MetricEncoder<'s>, std::fmt::Error> {
102 let family = openmetrics_data_model::MetricFamily {
103 name: {
104 match self.prefix {
105 Some(prefix) => prefix.as_str().to_string() + "_" + name,
106 None => name.to_string(),
107 }
108 },
109 r#type: {
110 let metric_type: openmetrics_data_model::MetricType = metric_type.into();
111 metric_type as i32
112 },
113 unit: if let Some(unit) = unit {
114 unit.as_str().to_string()
115 } else {
116 String::new()
117 },
118 help: help.to_string(),
119 ..Default::default()
120 };
121 let mut labels = vec![];
122 self.labels.encode(
123 LabelSetEncoder {
124 labels: &mut labels,
125 }
126 .into(),
127 )?;
128 self.metric_families.push(family);
129
130 Ok(MetricEncoder {
131 family: &mut self
132 .metric_families
133 .last_mut()
134 .expect("previous push")
135 .metrics,
136 metric_type,
137 labels,
138 })
139 }
140}
141
142#[derive(Debug)]
146pub(crate) struct MetricEncoder<'f> {
147 metric_type: MetricType,
149 family: &'f mut Vec<openmetrics_data_model::Metric>,
151 labels: Vec<openmetrics_data_model::Label>,
153}
154
155impl MetricEncoder<'_> {
156 pub fn encode_counter<
157 S: EncodeLabelSet,
158 CounterValue: EncodeCounterValue,
159 ExemplarValue: EncodeExemplarValue,
160 >(
161 &mut self,
162 v: &CounterValue,
163 exemplar: Option<&Exemplar<S, ExemplarValue>>,
164 ) -> Result<(), std::fmt::Error> {
165 let mut value = openmetrics_data_model::counter_value::Total::IntValue(0);
166 let mut e = CounterValueEncoder { value: &mut value }.into();
167 v.encode(&mut e)?;
168
169 self.family.push(openmetrics_data_model::Metric {
170 labels: self.labels.clone(),
171 metric_points: vec![openmetrics_data_model::MetricPoint {
172 value: Some(openmetrics_data_model::metric_point::Value::CounterValue(
173 openmetrics_data_model::CounterValue {
174 total: Some(value),
175 exemplar: exemplar.map(|e| e.try_into()).transpose()?,
176 ..Default::default()
177 },
178 )),
179 ..Default::default()
180 }],
181 });
182
183 Ok(())
184 }
185
186 pub fn encode_gauge<GaugeValue: EncodeGaugeValue>(
187 &mut self,
188 v: &GaugeValue,
189 ) -> Result<(), std::fmt::Error> {
190 let mut value = openmetrics_data_model::gauge_value::Value::IntValue(0);
191 let mut e = GaugeValueEncoder { value: &mut value }.into();
192 v.encode(&mut e)?;
193
194 self.family.push(openmetrics_data_model::Metric {
195 labels: self.labels.clone(),
196 metric_points: vec![openmetrics_data_model::MetricPoint {
197 value: Some(openmetrics_data_model::metric_point::Value::GaugeValue(
198 openmetrics_data_model::GaugeValue { value: Some(value) },
199 )),
200 ..Default::default()
201 }],
202 });
203
204 Ok(())
205 }
206
207 pub fn encode_info(
208 &mut self,
209 label_set: &impl super::EncodeLabelSet,
210 ) -> Result<(), std::fmt::Error> {
211 let mut info_labels = vec![];
212 label_set.encode(
213 LabelSetEncoder {
214 labels: &mut info_labels,
215 }
216 .into(),
217 )?;
218
219 self.family.push(openmetrics_data_model::Metric {
220 labels: self.labels.clone(),
221 metric_points: vec![openmetrics_data_model::MetricPoint {
222 value: Some(openmetrics_data_model::metric_point::Value::InfoValue(
223 openmetrics_data_model::InfoValue { info: info_labels },
224 )),
225 ..Default::default()
226 }],
227 });
228
229 Ok(())
230 }
231
232 pub fn encode_family<S: EncodeLabelSet>(
233 &mut self,
234 label_set: &S,
235 ) -> Result<MetricEncoder, std::fmt::Error> {
236 let mut labels = self.labels.clone();
237 label_set.encode(
238 LabelSetEncoder {
239 labels: &mut labels,
240 }
241 .into(),
242 )?;
243
244 Ok(MetricEncoder {
245 metric_type: self.metric_type,
246 family: self.family,
247 labels,
248 })
249 }
250
251 pub fn encode_histogram<S: EncodeLabelSet>(
252 &mut self,
253 sum: f64,
254 count: u64,
255 buckets: &[(f64, u64)],
256 exemplars: Option<&HashMap<usize, Exemplar<S, f64>>>,
257 ) -> Result<(), std::fmt::Error> {
258 let buckets = buckets
259 .iter()
260 .enumerate()
261 .map(|(i, (upper_bound, count))| {
262 Ok(openmetrics_data_model::histogram_value::Bucket {
263 upper_bound: *upper_bound,
264 count: *count,
265 exemplar: exemplars
266 .and_then(|exemplars| exemplars.get(&i).map(|exemplar| exemplar.try_into()))
267 .transpose()?,
268 })
269 })
270 .collect::<Result<Vec<_>, std::fmt::Error>>()?;
271
272 self.family.push(openmetrics_data_model::Metric {
273 labels: self.labels.clone(),
274 metric_points: vec![openmetrics_data_model::MetricPoint {
275 value: Some(openmetrics_data_model::metric_point::Value::HistogramValue(
276 openmetrics_data_model::HistogramValue {
277 count,
278 created: None,
279 buckets,
280 sum: Some(openmetrics_data_model::histogram_value::Sum::DoubleValue(
281 sum,
282 )),
283 },
284 )),
285 ..Default::default()
286 }],
287 });
288
289 Ok(())
290 }
291}
292
293impl<S: EncodeLabelSet, V: EncodeExemplarValue> TryFrom<&Exemplar<S, V>>
294 for openmetrics_data_model::Exemplar
295{
296 type Error = std::fmt::Error;
297
298 fn try_from(exemplar: &Exemplar<S, V>) -> Result<Self, Self::Error> {
299 let mut value = f64::default();
300 exemplar
301 .value
302 .encode(ExemplarValueEncoder { value: &mut value }.into())?;
303
304 let mut labels = vec![];
305 exemplar.label_set.encode(
306 LabelSetEncoder {
307 labels: &mut labels,
308 }
309 .into(),
310 )?;
311
312 Ok(openmetrics_data_model::Exemplar {
313 value,
314 timestamp: Default::default(),
315 label: labels,
316 })
317 }
318}
319
320#[derive(Debug)]
321pub(crate) struct GaugeValueEncoder<'a> {
322 value: &'a mut openmetrics_data_model::gauge_value::Value,
323}
324
325impl GaugeValueEncoder<'_> {
326 pub fn encode_u32(&mut self, v: u32) -> Result<(), std::fmt::Error> {
327 self.encode_i64(v as i64)
328 }
329
330 pub fn encode_i64(&mut self, v: i64) -> Result<(), std::fmt::Error> {
331 *self.value = openmetrics_data_model::gauge_value::Value::IntValue(v);
332 Ok(())
333 }
334
335 pub fn encode_f64(&mut self, v: f64) -> Result<(), std::fmt::Error> {
336 *self.value = openmetrics_data_model::gauge_value::Value::DoubleValue(v);
337 Ok(())
338 }
339}
340
341#[derive(Debug)]
342pub(crate) struct ExemplarValueEncoder<'a> {
343 value: &'a mut f64,
344}
345
346impl ExemplarValueEncoder<'_> {
347 pub fn encode(&mut self, v: f64) -> Result<(), std::fmt::Error> {
348 *self.value = v;
349 Ok(())
350 }
351}
352
353impl<K: ToString, V: ToString> From<&(K, V)> for openmetrics_data_model::Label {
354 fn from(kv: &(K, V)) -> Self {
355 openmetrics_data_model::Label {
356 name: kv.0.to_string(),
357 value: kv.1.to_string(),
358 }
359 }
360}
361
362#[derive(Debug)]
363pub(crate) struct CounterValueEncoder<'a> {
364 value: &'a mut openmetrics_data_model::counter_value::Total,
365}
366
367impl CounterValueEncoder<'_> {
368 pub fn encode_f64(&mut self, v: f64) -> Result<(), std::fmt::Error> {
369 *self.value = openmetrics_data_model::counter_value::Total::DoubleValue(v);
370 Ok(())
371 }
372
373 pub fn encode_u64(&mut self, v: u64) -> Result<(), std::fmt::Error> {
374 *self.value = openmetrics_data_model::counter_value::Total::IntValue(v);
375 Ok(())
376 }
377}
378
379#[derive(Debug)]
380pub(crate) struct LabelSetEncoder<'a> {
381 labels: &'a mut Vec<openmetrics_data_model::Label>,
382}
383
384impl LabelSetEncoder<'_> {
385 pub fn encode_label(&mut self) -> LabelEncoder {
386 LabelEncoder {
387 labels: self.labels,
388 }
389 }
390}
391
392#[derive(Debug)]
393pub(crate) struct LabelEncoder<'a> {
394 labels: &'a mut Vec<openmetrics_data_model::Label>,
395}
396
397impl LabelEncoder<'_> {
398 pub fn encode_label_key(&mut self) -> Result<LabelKeyEncoder, std::fmt::Error> {
399 self.labels.push(openmetrics_data_model::Label::default());
400
401 Ok(LabelKeyEncoder {
402 label: self.labels.last_mut().expect("To find pushed label."),
403 })
404 }
405}
406
407#[derive(Debug)]
408pub(crate) struct LabelKeyEncoder<'a> {
409 label: &'a mut openmetrics_data_model::Label,
410}
411
412impl std::fmt::Write for LabelKeyEncoder<'_> {
413 fn write_str(&mut self, s: &str) -> std::fmt::Result {
414 self.label.name.write_str(s)
415 }
416}
417
418impl<'a> LabelKeyEncoder<'a> {
419 pub fn encode_label_value(self) -> Result<LabelValueEncoder<'a>, std::fmt::Error> {
420 Ok(LabelValueEncoder {
421 label_value: &mut self.label.value,
422 })
423 }
424}
425
426#[derive(Debug)]
427pub(crate) struct LabelValueEncoder<'a> {
428 label_value: &'a mut String,
429}
430
431impl LabelValueEncoder<'_> {
432 pub fn finish(self) -> Result<(), std::fmt::Error> {
433 Ok(())
434 }
435}
436
437impl std::fmt::Write for LabelValueEncoder<'_> {
438 fn write_str(&mut self, s: &str) -> std::fmt::Result {
439 self.label_value.write_str(s)
440 }
441}
442
443#[cfg(test)]
444mod tests {
445 use super::*;
446 use crate::metrics::counter::Counter;
447 use crate::metrics::exemplar::{CounterWithExemplar, HistogramWithExemplars};
448 use crate::metrics::family::Family;
449 use crate::metrics::gauge::Gauge;
450 use crate::metrics::histogram::{exponential_buckets, Histogram};
451 use crate::metrics::info::Info;
452 use crate::registry::Unit;
453 use std::borrow::Cow;
454 use std::collections::HashSet;
455 use std::sync::atomic::AtomicI64;
456 use std::sync::atomic::AtomicU64;
457
458 #[test]
459 fn encode_counter_int() {
460 let counter: Counter = Counter::default();
461 let mut registry = Registry::default();
462 registry.register("my_counter", "My counter", counter.clone());
463 counter.inc();
464
465 let metric_set = encode(®istry).unwrap();
466
467 let family = metric_set.metric_families.first().unwrap();
468 assert_eq!("my_counter", family.name);
469 assert_eq!("My counter.", family.help);
470
471 assert_eq!(
472 openmetrics_data_model::MetricType::Counter as i32,
473 extract_metric_type(&metric_set)
474 );
475
476 match extract_metric_point_value(&metric_set) {
477 openmetrics_data_model::metric_point::Value::CounterValue(value) => {
478 let expected = openmetrics_data_model::counter_value::Total::IntValue(1);
479 assert_eq!(Some(expected), value.total);
480 assert_eq!(None, value.exemplar);
481 assert_eq!(None, value.created);
482 }
483 _ => panic!("wrong value type"),
484 }
485 }
486
487 #[test]
488 fn encode_counter_double() {
489 let counter: Counter<f64> = Counter::default();
491 let mut registry = Registry::default();
492 registry.register("my_counter", "My counter", counter.clone());
493 counter.inc();
494
495 let metric_set = encode(®istry).unwrap();
496
497 let family = metric_set.metric_families.first().unwrap();
498 assert_eq!("my_counter", family.name);
499 assert_eq!("My counter.", family.help);
500
501 assert_eq!(
502 openmetrics_data_model::MetricType::Counter as i32,
503 extract_metric_type(&metric_set)
504 );
505
506 match extract_metric_point_value(&metric_set) {
507 openmetrics_data_model::metric_point::Value::CounterValue(value) => {
508 let expected = openmetrics_data_model::counter_value::Total::DoubleValue(1.0);
510 assert_eq!(Some(expected), value.total);
511 assert_eq!(None, value.exemplar);
512 assert_eq!(None, value.created);
513 }
514 _ => panic!("wrong value type"),
515 }
516 }
517
518 #[test]
519 fn encode_counter_with_unit() {
520 let mut registry = Registry::default();
521 let counter: Counter = Counter::default();
522 registry.register_with_unit("my_counter", "My counter", Unit::Seconds, counter);
523
524 let metric_set = encode(®istry).unwrap();
525
526 let family = metric_set.metric_families.first().unwrap();
527 assert_eq!("my_counter", family.name);
528 assert_eq!("My counter.", family.help);
529 assert_eq!("seconds", family.unit);
530 }
531
532 #[test]
533 fn encode_counter_with_exemplar() {
534 let mut registry = Registry::default();
535
536 let counter_with_exemplar: CounterWithExemplar<Vec<(String, f64)>, f64> =
537 CounterWithExemplar::default();
538 registry.register(
539 "my_counter_with_exemplar",
540 "My counter with exemplar",
541 counter_with_exemplar.clone(),
542 );
543
544 counter_with_exemplar.inc_by(1.0, Some(vec![("user_id".to_string(), 42.0)]));
545
546 let metric_set = encode(®istry).unwrap();
547
548 let family = metric_set.metric_families.first().unwrap();
549 assert_eq!("my_counter_with_exemplar", family.name);
550 assert_eq!("My counter with exemplar.", family.help);
551
552 assert_eq!(
553 openmetrics_data_model::MetricType::Counter as i32,
554 extract_metric_type(&metric_set)
555 );
556
557 match extract_metric_point_value(&metric_set) {
558 openmetrics_data_model::metric_point::Value::CounterValue(value) => {
559 let expected = openmetrics_data_model::counter_value::Total::DoubleValue(1.0);
561 assert_eq!(Some(expected), value.total);
562
563 let exemplar = value.exemplar.as_ref().unwrap();
564 assert_eq!(1.0, exemplar.value);
565
566 let expected_label = {
567 openmetrics_data_model::Label {
568 name: "user_id".to_string(),
569 value: "42.0".to_string(),
570 }
571 };
572 assert_eq!(vec![expected_label], exemplar.label);
573 }
574 _ => panic!("wrong value type"),
575 }
576 }
577
578 #[test]
579 fn encode_gauge() {
580 let mut registry = Registry::default();
581 let gauge = Gauge::<i64, AtomicI64>::default();
582 registry.register("my_gauge", "My gauge", gauge.clone());
583 gauge.inc();
584
585 let metric_set = encode(®istry).unwrap();
586 let family = metric_set.metric_families.first().unwrap();
587 assert_eq!("my_gauge", family.name);
588 assert_eq!("My gauge.", family.help);
589
590 assert_eq!(
591 openmetrics_data_model::MetricType::Gauge as i32,
592 extract_metric_type(&metric_set)
593 );
594
595 match extract_metric_point_value(&metric_set) {
596 openmetrics_data_model::metric_point::Value::GaugeValue(value) => {
597 let expected = openmetrics_data_model::gauge_value::Value::IntValue(1);
598 assert_eq!(Some(expected), value.value);
599 }
600 _ => panic!("wrong value type"),
601 }
602 }
603
604 #[test]
605 fn encode_gauge_u64_normal() {
606 let mut registry = Registry::default();
607 let gauge = Gauge::<u64, AtomicU64>::default();
608 registry.register("my_gauge", "My gauge", gauge.clone());
609 gauge.set(12345);
610
611 let metric_set = encode(®istry).unwrap();
612 let family = metric_set.metric_families.first().unwrap();
613 assert_eq!("my_gauge", family.name);
614 assert_eq!("My gauge.", family.help);
615
616 assert_eq!(
617 openmetrics_data_model::MetricType::Gauge as i32,
618 extract_metric_type(&metric_set)
619 );
620
621 match extract_metric_point_value(&metric_set) {
622 openmetrics_data_model::metric_point::Value::GaugeValue(value) => {
623 let expected = openmetrics_data_model::gauge_value::Value::IntValue(12345);
624 assert_eq!(Some(expected), value.value);
625 }
626 _ => panic!("wrong value type"),
627 }
628 }
629
630 #[test]
631 fn encode_gauge_u64_max() {
632 let mut registry = Registry::default();
633 let gauge = Gauge::<u64, AtomicU64>::default();
634 registry.register("my_gauge", "My gauge", gauge.clone());
635 gauge.set(u64::MAX);
636
637 assert!(encode(®istry).is_err());
639 }
640
641 #[test]
642 fn encode_counter_family() {
643 let mut registry = Registry::default();
644 let family = Family::<Vec<(String, String)>, Counter>::default();
645 registry.register("my_counter_family", "My counter family", family.clone());
646
647 family
648 .get_or_create(&vec![
649 ("method".to_string(), "GET".to_string()),
650 ("status".to_string(), "200".to_string()),
651 ])
652 .inc();
653
654 family
655 .get_or_create(&vec![
656 ("method".to_string(), "POST".to_string()),
657 ("status".to_string(), "200".to_string()),
658 ])
659 .inc();
660
661 let metric_set = encode(®istry).unwrap();
662
663 let family = metric_set.metric_families.first().unwrap();
664 assert_eq!("my_counter_family", family.name);
665 assert_eq!("My counter family.", family.help);
666
667 assert_eq!(
668 openmetrics_data_model::MetricType::Counter as i32,
669 extract_metric_type(&metric_set)
670 );
671
672 let mut potential_method_value = HashSet::new();
675 potential_method_value.insert("GET");
676 potential_method_value.insert("POST");
677
678 let metric = family.metrics.first().unwrap();
680 assert_eq!(2, metric.labels.len());
681 assert_eq!("method", metric.labels[0].name);
682 assert!(potential_method_value.remove(&metric.labels[0].value.as_str()));
683 assert_eq!("status", metric.labels[1].name);
684 assert_eq!("200", metric.labels[1].value);
685
686 match extract_metric_point_value(&metric_set) {
687 openmetrics_data_model::metric_point::Value::CounterValue(value) => {
688 let expected = openmetrics_data_model::counter_value::Total::IntValue(1);
689 assert_eq!(Some(expected), value.total);
690 assert_eq!(None, value.exemplar);
691 assert_eq!(None, value.created);
692 }
693 _ => panic!("wrong value type"),
694 }
695
696 let metric2 = &family.metrics[1];
698 assert_eq!(2, metric2.labels.len());
699 assert_eq!("method", metric2.labels[0].name);
700 assert!(potential_method_value.remove(&metric2.labels[0].value.as_str()));
701 assert_eq!("status", metric2.labels[1].name);
702 assert_eq!("200", metric2.labels[1].value);
703 }
704
705 #[test]
706 fn encode_counter_family_with_prefix_with_label() {
707 let mut registry = Registry::default();
708 let sub_registry = registry.sub_registry_with_prefix("my_prefix");
709 let sub_sub_registry = sub_registry
710 .sub_registry_with_label((Cow::Borrowed("my_key"), Cow::Borrowed("my_value")));
711 let family = Family::<Vec<(String, String)>, Counter>::default();
712 sub_sub_registry.register("my_counter_family", "My counter family", family.clone());
713
714 family
715 .get_or_create(&vec![
716 ("method".to_string(), "GET".to_string()),
717 ("status".to_string(), "200".to_string()),
718 ])
719 .inc();
720
721 let metric_set = encode(®istry).unwrap();
722
723 let family = metric_set.metric_families.first().unwrap();
724 assert_eq!("my_prefix_my_counter_family", family.name);
725 assert_eq!("My counter family.", family.help);
726
727 assert_eq!(
728 openmetrics_data_model::MetricType::Counter as i32,
729 extract_metric_type(&metric_set)
730 );
731
732 let metric = family.metrics.first().unwrap();
733 assert_eq!(3, metric.labels.len());
734 assert_eq!("my_key", metric.labels[0].name);
735 assert_eq!("my_value", metric.labels[0].value);
736 assert_eq!("method", metric.labels[1].name);
737 assert_eq!("GET", metric.labels[1].value);
738 assert_eq!("status", metric.labels[2].name);
739 assert_eq!("200", metric.labels[2].value);
740
741 match extract_metric_point_value(&metric_set) {
742 openmetrics_data_model::metric_point::Value::CounterValue(value) => {
743 let expected = openmetrics_data_model::counter_value::Total::IntValue(1);
744 assert_eq!(Some(expected), value.total);
745 assert_eq!(None, value.exemplar);
746 assert_eq!(None, value.created);
747 }
748 _ => panic!("wrong value type"),
749 }
750 }
751
752 #[test]
753 fn encode_histogram() {
754 let mut registry = Registry::default();
755 let histogram = Histogram::new(exponential_buckets(1.0, 2.0, 10));
756 registry.register("my_histogram", "My histogram", histogram.clone());
757 histogram.observe(1.0);
758
759 let metric_set = encode(®istry).unwrap();
760
761 let family = metric_set.metric_families.first().unwrap();
762 assert_eq!("my_histogram", family.name);
763 assert_eq!("My histogram.", family.help);
764
765 assert_eq!(
766 openmetrics_data_model::MetricType::Histogram as i32,
767 extract_metric_type(&metric_set)
768 );
769
770 match extract_metric_point_value(&metric_set) {
771 openmetrics_data_model::metric_point::Value::HistogramValue(value) => {
772 assert_eq!(
773 Some(openmetrics_data_model::histogram_value::Sum::DoubleValue(
774 1.0
775 )),
776 value.sum
777 );
778 assert_eq!(1, value.count);
779 assert_eq!(11, value.buckets.len());
780 }
781 _ => panic!("wrong value type"),
782 }
783 }
784
785 #[test]
786 fn encode_histogram_with_exemplars() {
787 let mut registry = Registry::default();
788 let histogram = HistogramWithExemplars::new(exponential_buckets(1.0, 2.0, 10));
789 registry.register("my_histogram", "My histogram", histogram.clone());
790 histogram.observe(1.0, Some(vec![("user_id".to_string(), 42u64)]));
791
792 let metric_set = encode(®istry).unwrap();
793
794 let family = metric_set.metric_families.first().unwrap();
795 assert_eq!("my_histogram", family.name);
796 assert_eq!("My histogram.", family.help);
797
798 assert_eq!(
799 openmetrics_data_model::MetricType::Histogram as i32,
800 extract_metric_type(&metric_set)
801 );
802
803 match extract_metric_point_value(&metric_set) {
804 openmetrics_data_model::metric_point::Value::HistogramValue(value) => {
805 let exemplar = value.buckets.first().unwrap().exemplar.as_ref().unwrap();
806 assert_eq!(1.0, exemplar.value);
807
808 let expected_label = {
809 openmetrics_data_model::Label {
810 name: "user_id".to_string(),
811 value: "42".to_string(),
812 }
813 };
814 assert_eq!(vec![expected_label], exemplar.label);
815 }
816 _ => panic!("wrong value type"),
817 }
818 }
819
820 #[test]
821 fn encode_family_counter_histogram() {
822 let mut registry = Registry::default();
823
824 let counter_family = Family::<Vec<(String, String)>, Counter>::default();
825 let histogram_family =
826 Family::<Vec<(String, String)>, Histogram>::new_with_constructor(|| {
827 Histogram::new(exponential_buckets(1.0, 2.0, 10))
828 });
829
830 registry.register("my_counter", "My counter", counter_family.clone());
831 registry.register("my_histogram", "My histogram", histogram_family.clone());
832
833 counter_family
834 .get_or_create(&vec![("path".to_string(), "/".to_string())])
835 .inc();
836
837 histogram_family
838 .get_or_create(&vec![("path".to_string(), "/".to_string())])
839 .observe(1.0);
840
841 let metric_set = encode(®istry).unwrap();
842 assert_eq!("my_counter", metric_set.metric_families[0].name);
843 assert_eq!("my_histogram", metric_set.metric_families[1].name);
844 }
845
846 #[test]
847 fn encode_family_and_counter_and_histogram() {
848 let mut registry = Registry::default();
849
850 let counter_family = Family::<Vec<(String, String)>, Counter>::default();
852 let histogram_family =
853 Family::<Vec<(String, String)>, Histogram>::new_with_constructor(|| {
854 Histogram::new(exponential_buckets(1.0, 2.0, 10))
855 });
856
857 registry.register("my_family_counter", "My counter", counter_family.clone());
858 registry.register(
859 "my_family_histogram",
860 "My histogram",
861 histogram_family.clone(),
862 );
863
864 counter_family
865 .get_or_create(&vec![("path".to_string(), "/".to_string())])
866 .inc();
867
868 histogram_family
869 .get_or_create(&vec![("path".to_string(), "/".to_string())])
870 .observe(1.0);
871
872 let counter: Counter = Counter::default();
874 registry.register("my_counter", "My counter", counter.clone());
875 counter.inc();
876
877 let histogram = Histogram::new(exponential_buckets(1.0, 2.0, 10));
879 registry.register("my_histogram", "My histogram", histogram.clone());
880 histogram.observe(1.0);
881
882 let metric_set = encode(®istry).unwrap();
883 assert_eq!("my_family_counter", metric_set.metric_families[0].name);
884 assert_eq!("my_family_histogram", metric_set.metric_families[1].name);
885 }
886
887 #[test]
888 fn encode_info() {
889 let mut registry = Registry::default();
890 let info = Info::new(vec![("os".to_string(), "GNU/linux".to_string())]);
891 registry.register("my_info_metric", "My info metric", info);
892
893 let metric_set = encode(®istry).unwrap();
894
895 let family = metric_set.metric_families.first().unwrap();
896 assert_eq!("my_info_metric", family.name);
897 assert_eq!("My info metric.", family.help);
898
899 assert_eq!(
900 openmetrics_data_model::MetricType::Info as i32,
901 extract_metric_type(&metric_set)
902 );
903
904 match extract_metric_point_value(&metric_set) {
905 openmetrics_data_model::metric_point::Value::InfoValue(value) => {
906 assert_eq!(1, value.info.len());
907
908 let info = value.info.first().unwrap();
909 assert_eq!("os", info.name);
910 assert_eq!("GNU/linux", info.value);
911 }
912 _ => panic!("wrong value type"),
913 }
914 }
915
916 fn extract_metric_type(metric_set: &openmetrics_data_model::MetricSet) -> i32 {
917 let family = metric_set.metric_families.first().unwrap();
918 family.r#type
919 }
920
921 fn extract_metric_point_value(
922 metric_set: &openmetrics_data_model::MetricSet,
923 ) -> openmetrics_data_model::metric_point::Value {
924 let metric = metric_set
925 .metric_families
926 .first()
927 .unwrap()
928 .metrics
929 .first()
930 .unwrap();
931
932 metric
933 .metric_points
934 .first()
935 .unwrap()
936 .value
937 .as_ref()
938 .unwrap()
939 .clone()
940 }
941}