Skip to content

Commit 2ddebe1

Browse files
committed
Multiple changes
Added endpoints- - PATCH /{alertid}/enable -> enable a disabled alert - PATCH /{alertid}/disable -> disable an alert - PATCH /{alertid}/update_notification_state -> update the notification state (notify, mute) - PUT /{alertid}/evaluate_alert -> run manual eval for an alert - PUT /{alertid} -> modify an alert
1 parent f6bfdf8 commit 2ddebe1

31 files changed

+966
-485
lines changed

src/about.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,10 @@ pub fn print_about(
112112
current_version,
113113
); // " " " "
114114

115-
if let Some(latest_release) = latest_release {
116-
if latest_release.version > current_version {
117-
print_latest_release(latest_release);
118-
}
115+
if let Some(latest_release) = latest_release
116+
&& latest_release.version > current_version
117+
{
118+
print_latest_release(latest_release);
119119
}
120120

121121
eprintln!(

src/alerts/alert_enums.rs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,20 @@
1616
*
1717
*/
1818

19-
use std::fmt::{self, Display};
19+
use std::{
20+
fmt::{self, Display},
21+
str::FromStr,
22+
};
2023

24+
use chrono::{DateTime, Utc};
2125
use derive_more::derive::FromStr;
26+
use serde::ser::Error;
2227
use ulid::Ulid;
2328

24-
use crate::alerts::{alert_structs::RollingWindow, alert_traits::AlertTrait};
29+
use crate::alerts::{
30+
alert_structs::{AnomalyConfig, ForecastConfig, RollingWindow},
31+
alert_traits::AlertTrait,
32+
};
2533

2634
pub enum AlertTask {
2735
Create(Box<dyn AlertTrait>),
@@ -87,16 +95,16 @@ impl Display for LogicalOperator {
8795
#[serde(rename_all = "camelCase")]
8896
pub enum AlertType {
8997
Threshold,
90-
Anomaly,
91-
Forecast,
98+
Anomaly(AnomalyConfig),
99+
Forecast(ForecastConfig),
92100
}
93101

94102
impl Display for AlertType {
95103
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96104
match self {
97105
AlertType::Threshold => write!(f, "threshold"),
98-
AlertType::Anomaly => write!(f, "anomaly"),
99-
AlertType::Forecast => write!(f, "forecast"),
106+
AlertType::Anomaly(_) => write!(f, "anomaly"),
107+
AlertType::Forecast(_) => write!(f, "forecast"),
100108
}
101109
}
102110
}
@@ -232,14 +240,14 @@ pub enum AlertState {
232240
Triggered,
233241
#[default]
234242
NotTriggered,
235-
Paused,
243+
Disabled,
236244
}
237245

238246
impl Display for AlertState {
239247
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240248
match self {
241249
AlertState::Triggered => write!(f, "triggered"),
242-
AlertState::Paused => write!(f, "paused"),
250+
AlertState::Disabled => write!(f, "disabled"),
243251
AlertState::NotTriggered => write!(f, "not-triggered"),
244252
}
245253
}
@@ -255,14 +263,22 @@ pub enum NotificationState {
255263
/// It is a state which can only be set manually
256264
///
257265
/// user needs to pass the timestamp or the duration (in human time) till which the alert is silenced
258-
Snoozed(String),
266+
Mute(String),
259267
}
260268

261269
impl Display for NotificationState {
262270
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
263271
match self {
264272
NotificationState::Notify => write!(f, "notify"),
265-
NotificationState::Snoozed(end_time) => write!(f, "snoozed till {end_time}"),
273+
NotificationState::Mute(till_time) => {
274+
let till = match till_time.as_str() {
275+
"indefinite" => DateTime::<Utc>::MAX_UTC.to_rfc3339(),
276+
_ => DateTime::<Utc>::from_str(till_time)
277+
.map_err(|e| std::fmt::Error::custom(e.to_string()))?
278+
.to_rfc3339(),
279+
};
280+
write!(f, "{till}")
281+
}
266282
}
267283
}
268284
}

src/alerts/alert_structs.rs

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
use std::collections::HashMap;
2020

2121
use chrono::{DateTime, Utc};
22-
use serde::Serialize;
22+
use serde::{Deserialize, Serialize};
2323
use tokio::sync::{RwLock, mpsc};
2424
use ulid::Ulid;
2525

@@ -86,9 +86,9 @@ impl Context {
8686
format!("{} is now `not-triggered` ", self.alert_info.alert_name)
8787
}
8888

89-
pub(crate) fn default_paused_string(&self) -> String {
89+
pub(crate) fn default_disabled_string(&self) -> String {
9090
format!(
91-
"{} is now `paused`. No more evals will be run till it is `paused`.",
91+
"{} is now `disabled`. No more evals will be run till it is `disabled`.",
9292
self.alert_info.alert_name
9393
)
9494
}
@@ -242,6 +242,16 @@ pub struct RollingWindow {
242242
pub eval_frequency: u64,
243243
}
244244

245+
impl Default for RollingWindow {
246+
fn default() -> Self {
247+
Self {
248+
eval_start: "10m".into(),
249+
eval_end: "now".into(),
250+
eval_frequency: 10,
251+
}
252+
}
253+
}
254+
245255
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)]
246256
#[serde(rename_all = "camelCase")]
247257
pub struct AlertRequest {
@@ -329,3 +339,45 @@ pub struct AlertsInfo {
329339
pub id: Ulid,
330340
pub severity: Severity,
331341
}
342+
343+
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq)]
344+
#[serde(rename_all = "camelCase")]
345+
pub struct ForecastConfig {
346+
pub historic_duration: String,
347+
pub forecast_duration: String,
348+
}
349+
350+
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq)]
351+
#[serde(rename_all = "camelCase")]
352+
pub struct AnomalyConfig {
353+
pub historic_duration: String,
354+
}
355+
356+
/// Result structure for alert query execution with group support
357+
#[derive(Debug, Clone, Serialize, Deserialize)]
358+
pub struct AlertQueryResult {
359+
/// List of group results, each containing group values and the aggregate value
360+
pub groups: Vec<GroupResult>,
361+
/// True if this is a simple query without GROUP BY (single group with empty group_values)
362+
pub is_simple_query: bool,
363+
}
364+
365+
/// Result for a single group in a GROUP BY query
366+
#[derive(Debug, Clone, Serialize, Deserialize)]
367+
pub struct GroupResult {
368+
/// The group-by column values (empty for non-GROUP BY queries)
369+
pub group_values: HashMap<String, String>,
370+
/// The aggregate function value for this group
371+
pub aggregate_value: f64,
372+
}
373+
374+
impl AlertQueryResult {
375+
/// Get the single aggregate value for simple queries (backward compatibility)
376+
pub fn get_single_value(&self) -> f64 {
377+
if self.is_simple_query && !self.groups.is_empty() {
378+
self.groups[0].aggregate_value
379+
} else {
380+
0.0
381+
}
382+
}
383+
}

src/alerts/alert_traits.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,15 @@ pub trait AlertTrait: Debug + Send + Sync {
6565
fn get_alert_type(&self) -> &AlertType;
6666
fn get_threshold_config(&self) -> &ThresholdConfig;
6767
fn get_eval_config(&self) -> &EvalConfig;
68-
fn get_targets(&self) -> &Vec<Ulid>;
68+
fn get_targets(&self) -> &[Ulid];
6969
fn get_state(&self) -> &AlertState;
70-
fn get_eval_window(&self) -> String;
70+
fn get_eval_window(&self) -> &str;
7171
fn get_eval_frequency(&self) -> u64;
7272
fn get_created(&self) -> String;
7373
fn get_tags(&self) -> &Option<Vec<String>>;
74-
fn get_datasets(&self) -> &Vec<String>;
74+
fn get_datasets(&self) -> &[String];
7575
fn to_alert_config(&self) -> AlertConfig;
7676
fn clone_box(&self) -> Box<dyn AlertTrait>;
77-
// fn get_alert_message(&self) -> Result<String, AlertError>;
7877
}
7978

8079
#[async_trait]

0 commit comments

Comments
 (0)