//! offline alert/recovery messages. Domain half of the Alerter split; //! shared dispatch/cooldown plumbing lives in the parent module. use tracing::instrument; use super::{AlertCategory, AlertMeta, Alerter}; impl Alerter { /// All monitored targets are unreachable, likely a network issue with PoM itself. #[instrument(skip_all)] pub async fn send_monitoring_offline_alert(&self, target_count: usize) { let alert_key = "monitoring:self"; let subject = format!("[PoM] all {target_count} targets unreachable"); let body = format!( "All {target_count} monitored targets are non-operational.\n\ This likely indicates a network issue with the PoM instance itself,\n\ not an actual outage of all targets.\n\n\ Instance: {}\n\ Time: {}\n\n\ - PoM", self.instance_name, chrono::Utc::now().to_rfc3339(), ); self.fire_failure( &subject, &body, "critical", "pom-monitoring", Some("self"), AlertMeta { key: alert_key, category: AlertCategory::MonitoringOffline, from: None, to: None, error: None, }, ) .await; } /// At least one target is reachable again after a monitoring-offline event. #[instrument(skip_all)] pub async fn send_monitoring_recovery(&self) { let alert_key = "monitoring:self"; let subject = "[PoM] monitoring recovered".to_string(); let body = format!( "At least one target is reachable again.\n\ Instance: {}\n\ Time: {}\n\n\ - PoM", self.instance_name, chrono::Utc::now().to_rfc3339(), ); self.fire_recovery( &subject, &body, AlertMeta { key: alert_key, category: AlertCategory::MonitoringRecovery, from: None, to: None, error: None, }, ) .await; } }