1use std::sync::atomic::{AtomicU64, Ordering};
7
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Default)]
15pub struct ActorMetrics {
16 pub messages_received: AtomicU64,
18 pub messages_processed: AtomicU64,
20 pub messages_failed: AtomicU64,
22 pub heartbeats: AtomicU64,
24 pub last_message_at: AtomicU64,
26 pub restart_count: AtomicU64,
28 pub llm_input_tokens: AtomicU64,
30 pub llm_output_tokens: AtomicU64,
32 pub llm_cost_nano_usd: AtomicU64,
34}
35
36impl ActorMetrics {
37 pub fn new() -> Self {
38 Self::default()
39 }
40
41 pub fn record_received(&self) {
42 self.messages_received.fetch_add(1, Ordering::Relaxed);
43 let now = std::time::SystemTime::now()
44 .duration_since(std::time::UNIX_EPOCH)
45 .unwrap_or_default()
46 .as_secs();
47 self.last_message_at.store(now, Ordering::Relaxed);
48 }
49
50 pub fn record_processed(&self) {
51 self.messages_processed.fetch_add(1, Ordering::Relaxed);
52 }
53
54 pub fn record_failed(&self) {
55 self.messages_failed.fetch_add(1, Ordering::Relaxed);
56 }
57
58 pub fn record_heartbeat(&self) {
59 self.heartbeats.fetch_add(1, Ordering::Relaxed);
60 }
61
62 pub fn record_restart(&self) {
63 self.restart_count.fetch_add(1, Ordering::Relaxed);
64 }
65
66 pub fn record_llm_usage(&self, input_tokens: u64, output_tokens: u64, cost_nano_usd: u64) {
68 self.llm_input_tokens
69 .fetch_add(input_tokens, Ordering::Relaxed);
70 self.llm_output_tokens
71 .fetch_add(output_tokens, Ordering::Relaxed);
72 self.llm_cost_nano_usd
73 .fetch_add(cost_nano_usd, Ordering::Relaxed);
74 }
75
76 pub fn snapshot(&self) -> MetricsSnapshot {
78 MetricsSnapshot {
79 messages_received: self.messages_received.load(Ordering::Relaxed),
80 messages_processed: self.messages_processed.load(Ordering::Relaxed),
81 messages_failed: self.messages_failed.load(Ordering::Relaxed),
82 heartbeats: self.heartbeats.load(Ordering::Relaxed),
83 last_message_at: self.last_message_at.load(Ordering::Relaxed),
84 restart_count: self.restart_count.load(Ordering::Relaxed),
85 llm_input_tokens: self.llm_input_tokens.load(Ordering::Relaxed),
86 llm_output_tokens: self.llm_output_tokens.load(Ordering::Relaxed),
87 llm_cost_usd: self.llm_cost_nano_usd.load(Ordering::Relaxed) as f64 / 1_000_000_000.0,
88 }
89 }
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct MetricsSnapshot {
95 pub messages_received: u64,
96 pub messages_processed: u64,
97 pub messages_failed: u64,
98 pub heartbeats: u64,
99 pub last_message_at: u64,
101 pub restart_count: u64,
103 pub llm_input_tokens: u64,
105 pub llm_output_tokens: u64,
107 pub llm_cost_usd: f64,
109}