Skip to main content

codetether_agent/telemetry/tools/
counter.rs

1//! Lock-free success/failure counter for tool invocations.
2
3use std::sync::atomic::{AtomicU64, Ordering};
4
5/// Cumulative `(total, failures)` counter shared across the whole process.
6///
7/// Prefer the [`super::super::TOOL_EXECUTIONS`] singleton — constructing your
8/// own instance is only useful in tests.
9///
10/// # Examples
11///
12/// ```rust
13/// use codetether_agent::telemetry::AtomicToolCounter;
14///
15/// let c = AtomicToolCounter::new();
16/// c.record(true);
17/// c.record(false);
18/// c.record(true);
19///
20/// let (total, failures) = c.get();
21/// assert_eq!((total, failures), (3, 1));
22/// ```
23#[derive(Debug)]
24pub struct AtomicToolCounter {
25    count: AtomicU64,
26    failures: AtomicU64,
27}
28
29impl AtomicToolCounter {
30    /// Construct a zeroed counter.
31    pub fn new() -> Self {
32        Self {
33            count: AtomicU64::new(0),
34            failures: AtomicU64::new(0),
35        }
36    }
37
38    /// Record a single invocation. Increments `failures` iff `success` is false.
39    pub fn record(&self, success: bool) {
40        self.count.fetch_add(1, Ordering::Relaxed);
41        if !success {
42            self.failures.fetch_add(1, Ordering::Relaxed);
43        }
44    }
45
46    /// Load `(total_invocations, total_failures)` with `Relaxed` ordering.
47    pub fn get(&self) -> (u64, u64) {
48        (
49            self.count.load(Ordering::Relaxed),
50            self.failures.load(Ordering::Relaxed),
51        )
52    }
53}
54
55impl Default for AtomicToolCounter {
56    fn default() -> Self {
57        Self::new()
58    }
59}