1use rkyv::{Archive, Deserialize, Serialize};
7use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize};
8
9#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize, SerdeSerialize, SerdeDeserialize)]
11pub struct MetricsResult {
12 pub uptime_secs: u64,
14 pub queries: QueryMetrics,
16 pub mutations: MutationMetrics,
18 pub cache: CacheMetrics,
20 pub storage: StorageMetrics,
22 pub transport: TransportMetrics,
24}
25
26#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize, SerdeSerialize, SerdeDeserialize)]
28pub struct QueryMetrics {
29 pub total_count: u64,
31 pub avg_duration_us: u64,
33 pub p50_duration_us: u64,
35 pub p99_duration_us: u64,
37 pub max_duration_us: u64,
39 pub by_entity: Vec<EntityQueryCount>,
41}
42
43#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize, SerdeSerialize, SerdeDeserialize)]
45pub struct EntityQueryCount {
46 pub entity: String,
48 pub count: u64,
50}
51
52#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize, SerdeSerialize, SerdeDeserialize)]
54pub struct MutationMetrics {
55 pub total_count: u64,
57 pub inserts: u64,
59 pub updates: u64,
61 pub deletes: u64,
63 pub upserts: u64,
65 pub rows_affected: u64,
67}
68
69#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize, SerdeSerialize, SerdeDeserialize)]
71pub struct CacheMetrics {
72 pub hits: u64,
74 pub misses: u64,
76 pub hit_rate: f64,
78 pub size: u64,
80 pub capacity: u64,
82 pub evictions: u64,
84}
85
86#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize, SerdeSerialize, SerdeDeserialize)]
88pub struct StorageMetrics {
89 pub entity_counts: Vec<EntityCount>,
91 pub total_entities: u64,
93 pub size_bytes: Option<u64>,
95 pub active_transactions: u64,
97}
98
99#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize, SerdeSerialize, SerdeDeserialize)]
101pub struct EntityCount {
102 pub entity: String,
104 pub count: u64,
106}
107
108#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize, SerdeSerialize, SerdeDeserialize)]
110pub struct TransportMetrics {
111 pub requests_total: u64,
113 pub requests_success: u64,
115 pub requests_failed: u64,
117 pub bytes_received: u64,
119 pub bytes_sent: u64,
121 pub active_connections: u64,
123}
124
125impl MetricsResult {
126 pub fn new(
128 uptime_secs: u64,
129 queries: QueryMetrics,
130 mutations: MutationMetrics,
131 cache: CacheMetrics,
132 storage: StorageMetrics,
133 transport: TransportMetrics,
134 ) -> Self {
135 Self {
136 uptime_secs,
137 queries,
138 mutations,
139 cache,
140 storage,
141 transport,
142 }
143 }
144}
145
146impl Default for QueryMetrics {
147 fn default() -> Self {
148 Self {
149 total_count: 0,
150 avg_duration_us: 0,
151 p50_duration_us: 0,
152 p99_duration_us: 0,
153 max_duration_us: 0,
154 by_entity: Vec::new(),
155 }
156 }
157}
158
159impl Default for MutationMetrics {
160 fn default() -> Self {
161 Self {
162 total_count: 0,
163 inserts: 0,
164 updates: 0,
165 deletes: 0,
166 upserts: 0,
167 rows_affected: 0,
168 }
169 }
170}
171
172impl Default for CacheMetrics {
173 fn default() -> Self {
174 Self {
175 hits: 0,
176 misses: 0,
177 hit_rate: 0.0,
178 size: 0,
179 capacity: 0,
180 evictions: 0,
181 }
182 }
183}
184
185impl Default for StorageMetrics {
186 fn default() -> Self {
187 Self {
188 entity_counts: Vec::new(),
189 total_entities: 0,
190 size_bytes: None,
191 active_transactions: 0,
192 }
193 }
194}
195
196impl Default for TransportMetrics {
197 fn default() -> Self {
198 Self {
199 requests_total: 0,
200 requests_success: 0,
201 requests_failed: 0,
202 bytes_received: 0,
203 bytes_sent: 0,
204 active_connections: 0,
205 }
206 }
207}
208
209impl QueryMetrics {
210 pub fn new(
212 total_count: u64,
213 avg_duration_us: u64,
214 p50_duration_us: u64,
215 p99_duration_us: u64,
216 max_duration_us: u64,
217 ) -> Self {
218 Self {
219 total_count,
220 avg_duration_us,
221 p50_duration_us,
222 p99_duration_us,
223 max_duration_us,
224 by_entity: Vec::new(),
225 }
226 }
227
228 pub fn with_entity_count(mut self, entity: impl Into<String>, count: u64) -> Self {
230 self.by_entity.push(EntityQueryCount {
231 entity: entity.into(),
232 count,
233 });
234 self
235 }
236}
237
238impl CacheMetrics {
239 pub fn new(hits: u64, misses: u64, size: u64, capacity: u64, evictions: u64) -> Self {
241 let total = hits + misses;
242 let hit_rate = if total > 0 {
243 hits as f64 / total as f64
244 } else {
245 0.0
246 };
247 Self {
248 hits,
249 misses,
250 hit_rate,
251 size,
252 capacity,
253 evictions,
254 }
255 }
256}
257
258impl MutationMetrics {
259 pub fn new(inserts: u64, updates: u64, deletes: u64, upserts: u64, rows_affected: u64) -> Self {
261 Self {
262 total_count: inserts + updates + deletes + upserts,
263 inserts,
264 updates,
265 deletes,
266 upserts,
267 rows_affected,
268 }
269 }
270}
271
272impl TransportMetrics {
273 pub fn new(
275 requests_total: u64,
276 requests_success: u64,
277 requests_failed: u64,
278 bytes_received: u64,
279 bytes_sent: u64,
280 active_connections: u64,
281 ) -> Self {
282 Self {
283 requests_total,
284 requests_success,
285 requests_failed,
286 bytes_received,
287 bytes_sent,
288 active_connections,
289 }
290 }
291}
292
293#[cfg(test)]
294mod tests {
295 use super::*;
296
297 #[test]
298 fn test_metrics_result_serialization() {
299 let result = MetricsResult::new(
300 3600,
301 QueryMetrics::new(1000, 2500, 1500, 15000, 50000)
302 .with_entity_count("User", 500)
303 .with_entity_count("Post", 300),
304 MutationMetrics::new(100, 50, 20, 10, 180),
305 CacheMetrics::new(800, 200, 128, 1000, 50),
306 StorageMetrics::default(),
307 TransportMetrics::new(1200, 1150, 50, 1024 * 1024, 2 * 1024 * 1024, 5),
308 );
309
310 let bytes = rkyv::to_bytes::<rkyv::rancor::Error>(&result).unwrap();
311 let archived =
312 rkyv::access::<ArchivedMetricsResult, rkyv::rancor::Error>(&bytes).unwrap();
313 let deserialized: MetricsResult =
314 rkyv::deserialize::<MetricsResult, rkyv::rancor::Error>(archived).unwrap();
315
316 assert_eq!(result, deserialized);
317 }
318
319 #[test]
320 fn test_cache_hit_rate() {
321 let cache = CacheMetrics::new(80, 20, 50, 100, 5);
322 assert!((cache.hit_rate - 0.8).abs() < 0.001);
323 }
324
325 #[test]
326 fn test_mutation_total_count() {
327 let mutations = MutationMetrics::new(10, 5, 3, 2, 20);
328 assert_eq!(mutations.total_count, 20); }
330}