pub mod dedup;
pub mod escalation;
pub mod routing;
pub mod rules;
use crate::error::Result;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Alert {
pub id: String,
pub name: String,
pub severity: AlertSeverity,
pub status: AlertStatus,
pub message: String,
pub labels: std::collections::HashMap<String, String>,
pub timestamp: DateTime<Utc>,
pub starts_at: DateTime<Utc>,
pub ends_at: Option<DateTime<Utc>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum AlertSeverity {
Critical,
High,
Medium,
Low,
Info,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum AlertStatus {
Firing,
Resolved,
Acknowledged,
Silenced,
}
impl Alert {
pub fn new(name: String, severity: AlertSeverity, message: String) -> Self {
let now = Utc::now();
Self {
id: uuid::Uuid::new_v4().to_string(),
name,
severity,
status: AlertStatus::Firing,
message,
labels: std::collections::HashMap::new(),
timestamp: now,
starts_at: now,
ends_at: None,
}
}
pub fn with_label(mut self, key: String, value: String) -> Self {
self.labels.insert(key, value);
self
}
pub fn resolve(&mut self) {
self.status = AlertStatus::Resolved;
self.ends_at = Some(Utc::now());
}
pub fn acknowledge(&mut self) {
self.status = AlertStatus::Acknowledged;
}
}
pub struct AlertManager {
rules: rules::AlertRuleEngine,
router: routing::AlertRouter,
deduplicator: dedup::AlertDeduplicator,
}
impl AlertManager {
pub fn new() -> Self {
Self {
rules: rules::AlertRuleEngine::new(),
router: routing::AlertRouter::new(),
deduplicator: dedup::AlertDeduplicator::new(),
}
}
pub fn add_rule(&mut self, rule: rules::AlertRule) {
self.rules.add_rule(rule);
}
pub fn add_route(&mut self, route: routing::Route) {
self.router.add_route(route);
}
pub async fn evaluate_rules(&mut self) -> Result<Vec<Alert>> {
let alerts = self.rules.evaluate().await?;
let deduplicated = self.deduplicator.deduplicate(&alerts)?;
for alert in &deduplicated {
self.router.route(alert).await?;
}
Ok(deduplicated)
}
}
impl Default for AlertManager {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_alert_creation() {
let alert = Alert::new(
"test_alert".to_string(),
AlertSeverity::High,
"Test alert message".to_string(),
)
.with_label("service".to_string(), "oxigdal".to_string());
assert_eq!(alert.name, "test_alert");
assert_eq!(alert.severity, AlertSeverity::High);
assert_eq!(alert.status, AlertStatus::Firing);
assert_eq!(alert.labels.len(), 1);
}
#[test]
fn test_alert_resolution() {
let mut alert = Alert::new(
"test_alert".to_string(),
AlertSeverity::High,
"Test alert message".to_string(),
);
alert.resolve();
assert_eq!(alert.status, AlertStatus::Resolved);
assert!(alert.ends_at.is_some());
}
}