diff --git a/agent/src/status/mod.rs b/agent/src/status/mod.rs index 4036b5e..6aa5545 100644 --- a/agent/src/status/mod.rs +++ b/agent/src/status/mod.rs @@ -251,10 +251,32 @@ impl HostStatusManager { details: Some(self.format_aggregated_details(aggregated)), }; + // Create a descriptive summary based on change types + let mut summary_parts = Vec::new(); + let critical_count = aggregated.service_summaries.iter().filter(|s| s.final_status == Status::Critical).count(); + let warning_count = aggregated.service_summaries.iter().filter(|s| s.final_status == Status::Warning).count(); + let recovery_count = aggregated.service_summaries.iter().filter(|s| + matches!((s.initial_status, s.final_status), (Status::Warning | Status::Critical, Status::Ok)) + ).count(); + let startup_count = aggregated.service_summaries.iter().filter(|s| + matches!((s.initial_status, s.final_status), (Status::Unknown, Status::Ok | Status::Pending)) + ).count(); + + if critical_count > 0 { summary_parts.push(format!("{} critical", critical_count)); } + if warning_count > 0 { summary_parts.push(format!("{} warning", warning_count)); } + if recovery_count > 0 { summary_parts.push(format!("{} recovered", recovery_count)); } + if startup_count > 0 { summary_parts.push(format!("{} started", startup_count)); } + + let summary_text = if summary_parts.is_empty() { + format!("{} service changes", aggregated.service_summaries.len()) + } else { + summary_parts.join(", ") + }; + // Create a dummy metric for the notification let summary_metric = Metric { name: "host_status_summary".to_string(), - value: cm_dashboard_shared::MetricValue::String(format!("{} services changed", aggregated.service_summaries.len())), + value: cm_dashboard_shared::MetricValue::String(summary_text), status: aggregated.host_status_final, timestamp: Utc::now().timestamp() as u64, description: Some("Aggregated status summary".to_string()), @@ -282,32 +304,72 @@ impl HostStatusManager { )); } - details.push_str("Service Changes:\n"); + // Group services by change type + let mut critical_changes = Vec::new(); + let mut warning_changes = Vec::new(); + let mut recovery_changes = Vec::new(); + let mut startup_changes = Vec::new(); + let mut other_changes = Vec::new(); + for summary in &aggregated.service_summaries { - if summary.significant_change { - let status_indicator = if summary.final_status == Status::Ok && - (summary.initial_status == Status::Warning || summary.initial_status == Status::Critical) { - "✅" - } else if summary.final_status == Status::Warning { - "🟡" - } else if summary.final_status == Status::Critical { - "🔴" - } else { - "â„šī¸" - }; + let change_info = format!( + "{}: {:?} → {:?}{}", + summary.service_name, + summary.initial_status, + summary.final_status, + if summary.change_count > 1 { format!(" ({} changes)", summary.change_count) } else { String::new() } + ); - details.push_str(&format!( - " {} {}: {:?} → {:?}", - status_indicator, - summary.service_name, - summary.initial_status, - summary.final_status - )); + match (summary.initial_status, summary.final_status) { + (_, Status::Critical) => critical_changes.push(change_info), + (_, Status::Warning) => warning_changes.push(change_info), + (Status::Warning | Status::Critical, Status::Ok) => recovery_changes.push(change_info), + (Status::Unknown, Status::Ok | Status::Pending) => startup_changes.push(change_info), + _ => other_changes.push(change_info), + } + } - if summary.change_count > 1 { - details.push_str(&format!(" ({} changes)", summary.change_count)); - } - details.push('\n'); + // Show critical problems first + if !critical_changes.is_empty() { + details.push_str(&format!("🔴 CRITICAL ISSUES ({}):\n", critical_changes.len())); + for change in critical_changes { + details.push_str(&format!(" {}\n", change)); + } + details.push('\n'); + } + + // Show warnings + if !warning_changes.is_empty() { + details.push_str(&format!("🟡 WARNINGS ({}):\n", warning_changes.len())); + for change in warning_changes { + details.push_str(&format!(" {}\n", change)); + } + details.push('\n'); + } + + // Show recoveries + if !recovery_changes.is_empty() { + details.push_str(&format!("✅ RECOVERIES ({}):\n", recovery_changes.len())); + for change in recovery_changes { + details.push_str(&format!(" {}\n", change)); + } + details.push('\n'); + } + + // Show startups (usually not important but good to know) + if !startup_changes.is_empty() { + details.push_str(&format!("đŸŸĸ SERVICE STARTUPS ({}):\n", startup_changes.len())); + for change in startup_changes { + details.push_str(&format!(" {}\n", change)); + } + details.push('\n'); + } + + // Show other changes + if !other_changes.is_empty() { + details.push_str(&format!("â„šī¸ OTHER CHANGES ({}):\n", other_changes.len())); + for change in other_changes { + details.push_str(&format!(" {}\n", change)); } }