Improve notification email format with detailed service groupings

This commit is contained in:
Christoffer Martinsson 2025-10-21 19:25:43 +02:00
parent 34822bd835
commit 7ead8ee98a

View File

@ -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));
}
}