radiate_core/stats/
set.rs1use 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}