metriki_core/metrics/
gauge.rs1use std::fmt;
2use std::sync::Mutex;
3use std::time::{Duration, Instant};
4
5#[cfg(feature = "ser")]
6use serde::ser::SerializeMap;
7#[cfg(feature = "ser")]
8use serde::{Serialize, Serializer};
9
10pub trait GaugeFn: Send + Sync {
12 fn value(&self) -> f64;
13}
14
15impl<F: Fn() -> f64 + Send + Sync> GaugeFn for F {
16 fn value(&self) -> f64 {
17 self()
18 }
19}
20
21pub struct Gauge {
23 func: Box<dyn GaugeFn>,
24}
25
26impl Gauge {
27 pub(crate) fn new(f: Box<dyn GaugeFn>) -> Gauge {
28 Gauge { func: f }
29 }
30
31 pub fn value(&self) -> f64 {
32 self.func.value()
33 }
34}
35
36impl fmt::Debug for Gauge {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
38 f.debug_struct("Gauge").finish()
39 }
40}
41
42#[cfg(feature = "ser")]
43impl Serialize for Gauge {
44 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
45 where
46 S: Serializer,
47 {
48 let mut map = serializer.serialize_map(Some(1))?;
49 map.serialize_entry("value", &self.value())?;
50 map.end()
51 }
52}
53
54struct Cache<V> {
55 expiry: Instant,
56 value: V,
57}
58
59impl<V> Cache<V> {
60 fn expired(&self) -> bool {
61 self.expiry < Instant::now()
62 }
63
64 fn value(&self) -> &V {
65 &self.value
66 }
67}
68
69pub struct CachedGauge {
84 func: Box<dyn GaugeFn>,
85 cache: Mutex<Option<Cache<f64>>>,
86 ttl: Duration,
87}
88
89impl CachedGauge {
90 pub fn boxed(func: Box<dyn GaugeFn>, ttl: Duration) -> Box<CachedGauge> {
92 Box::new(CachedGauge {
93 func,
94 ttl,
95 cache: Mutex::new(None),
96 })
97 }
98}
99
100impl GaugeFn for CachedGauge {
101 fn value(&self) -> f64 {
102 let mut cache = self.cache.lock().unwrap();
103
104 if let Some(ref cache_inner) = *cache {
105 if !cache_inner.expired() {
106 return *cache_inner.value();
107 }
108 }
109
110 let value = self.func.value();
111 let new_cache = Cache {
112 expiry: Instant::now() + self.ttl,
113 value,
114 };
115
116 *cache = Some(new_cache);
117
118 value
119 }
120}
121
122pub struct StaticGauge(pub f64);
124
125impl GaugeFn for StaticGauge {
126 fn value(&self) -> f64 {
127 self.0
128 }
129}