1use crate::{
6 histogram::{Histogram, Sample},
7 meter::{register_meter_with_group, Meter},
8 metrics::is_enabled,
9};
10use std::{
11 sync::Arc,
12 time::{Duration, Instant},
13};
14
15pub trait Timer: Send + Sync {
16 fn update(&self, _d: Duration) {}
17
18 fn update_since(&self, start_time: Instant) {
19 self.update(Instant::now().saturating_duration_since(start_time));
20 }
21}
22
23fn register_timer_exp_decay(
24 group: &str, counter_name: &str, time_name: &str,
25) -> Arc<dyn Timer> {
26 if !is_enabled() {
27 Arc::new(NoopTimer)
28 } else {
29 Arc::new(StandardTimer {
30 meter: register_meter_with_group(group, counter_name),
31 histogram: Sample::ExpDecay(0.015)
32 .register_with_group(group, time_name, 1024),
33 })
34 }
35}
36
37pub fn register_timer(name: &str) -> Arc<dyn Timer> {
38 register_timer_exp_decay(name, "counter", "time_expdec")
39}
40
41pub fn register_timer_with_group(group: &str, name: &str) -> Arc<dyn Timer> {
42 let counter_name = format!("{}_counter", name);
43 let time_name = format!("{}_time_expdec", name);
44 register_timer_exp_decay(group, counter_name.as_str(), time_name.as_str())
45}
46
47struct NoopTimer;
48impl Timer for NoopTimer {}
49
50struct StandardTimer {
51 meter: Arc<dyn Meter>,
52 histogram: Arc<dyn Histogram>,
53}
54
55impl Timer for StandardTimer {
56 fn update(&self, d: Duration) {
57 self.meter.mark(1);
58 self.histogram.update(d.as_nanos() as u64);
59 }
60}
61
62pub struct ScopeTimer {
63 timer: Arc<dyn Timer>,
64 start: Instant,
65}
66
67impl ScopeTimer {
68 pub fn time_scope(timer: Arc<dyn Timer>) -> Self {
72 Self {
73 timer,
74 start: Instant::now(),
75 }
76 }
77}
78
79impl Drop for ScopeTimer {
80 fn drop(&mut self) { self.timer.update_since(self.start) }
81}