prometheus_endpoint/
sourced.rs1use prometheus::core::{Collector, Desc, Describer, Number, Opts};
21use prometheus::proto;
22use std::{cmp::Ordering, marker::PhantomData};
23
24pub type SourcedCounter<S> = SourcedMetric<Counter, S>;
30
31pub type SourcedGauge<S> = SourcedMetric<Gauge, S>;
33
34#[derive(Copy, Clone)]
36pub enum Counter {}
37
38#[derive(Copy, Clone)]
40pub enum Gauge {}
41
42#[derive(Debug, Clone)]
45pub struct SourcedMetric<T, S> {
46 source: S,
47 desc: Desc,
48 _type: PhantomData<T>,
49}
50
51pub trait MetricSource: Sync + Send + Clone {
53 type N: Number;
55 fn collect(&self, set: impl FnMut(&[&str], Self::N));
57}
58
59impl<T: SourcedType, S: MetricSource> SourcedMetric<T, S> {
60 pub fn new(opts: &Opts, source: S) -> prometheus::Result<Self> {
62 let desc = opts.describe()?;
63 Ok(Self { source, desc, _type: PhantomData })
64 }
65}
66
67impl<T: SourcedType, S: MetricSource> Collector for SourcedMetric<T, S> {
68 fn desc(&self) -> Vec<&Desc> {
69 vec![&self.desc]
70 }
71
72 fn collect(&self) -> Vec<proto::MetricFamily> {
73 let mut counters = Vec::new();
74
75 self.source.collect(|label_values, value| {
76 let mut m = proto::Metric::default();
77
78 match T::proto() {
79 proto::MetricType::COUNTER => {
80 let mut c = proto::Counter::default();
81 c.set_value(value.into_f64());
82 m.set_counter(c);
83 }
84 proto::MetricType::GAUGE => {
85 let mut g = proto::Gauge::default();
86 g.set_value(value.into_f64());
87 m.set_gauge(g);
88 }
89 t => {
90 log::error!("Unsupported sourced metric type: {:?}", t);
91 }
92 }
93
94 debug_assert_eq!(self.desc.variable_labels.len(), label_values.len());
95 match self.desc.variable_labels.len().cmp(&label_values.len()) {
96 Ordering::Greater =>
97 log::warn!("Missing label values for sourced metric {}", self.desc.fq_name),
98 Ordering::Less =>
99 log::warn!("Too many label values for sourced metric {}", self.desc.fq_name),
100 Ordering::Equal => {}
101 }
102
103 m.set_label(self.desc.variable_labels.iter().zip(label_values)
104 .map(|(l_name, l_value)| {
105 let mut l = proto::LabelPair::default();
106 l.set_name(l_name.to_string());
107 l.set_value(l_value.to_string());
108 l
109 })
110 .chain(self.desc.const_label_pairs.iter().cloned())
111 .collect::<Vec<_>>());
112
113 counters.push(m);
114 });
115
116 let mut m = proto::MetricFamily::default();
117 m.set_name(self.desc.fq_name.clone());
118 m.set_help(self.desc.help.clone());
119 m.set_field_type(T::proto());
120 m.set_metric(counters);
121
122 vec![m]
123 }
124}
125
126pub trait SourcedType: private::Sealed + Sync + Send {
128 #[doc(hidden)]
129 fn proto() -> proto::MetricType;
130}
131
132impl SourcedType for Counter {
133 fn proto() -> proto::MetricType { proto::MetricType::COUNTER }
134}
135
136impl SourcedType for Gauge {
137 fn proto() -> proto::MetricType { proto::MetricType::GAUGE }
138}
139
140mod private {
141 pub trait Sealed {}
142 impl Sealed for super::Counter {}
143 impl Sealed for super::Gauge {}
144}