1use crate::{
15 Clock, Counter, ExponentiallyDecayingReservoir, Gauge, Histogram, Meter, MetricId, Timer,
16};
17use parking_lot::Mutex;
18use std::collections::hash_map::Entry;
19use std::collections::{hash_map, HashMap};
20use std::sync::Arc;
21
22#[derive(Clone)]
24pub enum Metric {
25 Counter(Arc<Counter>),
27 Meter(Arc<Meter>),
29 Gauge(Arc<dyn Gauge>),
31 Histogram(Arc<Histogram>),
33 Timer(Arc<Timer>),
35}
36
37pub struct MetricRegistry {
51 metrics: Mutex<Arc<HashMap<Arc<MetricId>, Metric>>>,
52 clock: Arc<dyn Clock>,
53}
54
55impl Default for MetricRegistry {
56 fn default() -> Self {
57 MetricRegistry {
58 metrics: Mutex::new(Arc::new(HashMap::new())),
59 clock: crate::SYSTEM_CLOCK.clone(),
60 }
61 }
62}
63
64impl MetricRegistry {
65 #[inline]
67 pub fn new() -> MetricRegistry {
68 MetricRegistry::default()
69 }
70
71 #[inline]
75 pub fn set_clock(&mut self, clock: Arc<dyn Clock>) {
76 self.clock = clock;
77 }
78
79 #[inline]
81 pub fn clock(&self) -> &Arc<dyn Clock> {
82 &self.clock
83 }
84
85 pub fn counter_with<T, F>(&self, id: T, make_counter: F) -> Arc<Counter>
91 where
92 T: Into<MetricId>,
93 F: FnOnce() -> Counter,
94 {
95 match Arc::make_mut(&mut self.metrics.lock()).entry(Arc::new(id.into())) {
96 Entry::Occupied(e) => match e.get() {
97 Metric::Counter(c) => c.clone(),
98 _ => panic!("metric already registered as a non-counter: {:?}", e.key()),
99 },
100 Entry::Vacant(e) => {
101 let counter = Arc::new(make_counter());
102 e.insert(Metric::Counter(counter.clone()));
103 counter
104 }
105 }
106 }
107
108 pub fn counter<T>(&self, id: T) -> Arc<Counter>
114 where
115 T: Into<MetricId>,
116 {
117 self.counter_with(id, Counter::default)
118 }
119
120 pub fn meter_with<T, F>(&self, id: T, make_meter: F) -> Arc<Meter>
126 where
127 T: Into<MetricId>,
128 F: FnOnce() -> Meter,
129 {
130 match Arc::make_mut(&mut self.metrics.lock()).entry(Arc::new(id.into())) {
131 Entry::Occupied(e) => match e.get() {
132 Metric::Meter(m) => m.clone(),
133 _ => panic!("metric already registered as a non-meter: {:?}", e.key()),
134 },
135 Entry::Vacant(e) => {
136 let meter = Arc::new(make_meter());
137 e.insert(Metric::Meter(meter.clone()));
138 meter
139 }
140 }
141 }
142
143 pub fn meter<T>(&self, id: T) -> Arc<Meter>
149 where
150 T: Into<MetricId>,
151 {
152 self.meter_with(id, || Meter::new_with(self.clock.clone()))
153 }
154
155 pub fn gauge_with<T, F, G>(&self, id: T, make_gauge: F) -> Arc<dyn Gauge>
161 where
162 T: Into<MetricId>,
163 F: FnOnce() -> G,
164 G: Gauge,
165 {
166 match Arc::make_mut(&mut self.metrics.lock()).entry(Arc::new(id.into())) {
167 Entry::Occupied(e) => match e.get() {
168 Metric::Gauge(m) => m.clone(),
169 _ => panic!("metric already registered as a non-gauge: {:?}", e.key()),
170 },
171 Entry::Vacant(e) => {
172 let gauge = Arc::new(make_gauge());
173 e.insert(Metric::Gauge(gauge.clone()));
174 gauge
175 }
176 }
177 }
178
179 pub fn gauge<T, G>(&self, id: T, gauge: G) -> Arc<dyn Gauge>
185 where
186 T: Into<MetricId>,
187 G: Gauge,
188 {
189 self.gauge_with(id, || gauge)
190 }
191
192 pub fn replace_gauge<T, G>(&self, id: T, gauge: G)
194 where
195 T: Into<MetricId>,
196 G: Gauge,
197 {
198 Arc::make_mut(&mut self.metrics.lock())
199 .insert(Arc::new(id.into()), Metric::Gauge(Arc::new(gauge)));
200 }
201
202 pub fn histogram_with<T, F>(&self, id: T, make_histogram: F) -> Arc<Histogram>
208 where
209 T: Into<MetricId>,
210 F: FnOnce() -> Histogram,
211 {
212 match Arc::make_mut(&mut self.metrics.lock()).entry(Arc::new(id.into())) {
213 Entry::Occupied(e) => match e.get() {
214 Metric::Histogram(m) => m.clone(),
215 _ => panic!(
216 "metric already registered as a non-histogram: {:?}",
217 e.key()
218 ),
219 },
220 Entry::Vacant(e) => {
221 let histogram = Arc::new(make_histogram());
222 e.insert(Metric::Histogram(histogram.clone()));
223 histogram
224 }
225 }
226 }
227
228 pub fn histogram<T>(&self, id: T) -> Arc<Histogram>
234 where
235 T: Into<MetricId>,
236 {
237 self.histogram_with(id, || {
238 Histogram::new(ExponentiallyDecayingReservoir::new_with(self.clock.clone()))
239 })
240 }
241
242 pub fn timer_with<T, F>(&self, id: T, make_timer: F) -> Arc<Timer>
248 where
249 T: Into<MetricId>,
250 F: FnOnce() -> Timer,
251 {
252 match Arc::make_mut(&mut self.metrics.lock()).entry(Arc::new(id.into())) {
253 Entry::Occupied(e) => match e.get() {
254 Metric::Timer(m) => m.clone(),
255 _ => panic!("metric already registered as a non-timer: {:?}", e.key()),
256 },
257 Entry::Vacant(e) => {
258 let timer = Arc::new(make_timer());
259 e.insert(Metric::Timer(timer.clone()));
260 timer
261 }
262 }
263 }
264
265 pub fn timer<T>(&self, id: T) -> Arc<Timer>
271 where
272 T: Into<MetricId>,
273 {
274 self.timer_with(id, || {
275 Timer::new_with(
276 ExponentiallyDecayingReservoir::new_with(self.clock.clone()),
277 self.clock.clone(),
278 )
279 })
280 }
281
282 pub fn remove<T>(&self, id: T) -> Option<Metric>
284 where
285 T: Into<MetricId>,
286 {
287 Arc::make_mut(&mut self.metrics.lock()).remove(&id.into())
288 }
289
290 pub fn metrics(&self) -> Metrics {
294 Metrics(self.metrics.lock().clone())
295 }
296}
297
298pub struct Metrics(Arc<HashMap<Arc<MetricId>, Metric>>);
300
301impl Metrics {
302 pub fn iter(&self) -> MetricsIter<'_> {
304 MetricsIter(self.0.iter())
305 }
306}
307
308impl<'a> IntoIterator for &'a Metrics {
309 type Item = (&'a MetricId, &'a Metric);
310 type IntoIter = MetricsIter<'a>;
311
312 fn into_iter(self) -> MetricsIter<'a> {
313 self.iter()
314 }
315}
316
317pub struct MetricsIter<'a>(hash_map::Iter<'a, Arc<MetricId>, Metric>);
319
320impl<'a> Iterator for MetricsIter<'a> {
321 type Item = (&'a MetricId, &'a Metric);
322
323 #[inline]
324 fn next(&mut self) -> Option<(&'a MetricId, &'a Metric)> {
325 self.0.next().map(|(k, v)| (&**k, v))
326 }
327
328 #[inline]
329 fn size_hint(&self) -> (usize, Option<usize>) {
330 self.0.size_hint()
331 }
332}
333
334impl<'a> ExactSizeIterator for MetricsIter<'a> {}
335
336#[cfg(test)]
337mod test {
338 use crate::{MetricId, MetricRegistry};
339 use serde_value::Value;
340 use std::time::Duration;
341
342 #[test]
343 fn first_metric_wins() {
344 let registry = MetricRegistry::new();
345
346 let a = registry.counter("counter");
347 let b = registry.counter("counter");
348 a.add(1);
349 assert_eq!(b.count(), 1);
350
351 registry.gauge("gauge", || 1);
352 let b = registry.gauge("gauge", || 2);
353 assert_eq!(b.value(), Value::I32(1));
354
355 let a = registry.histogram("histogram");
356 let b = registry.histogram("histogram");
357 a.update(0);
358 assert_eq!(b.count(), 1);
359
360 let a = registry.meter("meter");
361 let b = registry.meter("meter");
362 a.mark(1);
363 assert_eq!(b.count(), 1);
364
365 let a = registry.timer("timer");
366 let b = registry.timer("timer");
367 a.update(Duration::from_secs(0));
368 assert_eq!(b.count(), 1);
369 }
370
371 #[test]
372 fn metrics_returns_snapshot() {
373 let registry = MetricRegistry::new();
374
375 registry.counter("counter");
376
377 let metrics = registry.metrics();
378
379 registry.timer("timer");
380
381 let metrics = metrics.iter().collect::<Vec<_>>();
382 assert_eq!(metrics.len(), 1);
383 assert_eq!(metrics[0].0, &MetricId::new("counter"));
384 }
385
386 #[test]
387 fn tagged_distinct_from_untagged() {
388 let registry = MetricRegistry::new();
389
390 let a = registry.counter("counter");
391 let b = registry.counter(MetricId::new("counter").with_tag("foo", "bar"));
392 a.inc();
393 assert_eq!(b.count(), 0);
394 }
395}