a2a_protocol_server/
metrics.rs1use std::sync::Arc;
31use std::time::Duration;
32
33#[derive(Debug, Clone, Copy, Default)]
37pub struct ConnectionPoolStats {
38 pub active_connections: u32,
40 pub idle_connections: u32,
42 pub total_connections_created: u64,
44 pub connections_closed: u64,
46}
47
48pub trait Metrics: Send + Sync + 'static {
53 fn on_request(&self, _method: &str) {}
55
56 fn on_response(&self, _method: &str) {}
58
59 fn on_error(&self, _method: &str, _error_kind: &str) {}
67
68 fn on_latency(&self, _method: &str, _duration: Duration) {}
74
75 fn on_queue_depth_change(&self, _active_queues: usize) {}
77
78 fn on_connection_pool_stats(&self, _stats: &ConnectionPoolStats) {}
82}
83
84#[derive(Debug, Default)]
86pub struct NoopMetrics;
87
88impl Metrics for NoopMetrics {}
89
90impl<T: Metrics + ?Sized> Metrics for Arc<T> {
95 fn on_request(&self, method: &str) {
96 (**self).on_request(method);
97 }
98
99 fn on_response(&self, method: &str) {
100 (**self).on_response(method);
101 }
102
103 fn on_error(&self, method: &str, error: &str) {
104 (**self).on_error(method, error);
105 }
106
107 fn on_latency(&self, method: &str, duration: Duration) {
108 (**self).on_latency(method, duration);
109 }
110
111 fn on_queue_depth_change(&self, active_queues: usize) {
112 (**self).on_queue_depth_change(active_queues);
113 }
114
115 fn on_connection_pool_stats(&self, stats: &ConnectionPoolStats) {
116 (**self).on_connection_pool_stats(stats);
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use std::sync::atomic::{AtomicU64, Ordering};
124
125 struct RecordingMetrics {
127 requests: AtomicU64,
128 responses: AtomicU64,
129 errors: AtomicU64,
130 latencies: AtomicU64,
131 queue_depths: AtomicU64,
132 pool_stats: AtomicU64,
133 }
134
135 impl RecordingMetrics {
136 fn new() -> Self {
137 Self {
138 requests: AtomicU64::new(0),
139 responses: AtomicU64::new(0),
140 errors: AtomicU64::new(0),
141 latencies: AtomicU64::new(0),
142 queue_depths: AtomicU64::new(0),
143 pool_stats: AtomicU64::new(0),
144 }
145 }
146 }
147
148 impl Metrics for RecordingMetrics {
149 fn on_request(&self, _method: &str) {
150 self.requests.fetch_add(1, Ordering::Relaxed);
151 }
152 fn on_response(&self, _method: &str) {
153 self.responses.fetch_add(1, Ordering::Relaxed);
154 }
155 fn on_error(&self, _method: &str, _error: &str) {
156 self.errors.fetch_add(1, Ordering::Relaxed);
157 }
158 fn on_latency(&self, _method: &str, _duration: Duration) {
159 self.latencies.fetch_add(1, Ordering::Relaxed);
160 }
161 fn on_queue_depth_change(&self, _active_queues: usize) {
162 self.queue_depths.fetch_add(1, Ordering::Relaxed);
163 }
164 fn on_connection_pool_stats(&self, _stats: &ConnectionPoolStats) {
165 self.pool_stats.fetch_add(1, Ordering::Relaxed);
166 }
167 }
168
169 #[test]
170 fn arc_delegates_on_request() {
171 let inner = Arc::new(RecordingMetrics::new());
172 let arc_metrics: Arc<RecordingMetrics> = Arc::clone(&inner);
173 arc_metrics.on_request("test");
174 assert_eq!(inner.requests.load(Ordering::Relaxed), 1);
175 }
176
177 #[test]
178 fn arc_delegates_on_response() {
179 let inner = Arc::new(RecordingMetrics::new());
180 let arc_metrics: Arc<RecordingMetrics> = Arc::clone(&inner);
181 arc_metrics.on_response("test");
182 assert_eq!(inner.responses.load(Ordering::Relaxed), 1);
183 }
184
185 #[test]
186 fn arc_delegates_on_error() {
187 let inner = Arc::new(RecordingMetrics::new());
188 let arc_metrics: Arc<RecordingMetrics> = Arc::clone(&inner);
189 arc_metrics.on_error("test", "err");
190 assert_eq!(inner.errors.load(Ordering::Relaxed), 1);
191 }
192
193 #[test]
194 fn arc_delegates_on_latency() {
195 let inner = Arc::new(RecordingMetrics::new());
196 let arc_metrics: Arc<RecordingMetrics> = Arc::clone(&inner);
197 arc_metrics.on_latency("test", Duration::from_millis(10));
198 assert_eq!(inner.latencies.load(Ordering::Relaxed), 1);
199 }
200
201 #[test]
202 fn arc_delegates_on_queue_depth_change() {
203 let inner = Arc::new(RecordingMetrics::new());
204 let arc_metrics: Arc<RecordingMetrics> = Arc::clone(&inner);
205 arc_metrics.on_queue_depth_change(5);
206 assert_eq!(inner.queue_depths.load(Ordering::Relaxed), 1);
207 }
208
209 #[test]
210 fn arc_delegates_on_connection_pool_stats() {
211 let inner = Arc::new(RecordingMetrics::new());
212 let arc_metrics: Arc<RecordingMetrics> = Arc::clone(&inner);
213 arc_metrics.on_connection_pool_stats(&ConnectionPoolStats::default());
214 assert_eq!(inner.pool_stats.load(Ordering::Relaxed), 1);
215 }
216}