Skip to main content

zentinel_proxy/agents/
metrics.rs

1//! Agent metrics collection.
2
3use std::sync::atomic::{AtomicU64, Ordering};
4
5/// Agent metrics collector.
6///
7/// Tracks call counts, success/failure rates, and decision distributions.
8#[derive(Default)]
9pub struct AgentMetrics {
10    /// Total calls
11    pub calls_total: AtomicU64,
12    /// Successful calls
13    pub calls_success: AtomicU64,
14    /// Failed calls
15    pub calls_failed: AtomicU64,
16    /// Timeout calls
17    pub calls_timeout: AtomicU64,
18    /// Circuit breaker trips
19    pub circuit_breaker_trips: AtomicU64,
20    /// Total call duration (microseconds)
21    pub duration_total_us: AtomicU64,
22    /// Decisions by type
23    pub decisions_allow: AtomicU64,
24    pub decisions_block: AtomicU64,
25    pub decisions_redirect: AtomicU64,
26    pub decisions_challenge: AtomicU64,
27    /// Bodies that exceeded an agent's inspection limit and skipped it (fail-open)
28    pub body_size_skips: AtomicU64,
29}
30
31impl AgentMetrics {
32    /// Create a new metrics instance.
33    pub fn new() -> Self {
34        Self::default()
35    }
36
37    /// Record a successful call with duration.
38    pub fn record_success(&self, duration_us: u64) {
39        self.calls_total.fetch_add(1, Ordering::Relaxed);
40        self.calls_success.fetch_add(1, Ordering::Relaxed);
41        self.duration_total_us
42            .fetch_add(duration_us, Ordering::Relaxed);
43    }
44
45    /// Record a failed call.
46    pub fn record_failure(&self) {
47        self.calls_total.fetch_add(1, Ordering::Relaxed);
48        self.calls_failed.fetch_add(1, Ordering::Relaxed);
49    }
50
51    /// Record a timeout.
52    pub fn record_timeout(&self) {
53        self.calls_total.fetch_add(1, Ordering::Relaxed);
54        self.calls_timeout.fetch_add(1, Ordering::Relaxed);
55    }
56
57    /// Record a body that exceeded an agent's inspection limit (fail-open skip).
58    pub fn record_body_size_skip(&self) {
59        self.body_size_skips.fetch_add(1, Ordering::Relaxed);
60    }
61
62    /// Get average call duration in microseconds.
63    pub fn average_duration_us(&self) -> f64 {
64        let total = self.duration_total_us.load(Ordering::Relaxed) as f64;
65        let success = self.calls_success.load(Ordering::Relaxed) as f64;
66        if success > 0.0 {
67            total / success
68        } else {
69            0.0
70        }
71    }
72}