shape_runtime/alerts/
types.rs1use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use uuid::Uuid;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(rename_all = "lowercase")]
13#[derive(Default)]
14pub enum AlertSeverity {
15 Debug,
17 #[default]
19 Info,
20 Warning,
22 Error,
24 Critical,
26}
27
28impl std::fmt::Display for AlertSeverity {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 match self {
31 AlertSeverity::Debug => write!(f, "DEBUG"),
32 AlertSeverity::Info => write!(f, "INFO"),
33 AlertSeverity::Warning => write!(f, "WARNING"),
34 AlertSeverity::Error => write!(f, "ERROR"),
35 AlertSeverity::Critical => write!(f, "CRITICAL"),
36 }
37 }
38}
39
40impl AlertSeverity {
41 pub fn from_str(s: &str) -> Self {
43 match s.to_lowercase().as_str() {
44 "debug" => AlertSeverity::Debug,
45 "info" => AlertSeverity::Info,
46 "warning" | "warn" => AlertSeverity::Warning,
47 "error" | "err" => AlertSeverity::Error,
48 "critical" | "crit" => AlertSeverity::Critical,
49 _ => AlertSeverity::Info,
50 }
51 }
52
53 pub fn priority(&self) -> u8 {
55 match self {
56 AlertSeverity::Debug => 0,
57 AlertSeverity::Info => 1,
58 AlertSeverity::Warning => 2,
59 AlertSeverity::Error => 3,
60 AlertSeverity::Critical => 4,
61 }
62 }
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct Alert {
68 pub id: Uuid,
70
71 pub severity: AlertSeverity,
73
74 pub title: String,
76
77 pub message: String,
79
80 #[serde(default)]
82 pub data: HashMap<String, serde_json::Value>,
83
84 #[serde(default)]
86 pub tags: Vec<String>,
87
88 pub timestamp: DateTime<Utc>,
90
91 #[serde(default)]
93 pub source: Option<String>,
94}
95
96impl Alert {
97 pub fn new(title: impl Into<String>, message: impl Into<String>) -> Self {
99 Self {
100 id: Uuid::new_v4(),
101 severity: AlertSeverity::Info,
102 title: title.into(),
103 message: message.into(),
104 data: HashMap::new(),
105 tags: Vec::new(),
106 timestamp: Utc::now(),
107 source: None,
108 }
109 }
110
111 pub fn with_severity(mut self, severity: AlertSeverity) -> Self {
113 self.severity = severity;
114 self
115 }
116
117 pub fn with_tag(mut self, tag: impl Into<String>) -> Self {
119 self.tags.push(tag.into());
120 self
121 }
122
123 pub fn with_tags(mut self, tags: impl IntoIterator<Item = impl Into<String>>) -> Self {
125 self.tags.extend(tags.into_iter().map(|t| t.into()));
126 self
127 }
128
129 pub fn with_data(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
131 self.data.insert(key.into(), value);
132 self
133 }
134
135 pub fn with_source(mut self, source: impl Into<String>) -> Self {
137 self.source = Some(source.into());
138 self
139 }
140
141 pub fn has_tag(&self, tag: &str) -> bool {
143 self.tags.iter().any(|t| t == tag)
144 }
145
146 pub fn has_any_tag(&self, tags: &[String]) -> bool {
148 tags.iter().any(|t| self.has_tag(t))
149 }
150}
151
152impl Default for Alert {
153 fn default() -> Self {
154 Self::new("", "")
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161
162 #[test]
163 fn test_alert_creation() {
164 let alert = Alert::new("Test Alert", "This is a test message")
165 .with_severity(AlertSeverity::Warning)
166 .with_tag("test")
167 .with_data("key", serde_json::json!("value"));
168
169 assert_eq!(alert.title, "Test Alert");
170 assert_eq!(alert.message, "This is a test message");
171 assert_eq!(alert.severity, AlertSeverity::Warning);
172 assert!(alert.has_tag("test"));
173 assert_eq!(alert.data.get("key"), Some(&serde_json::json!("value")));
174 }
175
176 #[test]
177 fn test_severity_priority() {
178 assert!(AlertSeverity::Critical.priority() > AlertSeverity::Error.priority());
179 assert!(AlertSeverity::Error.priority() > AlertSeverity::Warning.priority());
180 assert!(AlertSeverity::Warning.priority() > AlertSeverity::Info.priority());
181 assert!(AlertSeverity::Info.priority() > AlertSeverity::Debug.priority());
182 }
183
184 #[test]
185 fn test_severity_from_str() {
186 assert_eq!(AlertSeverity::from_str("debug"), AlertSeverity::Debug);
187 assert_eq!(AlertSeverity::from_str("WARNING"), AlertSeverity::Warning);
188 assert_eq!(AlertSeverity::from_str("crit"), AlertSeverity::Critical);
189 assert_eq!(AlertSeverity::from_str("unknown"), AlertSeverity::Info);
190 }
191}