use std::{collections::HashMap, fmt, sync::Arc};
use crate::{
core::Collector,
proto::{Gauge, Metric, MetricFamily, MetricType},
};
#[derive(Clone)]
pub struct PullingGauge {
desc: crate::core::Desc,
value: Arc<Box<dyn Fn() -> f64 + Send + Sync>>,
}
impl fmt::Debug for PullingGauge {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PullingGauge")
.field("desc", &self.desc)
.field("value", &"<opaque>")
.finish()
}
}
impl PullingGauge {
pub fn new<S1: Into<String>, S2: Into<String>>(
name: S1,
help: S2,
value: Box<dyn Fn() -> f64 + Send + Sync>,
) -> crate::Result<Self> {
Ok(PullingGauge {
value: Arc::new(value),
desc: crate::core::Desc::new(name.into(), help.into(), Vec::new(), HashMap::new())?,
})
}
fn metric(&self) -> Metric {
let mut gauge = Gauge::default();
let getter = &self.value;
gauge.set_value(getter());
let mut metric = Metric::default();
metric.set_gauge(gauge);
metric
}
}
impl Collector for PullingGauge {
fn desc(&self) -> Vec<&crate::core::Desc> {
vec![&self.desc]
}
fn collect(&self) -> Vec<crate::proto::MetricFamily> {
let mut m = MetricFamily::default();
m.set_name(self.desc.fq_name.clone());
m.set_help(self.desc.help.clone());
m.set_field_type(MetricType::GAUGE);
m.set_metric(from_vec!(vec![self.metric()]));
vec![m]
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::metrics::Collector;
#[test]
fn test_pulling_gauge() {
const VALUE: f64 = 10.0;
let gauge =
PullingGauge::new("test_gauge", "Purely for testing", Box::new(|| VALUE)).unwrap();
let metrics = gauge.collect();
assert_eq!(metrics.len(), 1);
assert_eq!(VALUE, metrics[0].get_metric()[0].get_gauge().get_value());
}
}