Skip to main content

loader/
metrics.rs

1//! Metrics and observability for loader operations.
2//!
3//! Tracks timing, throughput, and other operational metrics.
4
5use std::time::{Duration, Instant};
6use tracing::info;
7
8/// Metrics for a decryption operation
9#[derive(Debug, Clone)]
10pub struct OperationMetrics {
11    pub operation_type: String,
12    pub bytes_processed: usize,
13    pub duration: Duration,
14}
15
16impl OperationMetrics {
17    /// Create new metrics
18    pub fn new(operation_type: impl Into<String>, bytes_processed: usize, duration: Duration) -> Self {
19        Self {
20            operation_type: operation_type.into(),
21            bytes_processed,
22            duration,
23        }
24    }
25
26    /// Log metrics in a structured way
27    pub fn log(&self) {
28        let throughput_mbps = if self.duration.as_secs_f64() > 0.0 {
29            (self.bytes_processed as f64 / (1024.0 * 1024.0)) / self.duration.as_secs_f64()
30        } else {
31            0.0
32        };
33
34        info!(
35            operation = %self.operation_type,
36            bytes = self.bytes_processed,
37            duration_ms = self.duration.as_millis(),
38            throughput_mbps = format!("{:.2}", throughput_mbps),
39            "operation completed"
40        );
41    }
42
43    /// Get throughput in MB/s
44    pub fn throughput_mbps(&self) -> f64 {
45        if self.duration.as_secs_f64() > 0.0 {
46            (self.bytes_processed as f64 / (1024.0 * 1024.0)) / self.duration.as_secs_f64()
47        } else {
48            0.0
49        }
50    }
51}
52
53/// Timer for measuring operation duration
54pub struct Timer {
55    start: Instant,
56}
57
58impl Timer {
59    /// Start a new timer
60    pub fn start() -> Self {
61        Self {
62            start: Instant::now(),
63        }
64    }
65
66    /// Stop timer and return elapsed duration
67    pub fn stop(self) -> Duration {
68        self.start.elapsed()
69    }
70
71    /// Stop timer and create metrics
72    pub fn stop_with_metrics(self, operation_type: impl Into<String>, bytes: usize) -> OperationMetrics {
73        OperationMetrics::new(operation_type, bytes, self.stop())
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn test_metrics_throughput() {
83        let metrics = OperationMetrics::new(
84            "test_op",
85            1_000_000, // 1 MB
86            Duration::from_millis(100),
87        );
88
89        let throughput = metrics.throughput_mbps();
90        assert!(throughput > 9.0 && throughput < 11.0); // ~10 MB/s
91    }
92
93    #[test]
94    fn test_timer() {
95        let timer = Timer::start();
96        std::thread::sleep(Duration::from_millis(10));
97        let duration = timer.stop();
98
99        assert!(duration.as_millis() >= 10);
100    }
101}