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 &mut 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 &mut 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 &mut 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 &mut LabelSetEncoder {
307 labels: &mut labels,
308 }
309 .into(),
310 )?;
311
312 Ok(openmetrics_data_model::Exemplar {
313 value,
314 timestamp: exemplar.timestamp.map(Into::into),
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 prost_types::Timestamp;
446
447 use super::*;
448 use crate::metrics::counter::Counter;
449 use crate::metrics::exemplar::{CounterWithExemplar, HistogramWithExemplars};
450 use crate::metrics::family::Family;
451 use crate::metrics::gauge::Gauge;
452 use crate::metrics::histogram::{exponential_buckets, Histogram};
453 use crate::metrics::info::Info;
454 use crate::registry::Unit;
455 use std::borrow::Cow;
456 use std::collections::HashSet;
457 use std::sync::atomic::AtomicI64;
458 use std::sync::atomic::AtomicU64;
459 use std::time::SystemTime;
460
461 #[test]
462 fn encode_counter_int() {
463 let counter: Counter = Counter::default();
464 let mut registry = Registry::default();
465 registry.register("my_counter", "My counter", counter.clone());
466 counter.inc();
467
468 let metric_set = encode(®istry).unwrap();
469
470 let family = metric_set.metric_families.first().unwrap();
471 assert_eq!("my_counter", family.name);
472 assert_eq!("My counter.", family.help);
473
474 assert_eq!(
475 openmetrics_data_model::MetricType::Counter as i32,
476 extract_metric_type(&metric_set)
477 );
478
479 match extract_metric_point_value(&metric_set) {
480 openmetrics_data_model::metric_point::Value::CounterValue(value) => {
481 let expected = openmetrics_data_model::counter_value::Total::IntValue(1);
482 assert_eq!(Some(expected), value.total);
483 assert_eq!(None, value.exemplar);
484 assert_eq!(None, value.created);
485 }
486 _ => panic!("wrong value type"),
487 }
488 }
489
490 #[test]
491 fn encode_counter_double() {
492 let counter: Counter<f64> = Counter::default();
494 let mut registry = Registry::default();
495 registry.register("my_counter", "My counter", counter.clone());
496 counter.inc();
497
498 let metric_set = encode(®istry).unwrap();
499
500 let family = metric_set.metric_families.first().unwrap();
501 assert_eq!("my_counter", family.name);
502 assert_eq!("My counter.", family.help);
503
504 assert_eq!(
505 openmetrics_data_model::MetricType::Counter as i32,
506 extract_metric_type(&metric_set)
507 );
508
509 match extract_metric_point_value(&metric_set) {
510 openmetrics_data_model::metric_point::Value::CounterValue(value) => {
511 let expected = openmetrics_data_model::counter_value::Total::DoubleValue(1.0);
513 assert_eq!(Some(expected), value.total);
514 assert_eq!(None, value.exemplar);
515 assert_eq!(None, value.created);
516 }
517 _ => panic!("wrong value type"),
518 }
519 }
520
521 #[test]
522 fn encode_counter_with_unit() {
523 let mut registry = Registry::default();
524 let counter: Counter = Counter::default();
525 registry.register_with_unit("my_counter", "My counter", Unit::Seconds, counter);
526
527 let metric_set = encode(®istry).unwrap();
528
529 let family = metric_set.metric_families.first().unwrap();
530 assert_eq!("my_counter", family.name);
531 assert_eq!("My counter.", family.help);
532 assert_eq!("seconds", family.unit);
533 }
534
535 #[test]
536 fn encode_counter_with_exemplar() {
537 let now = SystemTime::now();
538 let now_ts: Timestamp = now.into();
539
540 let mut registry = Registry::default();
541
542 let counter_with_exemplar: CounterWithExemplar<Vec<(String, f64)>, f64> =
543 CounterWithExemplar::default();
544 registry.register(
545 "my_counter_with_exemplar",
546 "My counter with exemplar",
547 counter_with_exemplar.clone(),
548 );
549
550 counter_with_exemplar.inc_by(1.0, Some(vec![("user_id".to_string(), 42.0)]), None);
551
552 let metric_set = encode(®istry).unwrap();
553
554 let family = metric_set.metric_families.first().unwrap();
555 assert_eq!("my_counter_with_exemplar", family.name);
556 assert_eq!("My counter with exemplar.", family.help);
557
558 assert_eq!(
559 openmetrics_data_model::MetricType::Counter as i32,
560 extract_metric_type(&metric_set)
561 );
562
563 match extract_metric_point_value(&metric_set) {
564 openmetrics_data_model::metric_point::Value::CounterValue(value) => {
565 let expected = openmetrics_data_model::counter_value::Total::DoubleValue(1.0);
567 assert_eq!(Some(expected), value.total);
568
569 let exemplar = value.exemplar.as_ref().unwrap();
570 assert_eq!(1.0, exemplar.value);
571
572 assert!(exemplar.timestamp.is_none());
573
574 let expected_label = {
575 openmetrics_data_model::Label {
576 name: "user_id".to_string(),
577 value: "42.0".to_string(),
578 }
579 };
580 assert_eq!(vec![expected_label], exemplar.label);
581 }
582 _ => panic!("wrong value type"),
583 }
584
585 counter_with_exemplar.inc_by(1.0, Some(vec![("user_id".to_string(), 99.0)]), Some(now));
586
587 match extract_metric_point_value(&encode(®istry).unwrap()) {
588 openmetrics_data_model::metric_point::Value::CounterValue(value) => {
589 let expected = openmetrics_data_model::counter_value::Total::DoubleValue(2.0);
591 assert_eq!(Some(expected), value.total);
592
593 let exemplar = value.exemplar.as_ref().unwrap();
594 assert_eq!(1.0, exemplar.value);
595
596 assert_eq!(&now_ts, exemplar.timestamp.as_ref().unwrap());
597
598 let expected_label = {
599 openmetrics_data_model::Label {
600 name: "user_id".to_string(),
601 value: "99.0".to_string(),
602 }
603 };
604 assert_eq!(vec![expected_label], exemplar.label);
605 }
606 _ => panic!("wrong value type"),
607 }
608 }
609
610 #[test]
611 fn encode_gauge() {
612 let mut registry = Registry::default();
613 let gauge = Gauge::<i64, AtomicI64>::default();
614 registry.register("my_gauge", "My gauge", gauge.clone());
615 gauge.inc();
616
617 let metric_set = encode(®istry).unwrap();
618 let family = metric_set.metric_families.first().unwrap();
619 assert_eq!("my_gauge", family.name);
620 assert_eq!("My gauge.", family.help);
621
622 assert_eq!(
623 openmetrics_data_model::MetricType::Gauge as i32,
624 extract_metric_type(&metric_set)
625 );
626
627 match extract_metric_point_value(&metric_set) {
628 openmetrics_data_model::metric_point::Value::GaugeValue(value) => {
629 let expected = openmetrics_data_model::gauge_value::Value::IntValue(1);
630 assert_eq!(Some(expected), value.value);
631 }
632 _ => panic!("wrong value type"),
633 }
634 }
635
636 #[test]
637 fn encode_gauge_u64_normal() {
638 let mut registry = Registry::default();
639 let gauge = Gauge::<u64, AtomicU64>::default();
640 registry.register("my_gauge", "My gauge", gauge.clone());
641 gauge.set(12345);
642
643 let metric_set = encode(®istry).unwrap();
644 let family = metric_set.metric_families.first().unwrap();
645 assert_eq!("my_gauge", family.name);
646 assert_eq!("My gauge.", family.help);
647
648 assert_eq!(
649 openmetrics_data_model::MetricType::Gauge as i32,
650 extract_metric_type(&metric_set)
651 );
652
653 match extract_metric_point_value(&metric_set) {
654 openmetrics_data_model::metric_point::Value::GaugeValue(value) => {
655 let expected = openmetrics_data_model::gauge_value::Value::IntValue(12345);
656 assert_eq!(Some(expected), value.value);
657 }
658 _ => panic!("wrong value type"),
659 }
660 }
661
662 #[test]
663 fn encode_gauge_u64_max() {
664 let mut registry = Registry::default();
665 let gauge = Gauge::<u64, AtomicU64>::default();
666 registry.register("my_gauge", "My gauge", gauge.clone());
667 gauge.set(u64::MAX);
668
669 assert!(encode(®istry).is_err());
671 }
672
673 #[test]
674 fn encode_counter_family() {
675 let mut registry = Registry::default();
676 let family = Family::<Vec<(String, String)>, Counter>::default();
677 registry.register("my_counter_family", "My counter family", family.clone());
678
679 family
680 .get_or_create(&vec![
681 ("method".to_string(), "GET".to_string()),
682 ("status".to_string(), "200".to_string()),
683 ])
684 .inc();
685
686 family
687 .get_or_create(&vec![
688 ("method".to_string(), "POST".to_string()),
689 ("status".to_string(), "200".to_string()),
690 ])
691 .inc();
692
693 let metric_set = encode(®istry).unwrap();
694
695 let family = metric_set.metric_families.first().unwrap();
696 assert_eq!("my_counter_family", family.name);
697 assert_eq!("My counter family.", family.help);
698
699 assert_eq!(
700 openmetrics_data_model::MetricType::Counter as i32,
701 extract_metric_type(&metric_set)
702 );
703
704 let mut potential_method_value = HashSet::new();
707 potential_method_value.insert("GET");
708 potential_method_value.insert("POST");
709
710 let metric = family.metrics.first().unwrap();
712 assert_eq!(2, metric.labels.len());
713 assert_eq!("method", metric.labels[0].name);
714 assert!(potential_method_value.remove(&metric.labels[0].value.as_str()));
715 assert_eq!("status", metric.labels[1].name);
716 assert_eq!("200", metric.labels[1].value);
717
718 match extract_metric_point_value(&metric_set) {
719 openmetrics_data_model::metric_point::Value::CounterValue(value) => {
720 let expected = openmetrics_data_model::counter_value::Total::IntValue(1);
721 assert_eq!(Some(expected), value.total);
722 assert_eq!(None, value.exemplar);
723 assert_eq!(None, value.created);
724 }
725 _ => panic!("wrong value type"),
726 }
727
728 let metric2 = &family.metrics[1];
730 assert_eq!(2, metric2.labels.len());
731 assert_eq!("method", metric2.labels[0].name);
732 assert!(potential_method_value.remove(&metric2.labels[0].value.as_str()));
733 assert_eq!("status", metric2.labels[1].name);
734 assert_eq!("200", metric2.labels[1].value);
735 }
736
737 #[test]
738 fn encode_counter_family_with_prefix_with_label() {
739 let mut registry = Registry::default();
740 let sub_registry = registry.sub_registry_with_prefix("my_prefix");
741 let sub_sub_registry = sub_registry
742 .sub_registry_with_label((Cow::Borrowed("my_key"), Cow::Borrowed("my_value")));
743 let family = Family::<Vec<(String, String)>, Counter>::default();
744 sub_sub_registry.register("my_counter_family", "My counter family", family.clone());
745
746 family
747 .get_or_create(&vec![
748 ("method".to_string(), "GET".to_string()),
749 ("status".to_string(), "200".to_string()),
750 ])
751 .inc();
752
753 let metric_set = encode(®istry).unwrap();
754
755 let family = metric_set.metric_families.first().unwrap();
756 assert_eq!("my_prefix_my_counter_family", family.name);
757 assert_eq!("My counter family.", family.help);
758
759 assert_eq!(
760 openmetrics_data_model::MetricType::Counter as i32,
761 extract_metric_type(&metric_set)
762 );
763
764 let metric = family.metrics.first().unwrap();
765 assert_eq!(3, metric.labels.len());
766 assert_eq!("my_key", metric.labels[0].name);
767 assert_eq!("my_value", metric.labels[0].value);
768 assert_eq!("method", metric.labels[1].name);
769 assert_eq!("GET", metric.labels[1].value);
770 assert_eq!("status", metric.labels[2].name);
771 assert_eq!("200", metric.labels[2].value);
772
773 match extract_metric_point_value(&metric_set) {
774 openmetrics_data_model::metric_point::Value::CounterValue(value) => {
775 let expected = openmetrics_data_model::counter_value::Total::IntValue(1);
776 assert_eq!(Some(expected), value.total);
777 assert_eq!(None, value.exemplar);
778 assert_eq!(None, value.created);
779 }
780 _ => panic!("wrong value type"),
781 }
782 }
783
784 #[test]
785 fn encode_histogram() {
786 let mut registry = Registry::default();
787 let histogram = Histogram::new(exponential_buckets(1.0, 2.0, 10));
788 registry.register("my_histogram", "My histogram", histogram.clone());
789 histogram.observe(1.0);
790
791 let metric_set = encode(®istry).unwrap();
792
793 let family = metric_set.metric_families.first().unwrap();
794 assert_eq!("my_histogram", family.name);
795 assert_eq!("My histogram.", family.help);
796
797 assert_eq!(
798 openmetrics_data_model::MetricType::Histogram as i32,
799 extract_metric_type(&metric_set)
800 );
801
802 match extract_metric_point_value(&metric_set) {
803 openmetrics_data_model::metric_point::Value::HistogramValue(value) => {
804 assert_eq!(
805 Some(openmetrics_data_model::histogram_value::Sum::DoubleValue(
806 1.0
807 )),
808 value.sum
809 );
810 assert_eq!(1, value.count);
811 assert_eq!(11, value.buckets.len());
812 }
813 _ => panic!("wrong value type"),
814 }
815 }
816
817 #[test]
818 fn encode_histogram_with_exemplars() {
819 let now = SystemTime::now();
820 let now_ts: Timestamp = now.into();
821
822 let mut registry = Registry::default();
823 let histogram = HistogramWithExemplars::new(exponential_buckets(1.0, 2.0, 10));
824 registry.register("my_histogram", "My histogram", histogram.clone());
825
826 histogram.observe(1.0, Some(vec![("user_id".to_string(), 42u64)]), None);
827
828 let metric_set = encode(®istry).unwrap();
829
830 let family = metric_set.metric_families.first().unwrap();
831 assert_eq!("my_histogram", family.name);
832 assert_eq!("My histogram.", family.help);
833
834 assert_eq!(
835 openmetrics_data_model::MetricType::Histogram as i32,
836 extract_metric_type(&metric_set)
837 );
838
839 match extract_metric_point_value(&metric_set) {
840 openmetrics_data_model::metric_point::Value::HistogramValue(value) => {
841 let exemplar = value.buckets.first().unwrap().exemplar.as_ref().unwrap();
842 assert_eq!(1.0, exemplar.value);
843
844 assert!(exemplar.timestamp.is_none());
845
846 let expected_label = {
847 openmetrics_data_model::Label {
848 name: "user_id".to_string(),
849 value: "42".to_string(),
850 }
851 };
852 assert_eq!(vec![expected_label], exemplar.label);
853 }
854 _ => panic!("wrong value type"),
855 }
856
857 histogram.observe(2.0, Some(vec![("user_id".to_string(), 99u64)]), Some(now));
858
859 match extract_metric_point_value(&encode(®istry).unwrap()) {
860 openmetrics_data_model::metric_point::Value::HistogramValue(value) => {
861 let exemplar = value.buckets.get(1).unwrap().exemplar.as_ref().unwrap();
862 assert_eq!(2.0, exemplar.value);
863
864 assert_eq!(&now_ts, exemplar.timestamp.as_ref().unwrap());
865
866 let expected_label = {
867 openmetrics_data_model::Label {
868 name: "user_id".to_string(),
869 value: "99".to_string(),
870 }
871 };
872 assert_eq!(vec![expected_label], exemplar.label);
873 }
874 _ => panic!("wrong value type"),
875 }
876 }
877
878 #[test]
879 fn encode_family_counter_histogram() {
880 let mut registry = Registry::default();
881
882 let counter_family = Family::<Vec<(String, String)>, Counter>::default();
883 let histogram_family =
884 Family::<Vec<(String, String)>, Histogram>::new_with_constructor(|| {
885 Histogram::new(exponential_buckets(1.0, 2.0, 10))
886 });
887
888 registry.register("my_counter", "My counter", counter_family.clone());
889 registry.register("my_histogram", "My histogram", histogram_family.clone());
890
891 counter_family
892 .get_or_create(&vec![("path".to_string(), "/".to_string())])
893 .inc();
894
895 histogram_family
896 .get_or_create(&vec![("path".to_string(), "/".to_string())])
897 .observe(1.0);
898
899 let metric_set = encode(®istry).unwrap();
900 assert_eq!("my_counter", metric_set.metric_families[0].name);
901 assert_eq!("my_histogram", metric_set.metric_families[1].name);
902 }
903
904 #[test]
905 fn encode_family_and_counter_and_histogram() {
906 let mut registry = Registry::default();
907
908 let counter_family = Family::<Vec<(String, String)>, Counter>::default();
910 let histogram_family =
911 Family::<Vec<(String, String)>, Histogram>::new_with_constructor(|| {
912 Histogram::new(exponential_buckets(1.0, 2.0, 10))
913 });
914
915 registry.register("my_family_counter", "My counter", counter_family.clone());
916 registry.register(
917 "my_family_histogram",
918 "My histogram",
919 histogram_family.clone(),
920 );
921
922 counter_family
923 .get_or_create(&vec![("path".to_string(), "/".to_string())])
924 .inc();
925
926 histogram_family
927 .get_or_create(&vec![("path".to_string(), "/".to_string())])
928 .observe(1.0);
929
930 let counter: Counter = Counter::default();
932 registry.register("my_counter", "My counter", counter.clone());
933 counter.inc();
934
935 let histogram = Histogram::new(exponential_buckets(1.0, 2.0, 10));
937 registry.register("my_histogram", "My histogram", histogram.clone());
938 histogram.observe(1.0);
939
940 let metric_set = encode(®istry).unwrap();
941 assert_eq!("my_family_counter", metric_set.metric_families[0].name);
942 assert_eq!("my_family_histogram", metric_set.metric_families[1].name);
943 }
944
945 #[test]
946 fn encode_info() {
947 let mut registry = Registry::default();
948 let info = Info::new(vec![("os".to_string(), "GNU/linux".to_string())]);
949 registry.register("my_info_metric", "My info metric", info);
950
951 let metric_set = encode(®istry).unwrap();
952
953 let family = metric_set.metric_families.first().unwrap();
954 assert_eq!("my_info_metric", family.name);
955 assert_eq!("My info metric.", family.help);
956
957 assert_eq!(
958 openmetrics_data_model::MetricType::Info as i32,
959 extract_metric_type(&metric_set)
960 );
961
962 match extract_metric_point_value(&metric_set) {
963 openmetrics_data_model::metric_point::Value::InfoValue(value) => {
964 assert_eq!(1, value.info.len());
965
966 let info = value.info.first().unwrap();
967 assert_eq!("os", info.name);
968 assert_eq!("GNU/linux", info.value);
969 }
970 _ => panic!("wrong value type"),
971 }
972 }
973
974 fn extract_metric_type(metric_set: &openmetrics_data_model::MetricSet) -> i32 {
975 let family = metric_set.metric_families.first().unwrap();
976 family.r#type
977 }
978
979 fn extract_metric_point_value(
980 metric_set: &openmetrics_data_model::MetricSet,
981 ) -> openmetrics_data_model::metric_point::Value {
982 let metric = metric_set
983 .metric_families
984 .first()
985 .unwrap()
986 .metrics
987 .first()
988 .unwrap();
989
990 metric
991 .metric_points
992 .first()
993 .unwrap()
994 .value
995 .as_ref()
996 .unwrap()
997 .clone()
998 }
999}