Skip to main content

ormdb_proto/
metrics.rs

1//! Server metrics types.
2//!
3//! These types are returned by the GetMetrics operation to provide
4//! server statistics and performance information.
5
6use rkyv::{Archive, Deserialize, Serialize};
7use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize};
8
9/// Server metrics response.
10#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize, SerdeSerialize, SerdeDeserialize)]
11pub struct MetricsResult {
12    /// Server uptime in seconds.
13    pub uptime_secs: u64,
14    /// Query metrics.
15    pub queries: QueryMetrics,
16    /// Mutation metrics.
17    pub mutations: MutationMetrics,
18    /// Plan cache metrics.
19    pub cache: CacheMetrics,
20    /// Storage metrics.
21    pub storage: StorageMetrics,
22    /// Transport layer metrics.
23    pub transport: TransportMetrics,
24}
25
26/// Query-related metrics.
27#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize, SerdeSerialize, SerdeDeserialize)]
28pub struct QueryMetrics {
29    /// Total queries executed.
30    pub total_count: u64,
31    /// Average query time in microseconds.
32    pub avg_duration_us: u64,
33    /// P50 (median) query time in microseconds.
34    pub p50_duration_us: u64,
35    /// P99 query time in microseconds.
36    pub p99_duration_us: u64,
37    /// Maximum query time in microseconds.
38    pub max_duration_us: u64,
39    /// Queries per entity type.
40    pub by_entity: Vec<EntityQueryCount>,
41}
42
43/// Query count for a specific entity.
44#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize, SerdeSerialize, SerdeDeserialize)]
45pub struct EntityQueryCount {
46    /// Entity name.
47    pub entity: String,
48    /// Number of queries for this entity.
49    pub count: u64,
50}
51
52/// Mutation-related metrics.
53#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize, SerdeSerialize, SerdeDeserialize)]
54pub struct MutationMetrics {
55    /// Total mutations executed.
56    pub total_count: u64,
57    /// Total insert operations.
58    pub inserts: u64,
59    /// Total update operations.
60    pub updates: u64,
61    /// Total delete operations.
62    pub deletes: u64,
63    /// Total upsert operations.
64    pub upserts: u64,
65    /// Total rows affected by mutations.
66    pub rows_affected: u64,
67}
68
69/// Plan cache metrics.
70#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize, SerdeSerialize, SerdeDeserialize)]
71pub struct CacheMetrics {
72    /// Cache hits.
73    pub hits: u64,
74    /// Cache misses.
75    pub misses: u64,
76    /// Hit rate (0.0 - 1.0).
77    pub hit_rate: f64,
78    /// Current number of cached plans.
79    pub size: u64,
80    /// Maximum cache capacity.
81    pub capacity: u64,
82    /// Number of evictions.
83    pub evictions: u64,
84}
85
86/// Storage metrics.
87#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize, SerdeSerialize, SerdeDeserialize)]
88pub struct StorageMetrics {
89    /// Entity counts by type.
90    pub entity_counts: Vec<EntityCount>,
91    /// Total entities across all types.
92    pub total_entities: u64,
93    /// Storage size in bytes (if available).
94    pub size_bytes: Option<u64>,
95    /// Number of active transactions.
96    pub active_transactions: u64,
97}
98
99/// Entity count for a specific type.
100#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize, SerdeSerialize, SerdeDeserialize)]
101pub struct EntityCount {
102    /// Entity type name.
103    pub entity: String,
104    /// Number of records.
105    pub count: u64,
106}
107
108/// Transport layer metrics.
109#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize, SerdeSerialize, SerdeDeserialize)]
110pub struct TransportMetrics {
111    /// Total requests received.
112    pub requests_total: u64,
113    /// Successful requests.
114    pub requests_success: u64,
115    /// Failed requests.
116    pub requests_failed: u64,
117    /// Total bytes received.
118    pub bytes_received: u64,
119    /// Total bytes sent.
120    pub bytes_sent: u64,
121    /// Current active connections.
122    pub active_connections: u64,
123}
124
125impl MetricsResult {
126    /// Create a new metrics result.
127    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    /// Create new query metrics.
211    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    /// Add entity query count.
229    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    /// Create new cache metrics.
240    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    /// Create new mutation metrics.
260    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    /// Create new transport metrics.
274    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); // 10 + 5 + 3 + 2
329    }
330}