codetether_agent/telemetry/tokens/
counter.rs1use chrono::Utc;
8use std::collections::HashMap;
9use std::sync::atomic::{AtomicU64, Ordering};
10use tokio::sync::Mutex;
11
12use super::snapshot::{GlobalTokenSnapshot, TokenUsageSnapshot};
13use super::totals::TokenTotals;
14
15#[derive(Debug)]
33pub struct AtomicTokenCounter {
34 pub(super) prompt_tokens: AtomicU64,
35 pub(super) completion_tokens: AtomicU64,
36 pub(super) total_tokens: AtomicU64,
37 pub(super) request_count: AtomicU64,
38 pub(super) model_usage: Mutex<HashMap<String, (u64, u64)>>,
39 pub(super) model_cache_usage: Mutex<HashMap<String, (u64, u64)>>,
43 pub(super) model_last_prompt_tokens: Mutex<HashMap<String, u64>>,
47}
48
49impl AtomicTokenCounter {
50 pub fn new() -> Self {
52 Self {
53 prompt_tokens: AtomicU64::new(0),
54 completion_tokens: AtomicU64::new(0),
55 total_tokens: AtomicU64::new(0),
56 request_count: AtomicU64::new(0),
57 model_usage: Mutex::new(HashMap::new()),
58 model_cache_usage: Mutex::new(HashMap::new()),
59 model_last_prompt_tokens: Mutex::new(HashMap::new()),
60 }
61 }
62
63 pub fn record(&self, prompt: u64, completion: u64) {
66 self.prompt_tokens.fetch_add(prompt, Ordering::Relaxed);
67 self.completion_tokens
68 .fetch_add(completion, Ordering::Relaxed);
69 self.total_tokens
70 .fetch_add(prompt + completion, Ordering::Relaxed);
71 self.request_count.fetch_add(1, Ordering::Relaxed);
72 }
73
74 pub fn get(&self) -> (u64, u64, u64) {
76 (
77 self.prompt_tokens.load(Ordering::Relaxed),
78 self.completion_tokens.load(Ordering::Relaxed),
79 self.total_tokens.load(Ordering::Relaxed),
80 )
81 }
82
83 pub fn global_snapshot(&self) -> GlobalTokenSnapshot {
85 let (prompt, completion, total) = self.get();
86 let mut snapshot = GlobalTokenSnapshot::new(prompt, completion, total);
87 snapshot.request_count = self.request_count.load(Ordering::Relaxed);
88 snapshot
89 }
90
91 pub fn model_snapshots(&self) -> Vec<TokenUsageSnapshot> {
94 let Ok(usage) = self.model_usage.try_lock() else {
95 return Vec::new();
96 };
97 usage
98 .iter()
99 .map(|(name, (input, output))| TokenUsageSnapshot {
100 name: name.clone(),
101 prompt_tokens: *input,
102 completion_tokens: *output,
103 total_tokens: input + output,
104 totals: TokenTotals::new(*input, *output),
105 timestamp: Utc::now(),
106 request_count: 0,
107 })
108 .collect()
109 }
110}
111
112impl Default for AtomicTokenCounter {
113 fn default() -> Self {
114 Self::new()
115 }
116}
117
118mod record_model;