///|
/// Severity of an operational monitoring alert.
pub enum MonitoringAlertSeverity {
AlertNotice
AlertWarning
AlertCritical
}
///|
/// An alert emitted from waveform or network metrics.
pub struct MonitoringAlert {
code : String
severity : MonitoringAlertSeverity
station : String
channel : String
timestamp : Double
value : Double
threshold : Double
message : String
acknowledged : Bool
}
///|
/// A configurable alert rule.
pub struct MonitoringRule {
code : String
severity : MonitoringAlertSeverity
threshold : Double
greater_than : Bool
message : String
}
///|
/// Aggregate alert state for a monitoring cycle.
pub struct MonitoringAlertSummary {
total : Int
notices : Int
warnings : Int
critical : Int
unacknowledged : Int
healthy : Bool
}
///|
/// Return all alert severity values.
pub fn supported_monitoring_alerts() -> Array[MonitoringAlertSeverity] {
[AlertNotice, AlertWarning, AlertCritical]
}
///|
/// Return a stable alert severity label.
pub fn monitoring_alert_severity_name(
severity : MonitoringAlertSeverity,
) -> String {
match severity {
AlertNotice => "notice"
AlertWarning => "warning"
AlertCritical => "critical"
}
}
///|
/// Evaluate one rule against a value.
pub fn evaluate_monitoring_rule(
rule : MonitoringRule,
station : String,
channel : String,
timestamp : Double,
value : Double,
) -> MonitoringAlert? {
let violated = if rule.greater_than {
value > rule.threshold
} else {
value < rule.threshold
}
if violated {
Some({
code: rule.code,
severity: rule.severity,
station,
channel,
timestamp,
value,
threshold: rule.threshold,
message: rule.message,
acknowledged: false,
})
} else {
None
}
}
///|
/// Build standard station health rules.
pub fn standard_monitoring_rules() -> Array[MonitoringRule] {
[
{
code: "LOW_COMPLETENESS",
severity: AlertWarning,
threshold: 0.95,
greater_than: false,
message: "channel completeness is below target",
},
{
code: "CLIPPING",
severity: AlertCritical,
threshold: 0.001,
greater_than: true,
message: "channel clipping fraction is high",
},
{
code: "LOW_SNR",
severity: AlertWarning,
threshold: 3.0,
greater_than: false,
message: "signal-to-noise ratio is low",
},
{
code: "QUALITY_FAIL",
severity: AlertCritical,
threshold: 0.4,
greater_than: false,
message: "station quality score is below minimum",
},
]
}
///|
/// Evaluate standard rules for one quality report.
pub fn alerts_for_quality_report(
report : StationQualityReport,
timestamp : Double,
) -> Array[MonitoringAlert] {
let alerts : Array[MonitoringAlert] = Array::new()
let values = [
report.completeness,
report.clipping_fraction,
report.signal_to_noise_db,
report.score,
]
let rules = standard_monitoring_rules()
for index = 0
index < rules.length() && index < values.length()
index = index + 1 {
match
evaluate_monitoring_rule(
rules[index],
report.station,
report.channel,
timestamp,
values[index],
) {
Some(alert) => alerts.push(alert)
None => ()
}
}
alerts
}
///|
/// Count and classify alerts for an operator dashboard.
pub fn summarize_monitoring_alerts(
alerts : Array[MonitoringAlert],
) -> MonitoringAlertSummary {
let mut notices = 0
let mut warnings = 0
let mut critical = 0
let mut unacknowledged = 0
for alert in alerts {
if !alert.acknowledged {
unacknowledged += 1
}
match alert.severity {
AlertNotice => notices += 1
AlertWarning => warnings += 1
AlertCritical => critical += 1
}
}
{
total: alerts.length(),
notices,
warnings,
critical,
unacknowledged,
healthy: critical == 0,
}
}
///|
/// Mark an alert acknowledged by code and station.
pub fn acknowledge_alert(
alert : MonitoringAlert,
code : String,
station : String,
) -> MonitoringAlert {
{
code: alert.code,
severity: alert.severity,
station: alert.station,
channel: alert.channel,
timestamp: alert.timestamp,
value: alert.value,
threshold: alert.threshold,
message: alert.message,
acknowledged: alert.acknowledged ||
(alert.code == code && alert.station == station),
}
}
///|
/// Export alerts for a monitoring incident queue.
pub fn monitoring_alerts_to_csv(alerts : Array[MonitoringAlert]) -> String {
let mut output = "code,severity,station,channel,timestamp,value,threshold,acknowledged,message\n"
for alert in alerts {
output = output +
alert.code +
"," +
monitoring_alert_severity_name(alert.severity) +
"," +
alert.station +
"," +
alert.channel +
"," +
alert.timestamp.to_string() +
"," +
alert.value.to_string() +
"," +
alert.threshold.to_string() +
"," +
alert.acknowledged.to_string() +
"," +
alert.message +
"\n"
}
output
}
///|
/// Format an alert summary for a health endpoint.
pub fn monitoring_alert_summary_text(
summary : MonitoringAlertSummary,
) -> String {
"total=" +
summary.total.to_string() +
" notices=" +
summary.notices.to_string() +
" warnings=" +
summary.warnings.to_string() +
" critical=" +
summary.critical.to_string() +
" unacknowledged=" +
summary.unacknowledged.to_string() +
" healthy=" +
summary.healthy.to_string()
}