khora_telemetry/utils/
timer.rs

1// Copyright 2025 eraflo
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Provides RAII-based timers for automatically recording metrics. (RAII = Resource Acquisition Is Initialization)
16
17use crate::metrics::registry::HistogramHandle;
18use khora_core::utils::timer::Stopwatch;
19
20/// A utility for timing the duration of a scope and automatically recording
21/// the result in a `Histogram` when it is dropped.
22///
23/// This leverages the RAII pattern to ensure that the measurement is always
24// recorded, even in the case of early returns or panics.
25pub struct ScopedMetricTimer<'a> {
26    stopwatch: Stopwatch,
27    histogram: &'a HistogramHandle,
28}
29
30impl<'a> ScopedMetricTimer<'a> {
31    /// Creates a new timer for the given histogram and starts it immediately.
32    pub fn new(histogram: &'a HistogramHandle) -> Self {
33        Self {
34            stopwatch: Stopwatch::new(),
35            histogram,
36        }
37    }
38}
39
40/// When the timer goes out of scope, it records the elapsed time in milliseconds.
41impl<'a> Drop for ScopedMetricTimer<'a> {
42    fn drop(&mut self) {
43        if let Some(elapsed_secs) = self.stopwatch.elapsed_secs_f64() {
44            let elapsed_ms = elapsed_secs * 1000.0;
45            if let Err(e) = self.histogram.observe(elapsed_ms) {
46                log::warn!("[ScopedMetricTimer] Failed to record metric: {:?}", e);
47            }
48        }
49    }
50}