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