Skip to main content

tacho/
report.rs

1use super::{CounterMap, GaugeMap, HistogramWithSum, Key, Registry, StatMap};
2use indexmap::IndexMap;
3use std::sync::atomic::Ordering;
4use std::sync::{Arc, Mutex};
5
6type ReportCounterMap = IndexMap<Key, usize>;
7type ReportGaugeMap = IndexMap<Key, usize>;
8type ReportStatMap = IndexMap<Key, HistogramWithSum>;
9
10pub fn new(registry: Arc<Mutex<Registry>>) -> Reporter {
11    Reporter(registry)
12}
13
14#[derive(Clone)]
15pub struct Reporter(Arc<Mutex<Registry>>);
16
17impl Reporter {
18    /// Obtains a read-only view of a metrics report without clearing the underlying state.
19    pub fn peek(&self) -> Report {
20        let registry = self.0.lock().unwrap();
21        Report {
22            counters: snap_counters(&registry.counters),
23            gauges: snap_gauges(&registry.gauges),
24            stats: snap_stats(&registry.stats, false),
25        }
26    }
27
28    /// Obtains a Report and removes unused metrics.
29    pub fn take(&mut self) -> Report {
30        let mut registry = self.0.lock().unwrap();
31
32        let report = Report {
33            counters: snap_counters(&registry.counters),
34            gauges: snap_gauges(&registry.gauges),
35            stats: snap_stats(&registry.stats, true),
36        };
37
38        // Drop unreferenced metrics.
39        registry.counters.retain(|_, v| Arc::weak_count(v) > 0);
40        registry.gauges.retain(|_, v| Arc::weak_count(v) > 0);
41        registry.stats.retain(|_, v| Arc::weak_count(v) > 0);
42
43        report
44    }
45}
46
47fn snap_counters(counters: &CounterMap) -> ReportCounterMap {
48    let mut snap = ReportCounterMap::with_capacity(counters.len());
49    for (k, v) in &*counters {
50        let v = v.load(Ordering::Acquire);
51        snap.insert(k.clone(), v);
52    }
53    snap
54}
55
56fn snap_gauges(gauges: &GaugeMap) -> ReportGaugeMap {
57    let mut snap = ReportGaugeMap::with_capacity(gauges.len());
58    for (k, v) in &*gauges {
59        let v = v.load(Ordering::Acquire);
60        snap.insert(k.clone(), v);
61    }
62    snap
63}
64
65fn snap_stats(stats: &StatMap, clear: bool) -> ReportStatMap {
66    let mut snap = ReportStatMap::with_capacity(stats.len());
67    for (k, ptr) in &*stats {
68        let mut orig = ptr.lock().unwrap();
69        snap.insert(k.clone(), orig.clone());
70        if clear {
71            orig.clear();
72        }
73    }
74    snap
75}
76
77pub struct Report {
78    counters: ReportCounterMap,
79    gauges: ReportGaugeMap,
80    stats: ReportStatMap,
81}
82impl Report {
83    pub fn counters(&self) -> &ReportCounterMap {
84        &self.counters
85    }
86    pub fn gauges(&self) -> &ReportGaugeMap {
87        &self.gauges
88    }
89    pub fn stats(&self) -> &ReportStatMap {
90        &self.stats
91    }
92    pub fn is_empty(&self) -> bool {
93        self.counters.is_empty() && self.gauges.is_empty() && self.stats.is_empty()
94    }
95    pub fn len(&self) -> usize {
96        self.counters.len() + self.gauges.len() + self.stats.len()
97    }
98}