aether/sandbox/
metrics.rs

1//! 可观测性指标收集
2//!
3//! 收集运行时指标,支持监控和调试。
4
5use crate::cache::CacheStats;
6use std::sync::RwLock;
7use std::time::{Duration, Instant};
8
9/// 执行指标
10#[derive(Debug, Clone)]
11pub struct ExecutionMetrics {
12    /// 执行次数
13    pub execution_count: usize,
14    /// 总执行时间
15    pub total_duration: Duration,
16    /// 平均执行时间
17    pub average_duration: Duration,
18    /// 最小执行时间
19    pub min_duration: Duration,
20    /// 最大执行时间
21    pub max_duration: Duration,
22}
23
24impl Default for ExecutionMetrics {
25    fn default() -> Self {
26        Self {
27            execution_count: 0,
28            total_duration: Duration::ZERO,
29            average_duration: Duration::ZERO,
30            min_duration: Duration::MAX,
31            max_duration: Duration::ZERO,
32        }
33    }
34}
35
36/// 模块加载指标
37#[derive(Debug, Clone)]
38pub struct ModuleMetrics {
39    /// 模块加载次数
40    pub load_count: usize,
41    /// 缓存命中次数
42    pub cache_hits: usize,
43    /// 缓存未命中次数
44    pub cache_misses: usize,
45    /// 缓存命中率
46    pub hit_rate: f64,
47}
48
49impl Default for ModuleMetrics {
50    fn default() -> Self {
51        Self {
52            load_count: 0,
53            cache_hits: 0,
54            cache_misses: 0,
55            hit_rate: 0.0,
56        }
57    }
58}
59
60/// 综合指标快照
61#[derive(Debug, Clone)]
62pub struct MetricsSnapshot {
63    /// 执行指标
64    pub execution: ExecutionMetrics,
65    /// 模块指标
66    pub modules: ModuleMetrics,
67    /// TRACE 缓冲区条目数
68    pub trace_entries: usize,
69    /// 模块缓存大小
70    pub module_cache_size: usize,
71    /// AST 缓存统计
72    pub ast_cache: CacheStats,
73}
74
75/// 指标收集器
76pub struct MetricsCollector {
77    /// 是否启用
78    enabled: RwLock<bool>,
79    /// 执行开始时间(当前执行)
80    execution_start: RwLock<Option<Instant>>,
81    /// 执行指标
82    execution: RwLock<ExecutionMetrics>,
83    /// 模块指标
84    modules: RwLock<ModuleMetrics>,
85    /// 各模块的加载次数
86    module_loads: RwLock<std::collections::HashMap<String, usize>>,
87}
88
89impl MetricsCollector {
90    /// 创建新的指标收集器
91    pub fn new() -> Self {
92        Self {
93            enabled: RwLock::new(false),
94            execution_start: RwLock::new(None),
95            execution: RwLock::new(ExecutionMetrics::default()),
96            modules: RwLock::new(ModuleMetrics::default()),
97            module_loads: RwLock::new(std::collections::HashMap::new()),
98        }
99    }
100
101    /// 启用指标收集
102    pub fn enable(&self) {
103        *self.enabled.write().unwrap() = true;
104    }
105
106    /// 禁用指标收集
107    pub fn disable(&self) {
108        *self.enabled.write().unwrap() = false;
109    }
110
111    /// 是否启用
112    pub fn is_enabled(&self) -> bool {
113        *self.enabled.read().unwrap()
114    }
115
116    /// 记录执行开始
117    pub fn record_execution_start(&self) {
118        if !self.is_enabled() {
119            return;
120        }
121        *self.execution_start.write().unwrap() = Some(Instant::now());
122    }
123
124    /// 记录执行结束
125    pub fn record_execution_end(&self) {
126        if !self.is_enabled() {
127            return;
128        }
129
130        let start = self.execution_start.write().unwrap().take();
131        if let Some(start_time) = start {
132            let duration = start_time.elapsed();
133
134            let mut exec = self.execution.write().unwrap();
135            exec.execution_count += 1;
136            exec.total_duration += duration;
137            exec.average_duration = exec.total_duration / exec.execution_count as u32;
138            exec.min_duration = exec.min_duration.min(duration);
139            exec.max_duration = exec.max_duration.max(duration);
140        }
141    }
142
143    /// 记录模块加载
144    pub fn record_module_load(&self, module_id: &str, cached: bool) {
145        if !self.is_enabled() {
146            return;
147        }
148
149        let mut modules = self.modules.write().unwrap();
150        modules.load_count += 1;
151        if cached {
152            modules.cache_hits += 1;
153        } else {
154            modules.cache_misses += 1;
155        }
156        if modules.load_count > 0 {
157            modules.hit_rate = modules.cache_hits as f64 / modules.load_count as f64;
158        }
159
160        let mut loads = self.module_loads.write().unwrap();
161        *loads.entry(module_id.to_string()).or_insert(0) += 1;
162    }
163
164    /// 获取当前指标快照
165    pub fn snapshot(
166        &self,
167        trace_entries: usize,
168        module_cache_size: usize,
169        ast_cache: &CacheStats,
170    ) -> MetricsSnapshot {
171        MetricsSnapshot {
172            execution: self.execution.read().unwrap().clone(),
173            modules: self.modules.read().unwrap().clone(),
174            trace_entries,
175            module_cache_size,
176            ast_cache: ast_cache.clone(),
177        }
178    }
179
180    /// 重置所有指标
181    pub fn reset(&self) {
182        *self.execution.write().unwrap() = ExecutionMetrics::default();
183        *self.modules.write().unwrap() = ModuleMetrics::default();
184        self.module_loads.write().unwrap().clear();
185    }
186
187    /// 获取模块加载次数(用于调试)
188    pub fn module_load_count(&self, module_id: &str) -> usize {
189        self.module_loads
190            .read()
191            .unwrap()
192            .get(module_id)
193            .copied()
194            .unwrap_or(0)
195    }
196
197    /// 获取所有模块加载次数
198    pub fn all_module_loads(&self) -> std::collections::HashMap<String, usize> {
199        self.module_loads.read().unwrap().clone()
200    }
201}
202
203impl Default for MetricsCollector {
204    fn default() -> Self {
205        Self::new()
206    }
207}
208
209#[cfg(test)]
210mod tests {
211    use super::*;
212
213    #[test]
214    fn test_metrics_collector_enable_disable() {
215        let collector = MetricsCollector::new();
216        assert!(!collector.is_enabled());
217
218        collector.enable();
219        assert!(collector.is_enabled());
220
221        collector.disable();
222        assert!(!collector.is_enabled());
223    }
224
225    #[test]
226    fn test_execution_metrics() {
227        let collector = MetricsCollector::new();
228        collector.enable();
229
230        // 记录执行
231        collector.record_execution_start();
232        std::thread::sleep(Duration::from_millis(10));
233        collector.record_execution_end();
234
235        let snapshot = collector.snapshot(
236            0,
237            0,
238            &CacheStats {
239                size: 0,
240                max_size: 0,
241                hits: 0,
242                misses: 0,
243                hit_rate: 0.0,
244            },
245        );
246
247        assert_eq!(snapshot.execution.execution_count, 1);
248        assert!(snapshot.execution.total_duration.as_millis() >= 10);
249        assert_eq!(
250            snapshot.execution.min_duration,
251            snapshot.execution.max_duration
252        );
253    }
254
255    #[test]
256    fn test_module_metrics() {
257        let collector = MetricsCollector::new();
258        collector.enable();
259
260        // 记录模块加载
261        collector.record_module_load("test_module", false); // 未命中
262        collector.record_module_load("test_module", true); // 命中
263        collector.record_module_load("other_module", true); // 命中
264
265        let snapshot = collector.snapshot(
266            0,
267            0,
268            &CacheStats {
269                size: 0,
270                max_size: 0,
271                hits: 0,
272                misses: 0,
273                hit_rate: 0.0,
274            },
275        );
276
277        assert_eq!(snapshot.modules.load_count, 3);
278        assert_eq!(snapshot.modules.cache_hits, 2);
279        assert_eq!(snapshot.modules.cache_misses, 1);
280        assert!((snapshot.modules.hit_rate - 0.666).abs() < 0.01); // 约 66.6%
281    }
282
283    #[test]
284    fn test_metrics_disabled_no_collect() {
285        let collector = MetricsCollector::new();
286        // 不启用
287
288        collector.record_execution_start();
289        collector.record_execution_end();
290        collector.record_module_load("test", true);
291
292        let snapshot = collector.snapshot(
293            0,
294            0,
295            &CacheStats {
296                size: 0,
297                max_size: 0,
298                hits: 0,
299                misses: 0,
300                hit_rate: 0.0,
301            },
302        );
303
304        // 所有指标都应该是 0
305        assert_eq!(snapshot.execution.execution_count, 0);
306        assert_eq!(snapshot.modules.load_count, 0);
307    }
308
309    #[test]
310    fn test_metrics_reset() {
311        let collector = MetricsCollector::new();
312        collector.enable();
313
314        collector.record_execution_start();
315        collector.record_execution_end();
316        collector.record_module_load("test", true);
317
318        collector.reset();
319
320        let snapshot = collector.snapshot(
321            0,
322            0,
323            &CacheStats {
324                size: 0,
325                max_size: 0,
326                hits: 0,
327                misses: 0,
328                hit_rate: 0.0,
329            },
330        );
331
332        assert_eq!(snapshot.execution.execution_count, 0);
333        assert_eq!(snapshot.modules.load_count, 0);
334        assert_eq!(collector.all_module_loads().len(), 0);
335    }
336
337    #[test]
338    fn test_module_load_counts() {
339        let collector = MetricsCollector::new();
340        collector.enable();
341
342        collector.record_module_load("module_a", false);
343        collector.record_module_load("module_a", false);
344        collector.record_module_load("module_b", true);
345
346        assert_eq!(collector.module_load_count("module_a"), 2);
347        assert_eq!(collector.module_load_count("module_b"), 1);
348        assert_eq!(collector.module_load_count("module_c"), 0);
349
350        let loads = collector.all_module_loads();
351        assert_eq!(loads.len(), 2);
352    }
353}