prometheus/
pulling_gauge.rs

1use std::{collections::HashMap, fmt, sync::Arc};
2
3use crate::{
4    core::Collector,
5    proto::{Gauge, Metric, MetricFamily, MetricType},
6};
7
8/// A [Gauge] that returns the value from a provided function on every collect run.
9///
10/// This metric is the equivalant of Go's
11/// <https://pkg.go.dev/github.com/prometheus/client_golang@v1.11.0/prometheus#GaugeFunc>
12///
13/// # Examples
14/// ```
15/// # use prometheus::{Registry, PullingGauge};
16/// # // We are stubbing out std::thread::available_parallelism since it's not available in the
17/// # // oldest Rust version that we support.
18/// # fn available_parallelism() -> f64 { 0.0 }
19///
20/// let registry = Registry::new();
21/// let gauge = PullingGauge::new(
22///     "available_parallelism",
23///     "The available parallelism, usually the numbers of logical cores.",
24///     Box::new(|| available_parallelism())
25/// ).unwrap();
26/// registry.register(Box::new(gauge));
27/// ```
28#[derive(Clone)]
29pub struct PullingGauge {
30    desc: crate::core::Desc,
31    value: Arc<Box<dyn Fn() -> f64 + Send + Sync>>,
32}
33
34impl fmt::Debug for PullingGauge {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        f.debug_struct("PullingGauge")
37            .field("desc", &self.desc)
38            .field("value", &"<opaque>")
39            .finish()
40    }
41}
42
43impl PullingGauge {
44    /// Create a new [`PullingGauge`].
45    pub fn new<S1: Into<String>, S2: Into<String>>(
46        name: S1,
47        help: S2,
48        value: Box<dyn Fn() -> f64 + Send + Sync>,
49    ) -> crate::Result<Self> {
50        Ok(PullingGauge {
51            value: Arc::new(value),
52            desc: crate::core::Desc::new(name.into(), help.into(), Vec::new(), HashMap::new())?,
53        })
54    }
55
56    fn metric(&self) -> Metric {
57        let mut gauge = Gauge::default();
58        let getter = &self.value;
59        gauge.set_value(getter());
60
61        Metric::from_gauge(gauge)
62    }
63}
64
65impl Collector for PullingGauge {
66    fn desc(&self) -> Vec<&crate::core::Desc> {
67        vec![&self.desc]
68    }
69
70    fn collect(&self) -> Vec<crate::proto::MetricFamily> {
71        let mut m = MetricFamily::default();
72        m.set_name(self.desc.fq_name.clone());
73        m.set_help(self.desc.help.clone());
74        m.set_field_type(MetricType::GAUGE);
75        m.set_metric(vec![self.metric()]);
76        vec![m]
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83    use crate::metrics::Collector;
84    #[cfg(feature = "protobuf")]
85    use crate::proto_ext::MessageFieldExt;
86
87    #[test]
88    fn test_pulling_gauge() {
89        const VALUE: f64 = 10.0;
90
91        let gauge =
92            PullingGauge::new("test_gauge", "Purely for testing", Box::new(|| VALUE)).unwrap();
93
94        let metrics = gauge.collect();
95        assert_eq!(metrics.len(), 1);
96
97        assert_eq!(VALUE, metrics[0].get_metric()[0].get_gauge().get_value());
98    }
99}