metrics_procession/
recorder.rs1use std::sync::{Arc, Mutex, MutexGuard};
2
3use metrics::{CounterFn, GaugeFn, HistogramFn, Recorder};
4
5use crate::{
6 event::{Entry, Op},
7 procession::Procession,
8};
9
10#[derive(Debug, Clone, Default)]
11pub struct ProcessionRecorder(Arc<Mutex<Procession>>);
12
13impl ProcessionRecorder {
14 pub fn lock(&self) -> MutexGuard<Procession> {
15 self.0.lock().unwrap_or_else(|e| e.into_inner())
16 }
17 pub fn memory_size(&self) -> usize {
18 self.0.lock().unwrap().memory_size()
19 }
20}
21
22impl Recorder for ProcessionRecorder {
23 fn describe_counter(
24 &self,
25 _: metrics::KeyName,
26 _: Option<metrics::Unit>,
27 _: metrics::SharedString,
28 ) {
29 }
30
31 fn describe_gauge(
32 &self,
33 _: metrics::KeyName,
34 _: Option<metrics::Unit>,
35 _: metrics::SharedString,
36 ) {
37 }
38
39 fn describe_histogram(
40 &self,
41 _: metrics::KeyName,
42 _: Option<metrics::Unit>,
43 _: metrics::SharedString,
44 ) {
45 }
46
47 fn register_counter(&self, key: &metrics::Key, _: &metrics::Metadata<'_>) -> metrics::Counter {
48 let label = self.0.lock().unwrap().ensure_label(key);
49 metrics::Counter::from_arc(Arc::new(Counter(label, self.clone())))
50 }
51
52 fn register_gauge(&self, key: &metrics::Key, _: &metrics::Metadata<'_>) -> metrics::Gauge {
53 let label = self.0.lock().unwrap().ensure_label(key);
54 metrics::Gauge::from_arc(Arc::new(Gauge(label, self.clone())))
55 }
56
57 fn register_histogram(
58 &self,
59 key: &metrics::Key,
60 _: &metrics::Metadata<'_>,
61 ) -> metrics::Histogram {
62 let label = self.0.lock().unwrap().ensure_label(key);
63 metrics::Histogram::from_arc(Arc::new(Histo(label, self.clone())))
64 }
65}
66
67struct Counter(u16, ProcessionRecorder);
68
69impl CounterFn for Counter {
70 fn increment(&self, value: u64) {
71 self.insert(value, Op::Add);
72 }
73
74 fn absolute(&self, value: u64) {
75 self.insert(value, Op::Set);
76 }
77}
78
79impl Counter {
80 pub fn insert(&self, value: u64, op: Op) {
81 let Ok(value) = u32::try_from(value) else {
82 eprintln!("value has exceeded a u32, skipping event");
83 return;
84 };
85 self.1
86 .0
87 .lock()
88 .unwrap()
89 .insert_entry(Entry::Counter { value, op }, self.0);
90 }
91}
92
93struct Gauge(u16, ProcessionRecorder);
94
95impl GaugeFn for Gauge {
96 fn increment(&self, value: f64) {
97 self.1.0.lock().unwrap().insert_entry(
98 Entry::Gauge {
99 value: value as f32,
100 op: Op::Add,
101 },
102 self.0,
103 );
104 }
105
106 fn decrement(&self, value: f64) {
107 self.1.0.lock().unwrap().insert_entry(
108 Entry::Gauge {
109 value: value as f32,
110 op: Op::Sub,
111 },
112 self.0,
113 );
114 }
115
116 fn set(&self, value: f64) {
117 self.1.0.lock().unwrap().insert_entry(
118 Entry::Gauge {
119 value: value as f32,
120 op: Op::Set,
121 },
122 self.0,
123 );
124 }
125}
126
127struct Histo(u16, ProcessionRecorder);
128
129impl HistogramFn for Histo {
130 fn record(&self, value: f64) {
131 self.1.0.lock().unwrap().insert_entry(
132 Entry::Histogram {
133 value: value as f32,
134 },
135 self.0,
136 );
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 #[test]
145 fn install_and_emit() {
146 let recorder = ProcessionRecorder::default();
147 metrics::with_local_recorder(&recorder, || {
148 let ct = metrics::counter!("one_counter");
149 let ct2 = metrics::counter!("with_label", "label" => "this-one");
150 let g = metrics::gauge!("one_gauge");
151 let g2 = metrics::gauge!("with_labels", "label1" => "value1", "label2" => "value2");
152 let h = metrics::histogram!("one_histo");
153 let h2 = metrics::histogram!("with_label", "tid" => format!("{:?}", std::thread::current().id()));
154
155 for i in 0..1000 {
156 ct.increment(1);
157 ct2.increment(2);
158 g.set(i as f64);
159 g2.set((i / 2) as f64);
160 h.record(i as f64);
161 h2.record((i / 2) as f64);
162 }
163 });
164 }
165}