1use super::analytics::Anomaly;
7use super::config::{
8 AlertConfig, AlertSeverity, AlertThreshold, ChannelType, EscalationPolicy, NotificationChannel,
9 SuppressionRule, ThresholdType,
10};
11use crate::DeviceResult;
12use serde::{Deserialize, Serialize};
13use std::collections::{HashMap, VecDeque};
14use std::time::{Duration, SystemTime};
15use tokio::sync::mpsc;
16
17pub struct AlertManager {
19 config: AlertConfig,
20 active_alerts: HashMap<String, ActiveAlert>,
21 alert_history: VecDeque<ResolvedAlert>,
22 notification_dispatcher: NotificationDispatcher,
23 suppression_engine: SuppressionEngine,
24 escalation_engine: EscalationEngine,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct ActiveAlert {
30 pub alert_id: String,
31 pub timestamp: SystemTime,
32 pub metric_name: String,
33 pub threshold: AlertThreshold,
34 pub current_value: f64,
35 pub severity: AlertSeverity,
36 pub status: AlertStatus,
37 pub acknowledgement: Option<AlertAcknowledgement>,
38 pub escalation_level: usize,
39 pub notification_count: usize,
40 pub tags: HashMap<String, String>,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
45pub enum AlertStatus {
46 Triggered,
47 Acknowledged,
48 Escalated,
49 Resolved,
50 Suppressed,
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct AlertAcknowledgement {
56 pub acknowledged_by: String,
57 pub acknowledgement_time: SystemTime,
58 pub acknowledgement_note: Option<String>,
59 pub estimated_resolution_time: Option<SystemTime>,
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct ResolvedAlert {
65 pub alert: ActiveAlert,
66 pub resolution_timestamp: SystemTime,
67 pub resolution_method: ResolutionMethod,
68 pub duration: Duration,
69 pub resolution_note: Option<String>,
70 pub resolution_effectiveness: Option<f64>,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
75pub enum ResolutionMethod {
76 Automatic,
77 Manual,
78 SelfHealing,
79 UserIntervention,
80 SystemRestart,
81 ConfigurationChange,
82 Timeout,
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct AlertStatistics {
88 pub total_alerts: usize,
89 pub alerts_by_severity: HashMap<AlertSeverity, usize>,
90 pub alerts_by_metric: HashMap<String, usize>,
91 pub average_resolution_time: Duration,
92 pub false_positive_rate: f64,
93 pub escalation_rate: f64,
94 pub acknowledgement_rate: f64,
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct AlertTrends {
100 pub alert_frequency_trend: TrendDirection,
101 pub severity_trends: HashMap<AlertSeverity, TrendDirection>,
102 pub resolution_time_trend: TrendDirection,
103 pub false_positive_trend: TrendDirection,
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
108pub enum TrendDirection {
109 Increasing,
110 Decreasing,
111 Stable,
112 Volatile,
113}
114
115#[derive(Debug)]
117pub struct NotificationDispatcher {
118 channels: Vec<NotificationChannel>,
119 notification_queue: VecDeque<NotificationTask>,
120 delivery_history: VecDeque<DeliveryRecord>,
121 rate_limiter: RateLimiter,
122}
123
124#[derive(Debug, Clone)]
126pub struct NotificationTask {
127 pub task_id: String,
128 pub alert_id: String,
129 pub channel_type: ChannelType,
130 pub message: NotificationMessage,
131 pub priority: NotificationPriority,
132 pub retry_count: usize,
133 pub max_retries: usize,
134 pub created_at: SystemTime,
135}
136
137#[derive(Debug, Clone)]
139pub struct NotificationMessage {
140 pub subject: String,
141 pub body: String,
142 pub format: MessageFormat,
143 pub attachments: Vec<NotificationAttachment>,
144 pub metadata: HashMap<String, String>,
145}
146
147#[derive(Debug, Clone, PartialEq)]
149pub enum MessageFormat {
150 PlainText,
151 HTML,
152 Markdown,
153 JSON,
154 Custom(String),
155}
156
157#[derive(Debug, Clone)]
159pub struct NotificationAttachment {
160 pub name: String,
161 pub content_type: String,
162 pub data: Vec<u8>,
163}
164
165#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
167pub enum NotificationPriority {
168 Low,
169 Normal,
170 High,
171 Critical,
172 Emergency,
173}
174
175#[derive(Debug, Clone)]
177pub struct DeliveryRecord {
178 pub task_id: String,
179 pub channel_type: ChannelType,
180 pub delivery_time: SystemTime,
181 pub delivery_status: DeliveryStatus,
182 pub response_time: Duration,
183 pub error_message: Option<String>,
184}
185
186#[derive(Debug, Clone, PartialEq)]
188pub enum DeliveryStatus {
189 Sent,
190 Delivered,
191 Failed,
192 Retry,
193 Suppressed,
194}
195
196#[derive(Debug)]
198pub struct RateLimiter {
199 limits: HashMap<ChannelType, RateLimit>,
200 usage_tracking: HashMap<ChannelType, VecDeque<SystemTime>>,
201}
202
203#[derive(Debug, Clone)]
205pub struct RateLimit {
206 pub max_notifications: usize,
207 pub time_window: Duration,
208 pub burst_limit: Option<usize>,
209}
210
211pub struct SuppressionEngine {
213 rules: Vec<SuppressionRule>,
214 suppressed_alerts: HashMap<String, SuppressionRecord>,
215 suppression_history: VecDeque<SuppressionEvent>,
216}
217
218#[derive(Debug, Clone)]
220pub struct SuppressionRecord {
221 pub alert_id: String,
222 pub rule_id: String,
223 pub suppression_start: SystemTime,
224 pub suppression_end: SystemTime,
225 pub suppression_count: usize,
226}
227
228#[derive(Debug, Clone)]
230pub struct SuppressionEvent {
231 pub timestamp: SystemTime,
232 pub event_type: SuppressionEventType,
233 pub alert_id: String,
234 pub rule_id: String,
235 pub details: HashMap<String, String>,
236}
237
238#[derive(Debug, Clone, PartialEq)]
240pub enum SuppressionEventType {
241 AlertSuppressed,
242 AlertUnsuppressed,
243 RuleActivated,
244 RuleDeactivated,
245 SuppressionExpired,
246}
247
248pub struct EscalationEngine {
250 policies: Vec<EscalationPolicy>,
251 active_escalations: HashMap<String, EscalationState>,
252 escalation_history: VecDeque<EscalationEvent>,
253}
254
255#[derive(Debug, Clone)]
257pub struct EscalationState {
258 pub alert_id: String,
259 pub policy_id: String,
260 pub current_step: usize,
261 pub escalation_start: SystemTime,
262 pub next_escalation: Option<SystemTime>,
263 pub escalation_attempts: usize,
264}
265
266#[derive(Debug, Clone)]
268pub struct EscalationEvent {
269 pub timestamp: SystemTime,
270 pub alert_id: String,
271 pub policy_id: String,
272 pub step_number: usize,
273 pub escalation_type: EscalationType,
274 pub success: bool,
275 pub details: HashMap<String, String>,
276}
277
278#[derive(Debug, Clone, PartialEq)]
280pub enum EscalationType {
281 Notification,
282 AutoRemediation,
283 TicketCreation,
284 OnCallEscalation,
285 Custom(String),
286}
287
288#[derive(Debug, Clone)]
290pub struct NotificationFilter {
291 pub filter_type: String,
292 pub condition: String,
293 pub value: String,
294}
295
296impl AlertManager {
297 pub fn new(config: AlertConfig) -> Self {
298 Self {
299 config: config.clone(),
300 active_alerts: HashMap::new(),
301 alert_history: VecDeque::new(),
302 notification_dispatcher: NotificationDispatcher::new(
303 config.notification_channels.clone(),
304 ),
305 suppression_engine: SuppressionEngine::new(config.suppression_rules.clone()),
306 escalation_engine: EscalationEngine::new(config.escalation_policies.clone()),
307 }
308 }
309
310 pub async fn start_monitoring(&mut self) -> DeviceResult<()> {
311 self.notification_dispatcher.start().await?;
313 self.suppression_engine.start().await?;
314 self.escalation_engine.start().await?;
315
316 Ok(())
317 }
318
319 pub async fn stop_monitoring(&mut self) -> DeviceResult<()> {
320 self.notification_dispatcher.stop().await?;
322 self.suppression_engine.stop().await?;
323 self.escalation_engine.stop().await?;
324
325 Ok(())
326 }
327
328 pub async fn process_metric_value(
329 &mut self,
330 metric_name: &str,
331 value: f64,
332 ) -> DeviceResult<()> {
333 let threshold = self.config.alert_thresholds.get(metric_name).cloned();
334 if let Some(threshold) = threshold {
335 if self.should_trigger_alert(&threshold, value) {
336 self.trigger_alert(metric_name, &threshold, value).await?;
337 } else {
338 let alert_id = self
339 .active_alerts
340 .get(metric_name)
341 .map(|a| a.alert_id.clone());
342 if let Some(alert_id) = alert_id {
343 if self.should_resolve_alert(&threshold, value) {
344 self.resolve_alert(&alert_id, ResolutionMethod::Automatic)
345 .await?;
346 }
347 }
348 }
349 }
350
351 Ok(())
352 }
353
354 pub async fn process_anomaly(&mut self, anomaly: &Anomaly) -> DeviceResult<()> {
355 let alert_threshold = AlertThreshold {
357 metric_name: anomaly.metric_name.clone(),
358 threshold_type: ThresholdType::StandardDeviation,
359 value: anomaly.expected_value,
360 severity: self.map_anomaly_severity(&anomaly.severity),
361 duration: Duration::from_secs(60),
362 enabled: true,
363 };
364
365 self.trigger_alert(
366 &anomaly.metric_name,
367 &alert_threshold,
368 anomaly.current_value,
369 )
370 .await?;
371
372 Ok(())
373 }
374
375 pub async fn acknowledge_alert(
376 &mut self,
377 alert_id: &str,
378 user_id: &str,
379 note: Option<String>,
380 ) -> DeviceResult<()> {
381 if let Some(alert) = self.active_alerts.get_mut(alert_id) {
382 alert.acknowledgement = Some(AlertAcknowledgement {
383 acknowledged_by: user_id.to_string(),
384 acknowledgement_time: SystemTime::now(),
385 acknowledgement_note: note,
386 estimated_resolution_time: None,
387 });
388 alert.status = AlertStatus::Acknowledged;
389
390 self.escalation_engine.stop_escalation(alert_id).await?;
392 }
393
394 Ok(())
395 }
396
397 pub async fn resolve_alert(
398 &mut self,
399 alert_id: &str,
400 resolution_method: ResolutionMethod,
401 ) -> DeviceResult<()> {
402 if let Some(alert) = self.active_alerts.remove(alert_id) {
403 let duration = SystemTime::now()
404 .duration_since(alert.timestamp)
405 .unwrap_or(Duration::from_secs(0));
406
407 let resolved_alert = ResolvedAlert {
408 alert: alert.clone(),
409 resolution_timestamp: SystemTime::now(),
410 resolution_method,
411 duration,
412 resolution_note: None,
413 resolution_effectiveness: None,
414 };
415
416 self.alert_history.push_back(resolved_alert);
417
418 if self.alert_history.len() > 10000 {
420 self.alert_history.pop_front();
421 }
422
423 self.escalation_engine.stop_escalation(alert_id).await?;
425 }
426
427 Ok(())
428 }
429
430 pub fn get_alert_statistics(&self) -> AlertStatistics {
431 let mut stats = AlertStatistics {
432 total_alerts: self.active_alerts.len() + self.alert_history.len(),
433 alerts_by_severity: HashMap::new(),
434 alerts_by_metric: HashMap::new(),
435 average_resolution_time: Duration::from_secs(0),
436 false_positive_rate: 0.0,
437 escalation_rate: 0.0,
438 acknowledgement_rate: 0.0,
439 };
440
441 for alert in self.active_alerts.values() {
443 *stats
444 .alerts_by_severity
445 .entry(alert.severity.clone())
446 .or_insert(0) += 1;
447 *stats
448 .alerts_by_metric
449 .entry(alert.metric_name.clone())
450 .or_insert(0) += 1;
451 }
452
453 for resolved in &self.alert_history {
454 *stats
455 .alerts_by_severity
456 .entry(resolved.alert.severity.clone())
457 .or_insert(0) += 1;
458 *stats
459 .alerts_by_metric
460 .entry(resolved.alert.metric_name.clone())
461 .or_insert(0) += 1;
462 }
463
464 if !self.alert_history.is_empty() {
466 let total_duration: Duration = self.alert_history.iter().map(|r| r.duration).sum();
467 stats.average_resolution_time = total_duration / self.alert_history.len() as u32;
468 }
469
470 stats
471 }
472
473 async fn trigger_alert(
474 &mut self,
475 metric_name: &str,
476 threshold: &AlertThreshold,
477 value: f64,
478 ) -> DeviceResult<()> {
479 let alert_id = format!(
480 "{}-{}",
481 metric_name,
482 SystemTime::now()
483 .duration_since(std::time::UNIX_EPOCH)
484 .unwrap()
485 .as_secs()
486 );
487
488 let alert = ActiveAlert {
489 alert_id: alert_id.clone(),
490 timestamp: SystemTime::now(),
491 metric_name: metric_name.to_string(),
492 threshold: threshold.clone(),
493 current_value: value,
494 severity: threshold.severity.clone(),
495 status: AlertStatus::Triggered,
496 acknowledgement: None,
497 escalation_level: 0,
498 notification_count: 0,
499 tags: HashMap::new(),
500 };
501
502 if !self.suppression_engine.should_suppress(&alert).await? {
504 self.notification_dispatcher
506 .send_alert_notification(&alert)
507 .await?;
508
509 self.escalation_engine.start_escalation(&alert).await?;
511
512 self.active_alerts.insert(alert_id, alert);
513 }
514
515 Ok(())
516 }
517
518 fn should_trigger_alert(&self, threshold: &AlertThreshold, value: f64) -> bool {
519 if !threshold.enabled {
520 return false;
521 }
522
523 match threshold.threshold_type {
524 ThresholdType::GreaterThan => value > threshold.value,
525 ThresholdType::LessThan => value < threshold.value,
526 ThresholdType::Equal => (value - threshold.value).abs() < f64::EPSILON,
527 ThresholdType::NotEqual => (value - threshold.value).abs() > f64::EPSILON,
528 ThresholdType::PercentageChange => {
529 false
531 }
532 ThresholdType::StandardDeviation => {
533 false
535 }
536 ThresholdType::Custom(_) => {
537 false
539 }
540 }
541 }
542
543 fn should_resolve_alert(&self, threshold: &AlertThreshold, value: f64) -> bool {
544 !self.should_trigger_alert(threshold, value)
546 }
547
548 fn map_anomaly_severity(
549 &self,
550 anomaly_severity: &super::analytics::AnomalySeverity,
551 ) -> AlertSeverity {
552 match anomaly_severity {
553 super::analytics::AnomalySeverity::Low => AlertSeverity::Info,
554 super::analytics::AnomalySeverity::Medium => AlertSeverity::Warning,
555 super::analytics::AnomalySeverity::High => AlertSeverity::Error,
556 super::analytics::AnomalySeverity::Critical => AlertSeverity::Critical,
557 }
558 }
559}
560
561impl NotificationDispatcher {
562 pub fn new(channels: Vec<NotificationChannel>) -> Self {
563 Self {
564 channels,
565 notification_queue: VecDeque::new(),
566 delivery_history: VecDeque::new(),
567 rate_limiter: RateLimiter::new(),
568 }
569 }
570
571 pub async fn start(&mut self) -> DeviceResult<()> {
572 Ok(())
574 }
575
576 pub async fn stop(&mut self) -> DeviceResult<()> {
577 Ok(())
579 }
580
581 pub async fn send_alert_notification(&mut self, alert: &ActiveAlert) -> DeviceResult<()> {
582 for channel in &self.channels {
583 if !channel.enabled {
584 continue;
585 }
586
587 if self.rate_limiter.should_rate_limit(&channel.channel_type) {
588 continue;
589 }
590
591 let message = self.format_alert_message(alert, &channel.channel_type);
592 let task = NotificationTask {
593 task_id: format!("{}-{:?}", alert.alert_id, channel.channel_type),
594 alert_id: alert.alert_id.clone(),
595 channel_type: channel.channel_type.clone(),
596 message,
597 priority: self.map_severity_to_priority(&alert.severity),
598 retry_count: 0,
599 max_retries: 3,
600 created_at: SystemTime::now(),
601 };
602
603 self.notification_queue.push_back(task);
604 }
605
606 self.process_notification_queue().await?;
607 Ok(())
608 }
609
610 async fn process_notification_queue(&mut self) -> DeviceResult<()> {
611 while let Some(task) = self.notification_queue.pop_front() {
612 let delivery_status = self.deliver_notification(&task).await?;
613
614 if delivery_status == DeliveryStatus::Failed && task.retry_count < task.max_retries {
615 let mut retry_task = task.clone();
616 retry_task.retry_count += 1;
617 self.notification_queue.push_back(retry_task);
618 }
619
620 self.record_delivery(&task, delivery_status);
621 }
622
623 Ok(())
624 }
625
626 async fn deliver_notification(&self, task: &NotificationTask) -> DeviceResult<DeliveryStatus> {
627 match task.channel_type {
629 ChannelType::Email => {
630 Ok(DeliveryStatus::Sent)
632 }
633 ChannelType::Slack => {
634 Ok(DeliveryStatus::Sent)
636 }
637 ChannelType::Webhook => {
638 Ok(DeliveryStatus::Sent)
640 }
641 _ => Ok(DeliveryStatus::Failed),
642 }
643 }
644
645 fn format_alert_message(
646 &self,
647 alert: &ActiveAlert,
648 channel_type: &ChannelType,
649 ) -> NotificationMessage {
650 let subject = format!(
651 "[{}] Alert: {} threshold exceeded",
652 alert.severity as i32, alert.metric_name
653 );
654 let body = format!(
655 "Metric: {}\nCurrent Value: {:.4}\nThreshold: {:.4}\nSeverity: {:?}\nTime: {:?}",
656 alert.metric_name,
657 alert.current_value,
658 alert.threshold.value,
659 alert.severity,
660 alert.timestamp
661 );
662
663 let format = match channel_type {
664 ChannelType::Email => MessageFormat::HTML,
665 ChannelType::Slack => MessageFormat::Markdown,
666 _ => MessageFormat::PlainText,
667 };
668
669 NotificationMessage {
670 subject,
671 body,
672 format,
673 attachments: Vec::new(),
674 metadata: HashMap::new(),
675 }
676 }
677
678 fn map_severity_to_priority(&self, severity: &AlertSeverity) -> NotificationPriority {
679 match severity {
680 AlertSeverity::Info => NotificationPriority::Low,
681 AlertSeverity::Warning => NotificationPriority::Normal,
682 AlertSeverity::Error => NotificationPriority::High,
683 AlertSeverity::Critical => NotificationPriority::Critical,
684 }
685 }
686
687 fn record_delivery(&mut self, task: &NotificationTask, status: DeliveryStatus) {
688 let record = DeliveryRecord {
689 task_id: task.task_id.clone(),
690 channel_type: task.channel_type.clone(),
691 delivery_time: SystemTime::now(),
692 delivery_status: status,
693 response_time: Duration::from_millis(100), error_message: None,
695 };
696
697 self.delivery_history.push_back(record);
698
699 if self.delivery_history.len() > 10000 {
701 self.delivery_history.pop_front();
702 }
703 }
704}
705
706impl RateLimiter {
707 pub fn new() -> Self {
708 Self {
709 limits: HashMap::new(),
710 usage_tracking: HashMap::new(),
711 }
712 }
713
714 pub fn should_rate_limit(&mut self, channel_type: &ChannelType) -> bool {
715 let limit = self.limits.get(channel_type).cloned().unwrap_or(RateLimit {
716 max_notifications: 100,
717 time_window: Duration::from_secs(3600),
718 burst_limit: Some(10),
719 });
720
721 let now = SystemTime::now();
722 let usage = self
723 .usage_tracking
724 .entry(channel_type.clone())
725 .or_insert_with(VecDeque::new);
726
727 while let Some(front) = usage.front() {
729 if now.duration_since(*front).unwrap_or(Duration::from_secs(0)) > limit.time_window {
730 usage.pop_front();
731 } else {
732 break;
733 }
734 }
735
736 if usage.len() >= limit.max_notifications {
738 return true; }
740
741 usage.push_back(now);
743 false }
745}
746
747impl SuppressionEngine {
748 pub fn new(rules: Vec<SuppressionRule>) -> Self {
749 Self {
750 rules,
751 suppressed_alerts: HashMap::new(),
752 suppression_history: VecDeque::new(),
753 }
754 }
755
756 pub async fn start(&mut self) -> DeviceResult<()> {
757 Ok(())
759 }
760
761 pub async fn stop(&mut self) -> DeviceResult<()> {
762 Ok(())
764 }
765
766 pub async fn should_suppress(&mut self, alert: &ActiveAlert) -> DeviceResult<bool> {
767 for rule in self.rules.clone() {
768 if !rule.enabled {
769 continue;
770 }
771
772 if self.matches_suppression_rule(alert, &rule) {
773 self.apply_suppression(alert, &rule).await?;
774 return Ok(true);
775 }
776 }
777
778 Ok(false)
779 }
780
781 fn matches_suppression_rule(&self, _alert: &ActiveAlert, _rule: &SuppressionRule) -> bool {
782 false
784 }
785
786 async fn apply_suppression(
787 &mut self,
788 alert: &ActiveAlert,
789 rule: &SuppressionRule,
790 ) -> DeviceResult<()> {
791 let record = SuppressionRecord {
792 alert_id: alert.alert_id.clone(),
793 rule_id: rule.rule_name.clone(),
794 suppression_start: SystemTime::now(),
795 suppression_end: SystemTime::now() + rule.duration,
796 suppression_count: 1,
797 };
798
799 self.suppressed_alerts
800 .insert(alert.alert_id.clone(), record);
801
802 let event = SuppressionEvent {
803 timestamp: SystemTime::now(),
804 event_type: SuppressionEventType::AlertSuppressed,
805 alert_id: alert.alert_id.clone(),
806 rule_id: rule.rule_name.clone(),
807 details: HashMap::new(),
808 };
809
810 self.suppression_history.push_back(event);
811
812 Ok(())
813 }
814}
815
816impl EscalationEngine {
817 pub fn new(policies: Vec<EscalationPolicy>) -> Self {
818 Self {
819 policies,
820 active_escalations: HashMap::new(),
821 escalation_history: VecDeque::new(),
822 }
823 }
824
825 pub async fn start(&mut self) -> DeviceResult<()> {
826 Ok(())
828 }
829
830 pub async fn stop(&mut self) -> DeviceResult<()> {
831 self.active_escalations.clear();
833 Ok(())
834 }
835
836 pub async fn start_escalation(&mut self, alert: &ActiveAlert) -> DeviceResult<()> {
837 if let Some(policy) = self.find_escalation_policy(alert) {
839 let state = EscalationState {
840 alert_id: alert.alert_id.clone(),
841 policy_id: policy.policy_name.clone(),
842 current_step: 0,
843 escalation_start: SystemTime::now(),
844 next_escalation: Some(SystemTime::now() + Duration::from_secs(15 * 60)), escalation_attempts: 0,
846 };
847
848 self.active_escalations
849 .insert(alert.alert_id.clone(), state);
850 }
851
852 Ok(())
853 }
854
855 pub async fn stop_escalation(&mut self, alert_id: &str) -> DeviceResult<()> {
856 if let Some(_state) = self.active_escalations.remove(alert_id) {
857 let event = EscalationEvent {
859 timestamp: SystemTime::now(),
860 alert_id: alert_id.to_string(),
861 policy_id: String::new(),
862 step_number: 0,
863 escalation_type: EscalationType::Notification,
864 success: true,
865 details: HashMap::new(),
866 };
867
868 self.escalation_history.push_back(event);
869 }
870
871 Ok(())
872 }
873
874 fn find_escalation_policy(&self, _alert: &ActiveAlert) -> Option<&EscalationPolicy> {
875 self.policies.first()
877 }
878}
879
880impl Default for AlertStatistics {
882 fn default() -> Self {
883 Self {
884 total_alerts: 0,
885 alerts_by_severity: HashMap::new(),
886 alerts_by_metric: HashMap::new(),
887 average_resolution_time: Duration::from_secs(0),
888 false_positive_rate: 0.0,
889 escalation_rate: 0.0,
890 acknowledgement_rate: 0.0,
891 }
892 }
893}
894
895impl Default for AlertTrends {
896 fn default() -> Self {
897 Self {
898 alert_frequency_trend: TrendDirection::Stable,
899 severity_trends: HashMap::new(),
900 resolution_time_trend: TrendDirection::Stable,
901 false_positive_trend: TrendDirection::Stable,
902 }
903 }
904}