radiate_core/stats/
set.rs

1use crate::{Metric, MetricScope, MetricUpdate, Rollup, intern, stats::fmt};
2#[cfg(feature = "serde")]
3use serde::{Deserialize, Serialize};
4use std::{collections::HashMap, fmt::Debug};
5
6pub(super) const METRIC_SET: &str = "metric_set";
7
8pub struct MetricSetSummary {
9    pub metrics: usize,
10    pub updates: f32,
11}
12
13#[derive(Clone)]
14pub struct MetricSet {
15    metrics: HashMap<&'static str, Metric>,
16    set_stats: Metric,
17}
18
19impl MetricSet {
20    pub fn new() -> Self {
21        MetricSet {
22            metrics: HashMap::new(),
23            set_stats: Metric::new_scoped(METRIC_SET, MetricScope::Lifetime)
24                .with_rollup(Rollup::Sum),
25        }
26    }
27
28    #[inline(always)]
29    pub fn keys(&self) -> Vec<&'static str> {
30        self.metrics.keys().cloned().collect()
31    }
32
33    #[inline(always)]
34    pub fn flush_all_into(&self, target: &mut MetricSet) {
35        for (_, m) in self.iter() {
36            self.flush_metric_into(m.name(), target);
37        }
38
39        target.set_stats.update_from(&self.set_stats);
40    }
41
42    #[inline(always)]
43    pub fn flush_scope_into(&self, from_scope: MetricScope, target: &mut MetricSet) {
44        for (_, m) in self.iter_scope(from_scope) {
45            self.flush_metric_into(m.name(), target);
46        }
47    }
48
49    #[inline(always)]
50    pub fn flush_metric_into(&self, name: &'static str, target: &mut MetricSet) {
51        if let Some(m) = self.metrics.get(name) {
52            let dest = target.metrics.entry(name).or_insert_with(|| {
53                let mut clone = m.clone();
54                clone.clear_values();
55                clone
56            });
57
58            dest.update_from(m);
59        }
60    }
61
62    pub fn upsert<'a>(&mut self, name: &'static str, update: impl Into<MetricUpdate<'a>>) {
63        if let Some(m) = self.metrics.get_mut(name) {
64            self.set_stats.apply_update(1);
65            m.apply_update(update);
66            return;
67        }
68
69        let new_name = super::normalize_name(name);
70        if let Some(m) = self.metrics.get_mut(&new_name) {
71            self.set_stats.apply_update(1);
72            m.apply_update(update);
73        } else {
74            self.add(
75                Metric::new_scoped(new_name, super::defaults::default_scope(new_name))
76                    .with_rollup(super::defaults::default_rollup(new_name)),
77            );
78
79            self.set_stats.apply_update(1);
80            self.metrics
81                .get_mut(&new_name)
82                .unwrap()
83                .apply_update(update);
84        }
85    }
86
87    #[inline(always)]
88    pub fn add_or_update<'a>(&mut self, metric: Metric) {
89        self.set_stats.apply_update(1);
90        if let Some(m) = self.metrics.get_mut(metric.name()) {
91            m.update_from(&metric);
92        } else {
93            self.add(metric);
94        }
95    }
96
97    #[inline(always)]
98    pub fn iter_scope(&self, scope: MetricScope) -> impl Iterator<Item = (&'static str, &Metric)> {
99        self.metrics
100            .iter()
101            .filter_map(move |(k, m)| (m.scope() == scope).then_some((*k, m)))
102    }
103
104    #[inline(always)]
105    pub fn iter_scope_mut(
106        &mut self,
107        scope: MetricScope,
108    ) -> impl Iterator<Item = (&'static str, &mut Metric)> {
109        self.metrics
110            .iter_mut()
111            .filter_map(move |(k, m)| (m.scope() == scope).then_some((*k, m)))
112    }
113
114    #[inline(always)]
115    pub fn iter(&self) -> impl Iterator<Item = (&'static str, &Metric)> {
116        self.metrics.iter().map(|(name, metric)| (*name, metric))
117    }
118
119    #[inline(always)]
120    pub fn clear_scope(&mut self, scope: MetricScope) {
121        for (_, m) in self.iter_scope_mut(scope) {
122            m.clear_values();
123        }
124    }
125
126    #[inline(always)]
127    pub fn add(&mut self, metric: Metric) {
128        self.metrics.insert(metric.name(), metric);
129    }
130
131    #[inline(always)]
132    pub fn get(&self, name: &'static str) -> Option<&Metric> {
133        self.metrics.get(name)
134    }
135
136    #[inline(always)]
137    pub fn get_from_string(&self, name: String) -> Option<&Metric> {
138        self.metrics.get(name.as_str())
139    }
140
141    #[inline(always)]
142    pub fn clear(&mut self) {
143        for (_, m) in self.metrics.iter_mut() {
144            m.clear_values();
145        }
146
147        self.set_stats.clear_values();
148    }
149
150    #[inline(always)]
151    pub fn contains_key(&self, name: impl Into<String>) -> bool {
152        self.metrics.contains_key(intern!(name.into()))
153    }
154
155    #[inline(always)]
156    pub fn len(&self) -> usize {
157        self.metrics.len()
158    }
159
160    #[inline(always)]
161    pub fn summary(&self) -> MetricSetSummary {
162        MetricSetSummary {
163            metrics: self.metrics.len(),
164            updates: self.set_stats.statistic().map(|s| s.sum()).unwrap_or(0.0),
165        }
166    }
167}
168
169impl Default for MetricSet {
170    fn default() -> Self {
171        MetricSet::new()
172    }
173}
174
175impl std::fmt::Display for MetricSet {
176    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177        let summary = self.summary();
178        let out = format!(
179            "[{} metrics, {:.0} updates]",
180            summary.metrics, summary.updates
181        );
182        write!(f, "{out}\n{}", fmt::render_full(self).unwrap_or_default())?;
183        Ok(())
184    }
185}
186
187impl Debug for MetricSet {
188    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189        write!(f, "MetricSet {{\n")?;
190        write!(f, "{}\n", fmt::render_dashboard(&self).unwrap_or_default())?;
191        write!(f, "}}")
192    }
193}
194
195#[cfg(feature = "serde")]
196impl Serialize for MetricSet {
197    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
198    where
199        S: serde::Serializer,
200    {
201        let metrics = self
202            .metrics
203            .iter()
204            .map(|(_, metric)| metric.clone())
205            .collect::<Vec<Metric>>();
206        metrics.serialize(serializer)
207    }
208}
209
210#[cfg(feature = "serde")]
211impl<'de> Deserialize<'de> for MetricSet {
212    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
213    where
214        D: serde::Deserializer<'de>,
215    {
216        use crate::stats::MetricInner;
217
218        #[derive(Deserialize)]
219        struct MetricOwned {
220            name: String,
221            inner: MetricInner,
222            scope: MetricScope,
223            rollup: Rollup,
224        }
225
226        let metrics = Vec::<MetricOwned>::deserialize(deserializer)?;
227
228        let mut metric_set = MetricSet::new();
229        for metric in metrics {
230            let metric = Metric {
231                name: intern!(metric.name),
232                inner: metric.inner,
233                scope: metric.scope,
234                rollup: metric.rollup,
235            };
236            metric_set.add(metric);
237        }
238        Ok(metric_set)
239    }
240}