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