open_lark/core/
error_metrics.rs

1/// 错误统计和监控模块
2///
3/// 提供错误的统计分析和监控功能:
4/// - 错误频率统计
5/// - 错误类型分布
6/// - 性能影响分析
7/// - 趋势分析
8/// - 自动告警
9use std::collections::HashMap;
10use std::{
11    sync::{Arc, Mutex},
12    time::{Duration, SystemTime},
13};
14
15use crate::core::{
16    error::LarkAPIError,
17    error_codes::{ErrorCategory, LarkErrorCode},
18    error_helper::ErrorHandlingCategory,
19};
20
21/// 错误事件记录
22#[derive(Debug, Clone)]
23pub struct ErrorEvent {
24    /// 错误实例
25    pub error: LarkAPIError,
26    /// 发生时间
27    pub timestamp: SystemTime,
28    /// 错误分类
29    pub category: ErrorHandlingCategory,
30    /// 错误码(如果是API错误)
31    pub error_code: Option<LarkErrorCode>,
32    /// 是否可重试
33    pub is_retryable: bool,
34    /// 处理耗时(如果有)
35    pub processing_time: Option<Duration>,
36    /// 上下文信息
37    pub context: HashMap<String, String>,
38}
39
40impl ErrorEvent {
41    /// 从LarkAPIError创建错误事件
42    pub fn from_error(error: LarkAPIError) -> Self {
43        let category = match &error {
44            LarkAPIError::ApiError { code, .. } => {
45                if let Some(error_code) = LarkErrorCode::from_code(*code) {
46                    match error_code.category() {
47                        ErrorCategory::Authentication => ErrorHandlingCategory::Authentication,
48                        ErrorCategory::Permission => ErrorHandlingCategory::Permission,
49                        ErrorCategory::Parameter => ErrorHandlingCategory::ClientError,
50                        ErrorCategory::Resource => ErrorHandlingCategory::ClientError,
51                        ErrorCategory::Server => ErrorHandlingCategory::ServerError,
52                        ErrorCategory::Network => ErrorHandlingCategory::NetworkError,
53                        ErrorCategory::RateLimit => ErrorHandlingCategory::RateLimit,
54                        ErrorCategory::Other => ErrorHandlingCategory::Unknown,
55                    }
56                } else {
57                    ErrorHandlingCategory::Unknown
58                }
59            }
60            LarkAPIError::RequestError(_) => ErrorHandlingCategory::NetworkError,
61            LarkAPIError::MissingAccessToken => ErrorHandlingCategory::Authentication,
62            LarkAPIError::IllegalParamError(_) => ErrorHandlingCategory::ClientError,
63            _ => ErrorHandlingCategory::SystemError,
64        };
65
66        let error_code = match &error {
67            LarkAPIError::ApiError { code, .. } => LarkErrorCode::from_code(*code),
68            _ => None,
69        };
70
71        Self {
72            is_retryable: error.is_retryable(),
73            error,
74            timestamp: SystemTime::now(),
75            category,
76            error_code,
77            processing_time: None,
78            context: HashMap::new(),
79        }
80    }
81
82    /// 添加上下文信息
83    pub fn with_context(mut self, key: &str, value: &str) -> Self {
84        self.context.insert(key.to_string(), value.to_string());
85        self
86    }
87
88    /// 设置处理耗时
89    pub fn with_processing_time(mut self, duration: Duration) -> Self {
90        self.processing_time = Some(duration);
91        self
92    }
93
94    /// 获取错误严重级别
95    pub fn severity_level(&self) -> ErrorSeverity {
96        match &self.category {
97            ErrorHandlingCategory::Authentication => ErrorSeverity::Warning,
98            ErrorHandlingCategory::Permission => ErrorSeverity::Error,
99            ErrorHandlingCategory::ClientError => ErrorSeverity::Warning,
100            ErrorHandlingCategory::ServerError => ErrorSeverity::Critical,
101            ErrorHandlingCategory::NetworkError => ErrorSeverity::Warning,
102            ErrorHandlingCategory::RateLimit => ErrorSeverity::Warning,
103            ErrorHandlingCategory::SystemError => ErrorSeverity::Critical,
104            ErrorHandlingCategory::Unknown => ErrorSeverity::Error,
105        }
106    }
107}
108
109/// 错误严重级别
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
111pub enum ErrorSeverity {
112    /// 信息
113    Info,
114    /// 警告
115    Warning,
116    /// 错误
117    Error,
118    /// 严重
119    Critical,
120}
121
122impl ErrorSeverity {
123    /// 获取数值权重(用于排序)
124    pub fn weight(&self) -> u8 {
125        match self {
126            Self::Info => 1,
127            Self::Warning => 2,
128            Self::Error => 3,
129            Self::Critical => 4,
130        }
131    }
132
133    /// 获取显示符号
134    pub fn symbol(&self) -> &'static str {
135        match self {
136            Self::Info => "ℹ️",
137            Self::Warning => "⚠️",
138            Self::Error => "❌",
139            Self::Critical => "🚨",
140        }
141    }
142}
143
144/// 错误统计数据
145#[derive(Debug, Clone, Default)]
146pub struct ErrorStatistics {
147    /// 总错误数
148    pub total_errors: u64,
149    /// 按类别分组的错误数
150    pub errors_by_category: HashMap<ErrorHandlingCategory, u64>,
151    /// 按错误码分组的错误数
152    pub errors_by_code: HashMap<LarkErrorCode, u64>,
153    /// 按严重级别分组的错误数
154    pub errors_by_severity: HashMap<ErrorSeverity, u64>,
155    /// 可重试错误数
156    pub retryable_errors: u64,
157    /// 平均处理时间
158    pub average_processing_time: Option<Duration>,
159    /// 第一个错误时间
160    pub first_error_time: Option<SystemTime>,
161    /// 最后一个错误时间
162    pub last_error_time: Option<SystemTime>,
163}
164
165impl ErrorStatistics {
166    /// 计算错误率(每分钟)
167    pub fn error_rate_per_minute(&self) -> f64 {
168        if let (Some(first), Some(last)) = (self.first_error_time, self.last_error_time) {
169            if let Ok(duration) = last.duration_since(first) {
170                let minutes = duration.as_secs_f64() / 60.0;
171                if minutes > 0.0 {
172                    return self.total_errors as f64 / minutes;
173                }
174            }
175        }
176        0.0
177    }
178
179    /// 获取最常见的错误类别
180    pub fn most_common_category(&self) -> Option<ErrorHandlingCategory> {
181        self.errors_by_category
182            .iter()
183            .max_by_key(|(_, count)| *count)
184            .map(|(category, _)| *category)
185    }
186
187    /// 获取最严重的错误级别
188    pub fn highest_severity(&self) -> Option<ErrorSeverity> {
189        self.errors_by_severity
190            .keys()
191            .max_by_key(|severity| severity.weight())
192            .copied()
193    }
194
195    /// 计算可重试错误百分比
196    pub fn retryable_percentage(&self) -> f64 {
197        if self.total_errors == 0 {
198            0.0
199        } else {
200            (self.retryable_errors as f64 / self.total_errors as f64) * 100.0
201        }
202    }
203
204    /// 打印统计摘要
205    pub fn print_summary(&self) {
206        println!("📊 错误统计摘要:");
207        println!("   总错误数: {}", self.total_errors);
208        println!("   错误率: {:.2} 错误/分钟", self.error_rate_per_minute());
209        println!(
210            "   可重试错误: {} ({:.1}%)",
211            self.retryable_errors,
212            self.retryable_percentage()
213        );
214
215        if let Some(category) = self.most_common_category() {
216            println!("   最常见类别: {category:?}");
217        }
218
219        if let Some(severity) = self.highest_severity() {
220            println!("   最高严重级别: {} {:?}", severity.symbol(), severity);
221        }
222
223        if let Some(avg_time) = self.average_processing_time {
224            println!("   平均处理时间: {avg_time:?}");
225        }
226    }
227
228    /// 打印详细统计
229    pub fn print_detailed(&self) {
230        self.print_summary();
231
232        println!("\n📈 错误分类统计:");
233        for (category, count) in &self.errors_by_category {
234            let percentage = (*count as f64 / self.total_errors as f64) * 100.0;
235            println!("   {category:?}: {count} ({percentage:.1}%)");
236        }
237
238        println!("\n🔢 错误码统计:");
239        let mut sorted_codes: Vec<_> = self.errors_by_code.iter().collect();
240        sorted_codes.sort_by(|a, b| b.1.cmp(a.1));
241        for (code, count) in sorted_codes.iter().take(10) {
242            let percentage = (**count as f64 / self.total_errors as f64) * 100.0;
243            println!("   {code}: {count} ({percentage:.1}%)");
244        }
245
246        println!("\n⚠️ 严重级别统计:");
247        for severity in [
248            ErrorSeverity::Critical,
249            ErrorSeverity::Error,
250            ErrorSeverity::Warning,
251            ErrorSeverity::Info,
252        ] {
253            if let Some(count) = self.errors_by_severity.get(&severity) {
254                let percentage = (*count as f64 / self.total_errors as f64) * 100.0;
255                println!(
256                    "   {} {:?}: {} ({:.1}%)",
257                    severity.symbol(),
258                    severity,
259                    count,
260                    percentage
261                );
262            }
263        }
264    }
265}
266
267/// 错误监控器
268pub struct ErrorMonitor {
269    /// 错误事件历史
270    events: Arc<Mutex<Vec<ErrorEvent>>>,
271    /// 统计数据
272    statistics: Arc<Mutex<ErrorStatistics>>,
273    /// 配置
274    config: MonitorConfig,
275}
276
277/// 监控配置
278#[derive(Debug, Clone)]
279pub struct MonitorConfig {
280    /// 最大保存事件数量
281    pub max_events: usize,
282    /// 统计时间窗口
283    pub time_window: Duration,
284    /// 是否启用自动清理
285    pub auto_cleanup: bool,
286    /// 告警阈值
287    pub alert_thresholds: AlertThresholds,
288}
289
290impl Default for MonitorConfig {
291    fn default() -> Self {
292        Self {
293            max_events: 1000,
294            time_window: Duration::from_secs(24 * 60 * 60), // 24小时
295            auto_cleanup: true,
296            alert_thresholds: AlertThresholds::default(),
297        }
298    }
299}
300
301/// 告警阈值配置
302#[derive(Debug, Clone)]
303pub struct AlertThresholds {
304    /// 错误率阈值(每分钟)
305    pub error_rate_per_minute: f64,
306    /// 严重错误阈值
307    pub critical_errors_count: u64,
308    /// 连续失败阈值
309    pub consecutive_failures: u32,
310}
311
312impl Default for AlertThresholds {
313    fn default() -> Self {
314        Self {
315            error_rate_per_minute: 10.0,
316            critical_errors_count: 5,
317            consecutive_failures: 3,
318        }
319    }
320}
321
322impl Default for ErrorMonitor {
323    fn default() -> Self {
324        Self::new(MonitorConfig::default())
325    }
326}
327
328impl ErrorMonitor {
329    /// 创建新的错误监控器
330    pub fn new(config: MonitorConfig) -> Self {
331        Self {
332            events: Arc::new(Mutex::new(Vec::new())),
333            statistics: Arc::new(Mutex::new(ErrorStatistics::default())),
334            config,
335        }
336    }
337
338    /// 记录错误事件
339    pub fn record_error(&self, error: LarkAPIError) {
340        let event = ErrorEvent::from_error(error);
341        self.record_event(event);
342    }
343
344    /// 记录带上下文的错误事件
345    pub fn record_error_with_context(&self, error: LarkAPIError, context: HashMap<String, String>) {
346        let mut event = ErrorEvent::from_error(error);
347        event.context = context;
348        self.record_event(event);
349    }
350
351    /// 记录错误事件
352    pub fn record_event(&self, event: ErrorEvent) {
353        // 更新统计数据
354        if let Ok(mut stats) = self.statistics.lock() {
355            stats.total_errors += 1;
356
357            // 更新分类统计
358            *stats.errors_by_category.entry(event.category).or_insert(0) += 1;
359
360            // 更新错误码统计
361            if let Some(code) = event.error_code {
362                *stats.errors_by_code.entry(code).or_insert(0) += 1;
363            }
364
365            // 更新严重级别统计
366            let severity = event.severity_level();
367            *stats.errors_by_severity.entry(severity).or_insert(0) += 1;
368
369            // 更新可重试统计
370            if event.is_retryable {
371                stats.retryable_errors += 1;
372            }
373
374            // 更新时间范围
375            if stats.first_error_time.is_none() {
376                stats.first_error_time = Some(event.timestamp);
377            }
378            stats.last_error_time = Some(event.timestamp);
379        }
380
381        // 添加到事件历史
382        if let Ok(mut events) = self.events.lock() {
383            events.push(event);
384
385            // 自动清理旧事件
386            if self.config.auto_cleanup && events.len() > self.config.max_events {
387                let len = events.len();
388                let max_events = self.config.max_events;
389                events.drain(0..(len - max_events));
390            }
391        }
392
393        // 检查告警条件
394        self.check_alerts();
395    }
396
397    /// 获取统计数据
398    pub fn get_statistics(&self) -> ErrorStatistics {
399        self.statistics.lock().unwrap().clone()
400    }
401
402    /// 获取最近的错误事件
403    pub fn get_recent_events(&self, limit: usize) -> Vec<ErrorEvent> {
404        if let Ok(events) = self.events.lock() {
405            events.iter().rev().take(limit).cloned().collect()
406        } else {
407            Vec::new()
408        }
409    }
410
411    /// 清理旧事件
412    pub fn cleanup_old_events(&self) {
413        if let Ok(mut events) = self.events.lock() {
414            let cutoff_time = SystemTime::now() - self.config.time_window;
415            events.retain(|event| event.timestamp >= cutoff_time);
416        }
417    }
418
419    /// 重置统计数据
420    pub fn reset_statistics(&self) {
421        if let Ok(mut stats) = self.statistics.lock() {
422            *stats = ErrorStatistics::default();
423        }
424        if let Ok(mut events) = self.events.lock() {
425            events.clear();
426        }
427    }
428
429    /// 检查告警条件
430    fn check_alerts(&self) {
431        let stats = self.get_statistics();
432
433        // 检查错误率
434        if stats.error_rate_per_minute() > self.config.alert_thresholds.error_rate_per_minute {
435            self.trigger_alert(
436                AlertType::HighErrorRate,
437                format!("错误率过高: {:.2} 错误/分钟", stats.error_rate_per_minute()),
438            );
439        }
440
441        // 检查严重错误
442        if let Some(critical_count) = stats.errors_by_severity.get(&ErrorSeverity::Critical) {
443            if *critical_count >= self.config.alert_thresholds.critical_errors_count {
444                self.trigger_alert(
445                    AlertType::CriticalErrors,
446                    format!("严重错误过多: {critical_count} 个"),
447                );
448            }
449        }
450    }
451
452    /// 触发告警
453    fn trigger_alert(&self, alert_type: AlertType, message: String) {
454        println!("🚨 告警 [{alert_type:?}]: {message}");
455        // 这里可以集成外部告警系统
456    }
457
458    /// 生成错误报告
459    pub fn generate_report(&self) -> ErrorReport {
460        let stats = self.get_statistics();
461        let recent_events = self.get_recent_events(10);
462
463        ErrorReport {
464            statistics: stats,
465            recent_events,
466            generated_at: SystemTime::now(),
467            time_window: self.config.time_window,
468        }
469    }
470}
471
472/// 告警类型
473#[derive(Debug)]
474enum AlertType {
475    HighErrorRate,
476    CriticalErrors,
477    #[allow(dead_code)]
478    ConsecutiveFailures,
479}
480
481/// 错误报告
482#[derive(Debug)]
483pub struct ErrorReport {
484    /// 统计数据
485    pub statistics: ErrorStatistics,
486    /// 最近事件
487    pub recent_events: Vec<ErrorEvent>,
488    /// 报告生成时间
489    pub generated_at: SystemTime,
490    /// 统计时间窗口
491    pub time_window: Duration,
492}
493
494impl ErrorReport {
495    /// 打印报告
496    pub fn print(&self) {
497        println!("📋 错误监控报告");
498        println!("生成时间: {:?}", self.generated_at);
499        println!("统计窗口: {:?}", self.time_window);
500        println!("{}", "=".repeat(50));
501
502        self.statistics.print_detailed();
503
504        println!("\n🕒 最近错误事件:");
505        for (i, event) in self.recent_events.iter().enumerate() {
506            println!(
507                "   {}. [{:?}] {} {:?}",
508                i + 1,
509                event.timestamp,
510                event.severity_level().symbol(),
511                event.category
512            );
513        }
514    }
515
516    /// 保存到文件
517    pub fn save_to_file(&self, path: &str) -> Result<(), std::io::Error> {
518        use std::{fs::File, io::Write};
519
520        let mut file = File::create(path)?;
521
522        writeln!(file, "错误监控报告")?;
523        writeln!(file, "生成时间: {:?}", self.generated_at)?;
524        writeln!(file, "统计窗口: {:?}", self.time_window)?;
525        writeln!(file, "{}", "=".repeat(50))?;
526
527        writeln!(file, "\n统计摘要:")?;
528        writeln!(file, "总错误数: {}", self.statistics.total_errors)?;
529        writeln!(
530            file,
531            "错误率: {:.2} 错误/分钟",
532            self.statistics.error_rate_per_minute()
533        )?;
534        writeln!(
535            file,
536            "可重试错误: {:.1}%",
537            self.statistics.retryable_percentage()
538        )?;
539
540        Ok(())
541    }
542}
543
544#[cfg(test)]
545mod tests {
546    use super::*;
547    use rstest::rstest;
548    use std::thread;
549
550    #[test]
551    fn test_error_event_creation() {
552        let error = LarkAPIError::api_error(403, "Forbidden", None);
553        let event = ErrorEvent::from_error(error);
554
555        assert_eq!(event.category, ErrorHandlingCategory::Permission);
556        assert_eq!(event.error_code, Some(LarkErrorCode::Forbidden));
557        assert!(!event.is_retryable);
558    }
559
560    #[test]
561    fn test_error_statistics() {
562        let stats = ErrorStatistics {
563            total_errors: 100,
564            retryable_errors: 60,
565            ..Default::default()
566        };
567
568        assert_eq!(stats.retryable_percentage(), 60.0);
569    }
570
571    #[test]
572    fn test_error_monitor() {
573        let monitor = ErrorMonitor::default();
574
575        // 记录一些错误
576        monitor.record_error(LarkAPIError::api_error(403, "Forbidden", None));
577        monitor.record_error(LarkAPIError::api_error(500, "Server Error", None));
578
579        let stats = monitor.get_statistics();
580        assert_eq!(stats.total_errors, 2);
581        assert_eq!(stats.errors_by_category.len(), 2);
582    }
583
584    #[test]
585    fn test_error_severity() {
586        assert_eq!(ErrorSeverity::Critical.weight(), 4);
587        assert_eq!(ErrorSeverity::Warning.weight(), 2);
588        assert_eq!(ErrorSeverity::Critical.symbol(), "🚨");
589    }
590
591    // New comprehensive tests
592
593    #[rstest]
594    #[case(
595        LarkAPIError::api_error(401, "Unauthorized", None),
596        ErrorHandlingCategory::Authentication
597    )]
598    #[case(
599        LarkAPIError::api_error(403, "Forbidden", None),
600        ErrorHandlingCategory::Permission
601    )]
602    #[case(
603        LarkAPIError::api_error(400, "Bad Request", None),
604        ErrorHandlingCategory::ClientError
605    )]
606    #[case(
607        LarkAPIError::api_error(500, "Internal Server Error", None),
608        ErrorHandlingCategory::ServerError
609    )]
610    #[case(
611        LarkAPIError::api_error(429, "Too Many Requests", None),
612        ErrorHandlingCategory::RateLimit
613    )]
614    #[case(LarkAPIError::RequestError("Network timeout".to_string()), ErrorHandlingCategory::NetworkError)]
615    #[case(
616        LarkAPIError::MissingAccessToken,
617        ErrorHandlingCategory::Authentication
618    )]
619    #[case(LarkAPIError::IllegalParamError("invalid param".to_string()), ErrorHandlingCategory::ClientError)]
620    fn test_error_event_category_mapping(
621        #[case] error: LarkAPIError,
622        #[case] expected_category: ErrorHandlingCategory,
623    ) {
624        let event = ErrorEvent::from_error(error);
625        assert_eq!(event.category, expected_category);
626    }
627
628    #[test]
629    fn test_error_event_with_context() {
630        let error = LarkAPIError::api_error(400, "Bad Request", None);
631        let event = ErrorEvent::from_error(error)
632            .with_context("endpoint", "/api/test")
633            .with_context("user_id", "123");
634
635        assert_eq!(event.context.len(), 2);
636        assert_eq!(
637            event.context.get("endpoint"),
638            Some(&"/api/test".to_string())
639        );
640        assert_eq!(event.context.get("user_id"), Some(&"123".to_string()));
641    }
642
643    #[test]
644    fn test_error_event_with_processing_time() {
645        let error = LarkAPIError::api_error(500, "Server Error", None);
646        let processing_time = Duration::from_millis(150);
647        let event = ErrorEvent::from_error(error).with_processing_time(processing_time);
648
649        assert_eq!(event.processing_time, Some(processing_time));
650    }
651
652    #[rstest]
653    #[case(ErrorHandlingCategory::Authentication, ErrorSeverity::Warning)]
654    #[case(ErrorHandlingCategory::Permission, ErrorSeverity::Error)]
655    #[case(ErrorHandlingCategory::ClientError, ErrorSeverity::Warning)]
656    #[case(ErrorHandlingCategory::ServerError, ErrorSeverity::Critical)]
657    #[case(ErrorHandlingCategory::NetworkError, ErrorSeverity::Warning)]
658    #[case(ErrorHandlingCategory::RateLimit, ErrorSeverity::Warning)]
659    #[case(ErrorHandlingCategory::SystemError, ErrorSeverity::Critical)]
660    #[case(ErrorHandlingCategory::Unknown, ErrorSeverity::Error)]
661    fn test_error_event_severity_level(
662        #[case] category: ErrorHandlingCategory,
663        #[case] expected_severity: ErrorSeverity,
664    ) {
665        let error = LarkAPIError::api_error(400, "Test", None);
666        let mut event = ErrorEvent::from_error(error);
667        event.category = category;
668
669        assert_eq!(event.severity_level(), expected_severity);
670    }
671
672    #[test]
673    fn test_error_severity_weights() {
674        assert_eq!(ErrorSeverity::Info.weight(), 1);
675        assert_eq!(ErrorSeverity::Warning.weight(), 2);
676        assert_eq!(ErrorSeverity::Error.weight(), 3);
677        assert_eq!(ErrorSeverity::Critical.weight(), 4);
678
679        // Test ordering
680        assert!(ErrorSeverity::Critical.weight() > ErrorSeverity::Error.weight());
681        assert!(ErrorSeverity::Error.weight() > ErrorSeverity::Warning.weight());
682    }
683
684    #[test]
685    fn test_error_severity_symbols() {
686        assert_eq!(ErrorSeverity::Info.symbol(), "ℹ️");
687        assert_eq!(ErrorSeverity::Warning.symbol(), "⚠️");
688        assert_eq!(ErrorSeverity::Error.symbol(), "❌");
689        assert_eq!(ErrorSeverity::Critical.symbol(), "🚨");
690    }
691
692    #[test]
693    fn test_error_statistics_default() {
694        let stats = ErrorStatistics::default();
695
696        assert_eq!(stats.total_errors, 0);
697        assert!(stats.errors_by_category.is_empty());
698        assert!(stats.errors_by_code.is_empty());
699        assert!(stats.errors_by_severity.is_empty());
700        assert_eq!(stats.retryable_errors, 0);
701        assert!(stats.average_processing_time.is_none());
702        assert!(stats.first_error_time.is_none());
703        assert!(stats.last_error_time.is_none());
704    }
705
706    #[test]
707    fn test_error_statistics_error_rate_calculation() {
708        let now = SystemTime::now();
709        let one_minute_ago = now - Duration::from_secs(60);
710
711        let stats = ErrorStatistics {
712            total_errors: 10,
713            first_error_time: Some(one_minute_ago),
714            last_error_time: Some(now),
715            ..Default::default()
716        };
717
718        let rate = stats.error_rate_per_minute();
719        assert!(rate > 9.0 && rate <= 10.0); // Should be around 10 errors per minute
720    }
721
722    #[test]
723    fn test_error_statistics_error_rate_no_time_range() {
724        let stats = ErrorStatistics {
725            total_errors: 10,
726            first_error_time: None,
727            last_error_time: None,
728            ..Default::default()
729        };
730
731        assert_eq!(stats.error_rate_per_minute(), 0.0);
732    }
733
734    #[test]
735    fn test_error_statistics_most_common_category() {
736        let mut stats = ErrorStatistics::default();
737        stats
738            .errors_by_category
739            .insert(ErrorHandlingCategory::Authentication, 5);
740        stats
741            .errors_by_category
742            .insert(ErrorHandlingCategory::Permission, 10);
743        stats
744            .errors_by_category
745            .insert(ErrorHandlingCategory::ClientError, 3);
746
747        assert_eq!(
748            stats.most_common_category(),
749            Some(ErrorHandlingCategory::Permission)
750        );
751    }
752
753    #[test]
754    fn test_error_statistics_highest_severity() {
755        let mut stats = ErrorStatistics::default();
756        stats.errors_by_severity.insert(ErrorSeverity::Warning, 5);
757        stats.errors_by_severity.insert(ErrorSeverity::Error, 3);
758        stats.errors_by_severity.insert(ErrorSeverity::Critical, 1);
759
760        assert_eq!(stats.highest_severity(), Some(ErrorSeverity::Critical));
761    }
762
763    #[test]
764    fn test_error_statistics_retryable_percentage() {
765        let stats = ErrorStatistics {
766            total_errors: 50,
767            retryable_errors: 20,
768            ..Default::default()
769        };
770
771        assert_eq!(stats.retryable_percentage(), 40.0);
772
773        // Test with zero total errors
774        let empty_stats = ErrorStatistics::default();
775        assert_eq!(empty_stats.retryable_percentage(), 0.0);
776    }
777
778    #[test]
779    fn test_error_statistics_print_methods() {
780        let mut stats = ErrorStatistics {
781            total_errors: 100,
782            retryable_errors: 30,
783            ..Default::default()
784        };
785        stats
786            .errors_by_category
787            .insert(ErrorHandlingCategory::ServerError, 50);
788        stats.errors_by_severity.insert(ErrorSeverity::Critical, 10);
789
790        // These methods should not panic
791        stats.print_summary();
792        stats.print_detailed();
793    }
794
795    #[test]
796    fn test_monitor_config_default() {
797        let config = MonitorConfig::default();
798
799        assert_eq!(config.max_events, 1000);
800        assert_eq!(config.time_window, Duration::from_secs(24 * 60 * 60));
801        assert!(config.auto_cleanup);
802    }
803
804    #[test]
805    fn test_alert_thresholds_default() {
806        let thresholds = AlertThresholds::default();
807
808        assert_eq!(thresholds.error_rate_per_minute, 10.0);
809        assert_eq!(thresholds.critical_errors_count, 5);
810        assert_eq!(thresholds.consecutive_failures, 3);
811    }
812
813    #[test]
814    fn test_error_monitor_new() {
815        let config = MonitorConfig {
816            max_events: 500,
817            time_window: Duration::from_secs(3600),
818            auto_cleanup: false,
819            alert_thresholds: AlertThresholds::default(),
820        };
821        let monitor = ErrorMonitor::new(config.clone());
822
823        assert_eq!(monitor.config.max_events, 500);
824        assert_eq!(monitor.config.time_window, Duration::from_secs(3600));
825        assert!(!monitor.config.auto_cleanup);
826    }
827
828    #[test]
829    fn test_error_monitor_default() {
830        let monitor = ErrorMonitor::default();
831        assert_eq!(monitor.config.max_events, 1000);
832    }
833
834    #[test]
835    fn test_error_monitor_record_error() {
836        let monitor = ErrorMonitor::default();
837
838        monitor.record_error(LarkAPIError::api_error(403, "Forbidden", None));
839        monitor.record_error(LarkAPIError::api_error(500, "Server Error", None));
840        monitor.record_error(LarkAPIError::MissingAccessToken);
841
842        let stats = monitor.get_statistics();
843        assert_eq!(stats.total_errors, 3);
844        assert_eq!(stats.errors_by_category.len(), 3);
845        assert!(stats
846            .errors_by_category
847            .contains_key(&ErrorHandlingCategory::Permission));
848        assert!(stats
849            .errors_by_category
850            .contains_key(&ErrorHandlingCategory::ServerError));
851        assert!(stats
852            .errors_by_category
853            .contains_key(&ErrorHandlingCategory::Authentication));
854    }
855
856    #[test]
857    fn test_error_monitor_record_error_with_context() {
858        let monitor = ErrorMonitor::default();
859        let mut context = HashMap::new();
860        context.insert("user_id".to_string(), "123".to_string());
861        context.insert("endpoint".to_string(), "/api/test".to_string());
862
863        monitor
864            .record_error_with_context(LarkAPIError::api_error(400, "Bad Request", None), context);
865
866        let events = monitor.get_recent_events(1);
867        assert_eq!(events.len(), 1);
868        assert_eq!(events[0].context.len(), 2);
869    }
870
871    #[test]
872    fn test_error_monitor_get_recent_events() {
873        let monitor = ErrorMonitor::default();
874
875        // Record 5 errors
876        for i in 0..5 {
877            monitor.record_error(LarkAPIError::api_error(400 + i, "Test Error", None));
878        }
879
880        // Get last 3 events
881        let recent = monitor.get_recent_events(3);
882        assert_eq!(recent.len(), 3);
883
884        // Should be in reverse order (most recent first)
885        // The last recorded error should be first in the result
886    }
887
888    #[test]
889    fn test_error_monitor_auto_cleanup() {
890        let config = MonitorConfig {
891            max_events: 3,
892            auto_cleanup: true,
893            ..MonitorConfig::default()
894        };
895        let monitor = ErrorMonitor::new(config);
896
897        // Record 5 errors (more than max_events)
898        for i in 0..5 {
899            monitor.record_error(LarkAPIError::api_error(400 + i, "Test Error", None));
900        }
901
902        let recent = monitor.get_recent_events(10);
903        assert_eq!(recent.len(), 3); // Should be limited to max_events
904    }
905
906    #[test]
907    fn test_error_monitor_cleanup_old_events() {
908        let config = MonitorConfig {
909            time_window: Duration::from_millis(100),
910            ..MonitorConfig::default()
911        };
912        let monitor = ErrorMonitor::new(config);
913
914        monitor.record_error(LarkAPIError::api_error(400, "Old Error", None));
915
916        // Wait for the time window to pass
917        thread::sleep(Duration::from_millis(150));
918
919        monitor.cleanup_old_events();
920
921        let recent = monitor.get_recent_events(10);
922        assert_eq!(recent.len(), 0); // Should be empty after cleanup
923    }
924
925    #[test]
926    fn test_error_monitor_reset_statistics() {
927        let monitor = ErrorMonitor::default();
928
929        monitor.record_error(LarkAPIError::api_error(403, "Forbidden", None));
930        monitor.record_error(LarkAPIError::api_error(500, "Server Error", None));
931
932        let stats_before = monitor.get_statistics();
933        assert_eq!(stats_before.total_errors, 2);
934
935        monitor.reset_statistics();
936
937        let stats_after = monitor.get_statistics();
938        assert_eq!(stats_after.total_errors, 0);
939        assert!(stats_after.errors_by_category.is_empty());
940
941        let events = monitor.get_recent_events(10);
942        assert_eq!(events.len(), 0);
943    }
944
945    #[test]
946    fn test_error_monitor_statistics_updates() {
947        let monitor = ErrorMonitor::default();
948
949        // Record retryable error
950        monitor.record_error(LarkAPIError::api_error(429, "Too Many Requests", None));
951        // Record non-retryable error
952        monitor.record_error(LarkAPIError::IllegalParamError("invalid".to_string()));
953
954        let stats = monitor.get_statistics();
955        assert_eq!(stats.total_errors, 2);
956        assert_eq!(stats.retryable_errors, 1);
957        assert!(stats.first_error_time.is_some());
958        assert!(stats.last_error_time.is_some());
959    }
960
961    #[test]
962    fn test_error_monitor_error_code_tracking() {
963        let monitor = ErrorMonitor::default();
964
965        monitor.record_error(LarkAPIError::api_error(403, "Forbidden", None));
966        monitor.record_error(LarkAPIError::api_error(403, "Forbidden", None));
967        monitor.record_error(LarkAPIError::api_error(500, "Server Error", None));
968
969        let stats = monitor.get_statistics();
970        assert_eq!(
971            stats.errors_by_code.get(&LarkErrorCode::Forbidden),
972            Some(&2)
973        );
974        assert_eq!(
975            stats
976                .errors_by_code
977                .get(&LarkErrorCode::InternalServerError),
978            Some(&1)
979        );
980    }
981
982    #[test]
983    fn test_error_monitor_generate_report() {
984        let monitor = ErrorMonitor::default();
985
986        monitor.record_error(LarkAPIError::api_error(403, "Forbidden", None));
987        monitor.record_error(LarkAPIError::api_error(500, "Server Error", None));
988
989        let report = monitor.generate_report();
990        assert_eq!(report.statistics.total_errors, 2);
991        assert!(report.recent_events.len() <= 10);
992        assert!(report.generated_at <= SystemTime::now());
993        assert_eq!(report.time_window, monitor.config.time_window);
994    }
995
996    #[test]
997    fn test_error_report_methods() {
998        let monitor = ErrorMonitor::default();
999        monitor.record_error(LarkAPIError::api_error(403, "Forbidden", None));
1000
1001        let report = monitor.generate_report();
1002
1003        // These methods should not panic
1004        report.print();
1005
1006        // Test saving to file (using a temp path)
1007        let temp_path = "/tmp/test_error_report.txt";
1008        let result = report.save_to_file(temp_path);
1009        assert!(result.is_ok());
1010
1011        // Clean up
1012        let _ = std::fs::remove_file(temp_path);
1013    }
1014
1015    #[test]
1016    fn test_error_monitor_concurrent_access() {
1017        use std::sync::Arc;
1018        use std::thread;
1019
1020        let monitor = Arc::new(ErrorMonitor::default());
1021        let mut handles = vec![];
1022
1023        // Spawn multiple threads recording errors
1024        for i in 0..10 {
1025            let monitor_clone = Arc::clone(&monitor);
1026            let handle = thread::spawn(move || {
1027                monitor_clone.record_error(LarkAPIError::api_error(
1028                    400 + i,
1029                    "Concurrent Error",
1030                    None,
1031                ));
1032            });
1033            handles.push(handle);
1034        }
1035
1036        // Wait for all threads to complete
1037        for handle in handles {
1038            handle.join().unwrap();
1039        }
1040
1041        let stats = monitor.get_statistics();
1042        assert_eq!(stats.total_errors, 10);
1043    }
1044
1045    #[test]
1046    fn test_error_monitor_alert_triggering() {
1047        let config = MonitorConfig {
1048            alert_thresholds: AlertThresholds {
1049                critical_errors_count: 2,
1050                ..AlertThresholds::default()
1051            },
1052            ..MonitorConfig::default()
1053        };
1054        let monitor = ErrorMonitor::new(config);
1055
1056        // Record critical errors to trigger alert
1057        monitor.record_error(LarkAPIError::api_error(500, "Server Error 1", None));
1058        monitor.record_error(LarkAPIError::api_error(500, "Server Error 2", None));
1059
1060        // The check_alerts method is called internally when recording errors
1061        // We can verify the alert was processed by checking the statistics
1062        let stats = monitor.get_statistics();
1063        assert!(
1064            stats
1065                .errors_by_severity
1066                .get(&ErrorSeverity::Critical)
1067                .unwrap()
1068                >= &2
1069        );
1070    }
1071
1072    #[test]
1073    fn test_error_event_timestamp() {
1074        let error = LarkAPIError::api_error(400, "Test", None);
1075        let event = ErrorEvent::from_error(error);
1076        let now = SystemTime::now();
1077
1078        // Timestamp should be recent (within 1 second)
1079        let diff = now.duration_since(event.timestamp).unwrap_or_default();
1080        assert!(diff.as_secs() < 1);
1081    }
1082}