Skip to content

Commit fc4cbbf

Browse files
authored
Alerts updates (#1398)
* Updates to alerts - separated out enums, traits, and structs - added ability to pause alert evals (new endpoints to pause and resume) - added snooze for notifications (time dependent) - removed masking from targets fow now * updates: - separated `NotificationConfig` from target config * Update sync.rs * Update alert_structs.rs add serde default * 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 * updates: coderabbit suggestions and bugfixes * bugfixes deadlock issue with alert updates * updates added pagination * fix aggregate alias fetch * updated message
1 parent 574e3b1 commit fc4cbbf

File tree

14 files changed

+2023
-994
lines changed

14 files changed

+2023
-994
lines changed

src/alerts/alert_enums.rs

Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
/*
2+
* Parseable Server (C) 2022 - 2024 Parseable, Inc.
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU Affero General Public License as
6+
* published by the Free Software Foundation, either version 3 of the
7+
* License, or (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Affero General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Affero General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*
17+
*/
18+
19+
use std::fmt::{self, Display};
20+
21+
use chrono::{DateTime, Utc};
22+
use derive_more::derive::FromStr;
23+
use ulid::Ulid;
24+
25+
use crate::alerts::{
26+
alert_structs::{AnomalyConfig, ForecastConfig, RollingWindow},
27+
alert_traits::AlertTrait,
28+
};
29+
30+
pub enum AlertTask {
31+
Create(Box<dyn AlertTrait>),
32+
Delete(Ulid),
33+
}
34+
35+
#[derive(Default, Debug, serde::Serialize, serde::Deserialize, Clone)]
36+
#[serde(rename_all = "lowercase")]
37+
pub enum AlertVersion {
38+
V1,
39+
#[default]
40+
V2,
41+
}
42+
43+
impl From<&str> for AlertVersion {
44+
fn from(value: &str) -> Self {
45+
match value {
46+
"v1" => Self::V1,
47+
"v2" => Self::V2,
48+
_ => Self::V2, // default to v2
49+
}
50+
}
51+
}
52+
53+
#[derive(
54+
Debug,
55+
serde::Serialize,
56+
serde::Deserialize,
57+
Clone,
58+
Default,
59+
FromStr,
60+
PartialEq,
61+
PartialOrd,
62+
Eq,
63+
Ord,
64+
)]
65+
#[serde(rename_all = "camelCase")]
66+
pub enum Severity {
67+
Critical,
68+
High,
69+
#[default]
70+
Medium,
71+
Low,
72+
}
73+
74+
impl Display for Severity {
75+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76+
match self {
77+
Severity::Critical => write!(f, "Critical"),
78+
Severity::High => write!(f, "High"),
79+
Severity::Medium => write!(f, "Medium"),
80+
Severity::Low => write!(f, "Low"),
81+
}
82+
}
83+
}
84+
85+
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)]
86+
#[serde(rename_all = "camelCase")]
87+
pub enum LogicalOperator {
88+
And,
89+
Or,
90+
}
91+
92+
impl Display for LogicalOperator {
93+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94+
match self {
95+
LogicalOperator::And => write!(f, "AND"),
96+
LogicalOperator::Or => write!(f, "OR"),
97+
}
98+
}
99+
}
100+
101+
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq)]
102+
#[serde(rename_all = "camelCase")]
103+
pub enum AlertType {
104+
Threshold,
105+
Anomaly(AnomalyConfig),
106+
Forecast(ForecastConfig),
107+
}
108+
109+
impl Display for AlertType {
110+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111+
match self {
112+
AlertType::Threshold => write!(f, "threshold"),
113+
AlertType::Anomaly(_) => write!(f, "anomaly"),
114+
AlertType::Forecast(_) => write!(f, "forecast"),
115+
}
116+
}
117+
}
118+
119+
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)]
120+
#[serde(rename_all = "camelCase")]
121+
pub enum AlertOperator {
122+
#[serde(rename = ">")]
123+
GreaterThan,
124+
#[serde(rename = "<")]
125+
LessThan,
126+
#[serde(rename = "=")]
127+
Equal,
128+
#[serde(rename = "!=")]
129+
NotEqual,
130+
#[serde(rename = ">=")]
131+
GreaterThanOrEqual,
132+
#[serde(rename = "<=")]
133+
LessThanOrEqual,
134+
}
135+
136+
impl Display for AlertOperator {
137+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138+
match self {
139+
AlertOperator::GreaterThan => write!(f, ">"),
140+
AlertOperator::LessThan => write!(f, "<"),
141+
AlertOperator::Equal => write!(f, "="),
142+
AlertOperator::NotEqual => write!(f, "!="),
143+
AlertOperator::GreaterThanOrEqual => write!(f, ">="),
144+
AlertOperator::LessThanOrEqual => write!(f, "<="),
145+
}
146+
}
147+
}
148+
149+
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, FromStr, PartialEq, Eq)]
150+
#[serde(rename_all = "camelCase")]
151+
pub enum WhereConfigOperator {
152+
#[serde(rename = "=")]
153+
Equal,
154+
#[serde(rename = "!=")]
155+
NotEqual,
156+
#[serde(rename = "<")]
157+
LessThan,
158+
#[serde(rename = ">")]
159+
GreaterThan,
160+
#[serde(rename = "<=")]
161+
LessThanOrEqual,
162+
#[serde(rename = ">=")]
163+
GreaterThanOrEqual,
164+
#[serde(rename = "is null")]
165+
IsNull,
166+
#[serde(rename = "is not null")]
167+
IsNotNull,
168+
#[serde(rename = "ilike")]
169+
ILike,
170+
#[serde(rename = "contains")]
171+
Contains,
172+
#[serde(rename = "begins with")]
173+
BeginsWith,
174+
#[serde(rename = "ends with")]
175+
EndsWith,
176+
#[serde(rename = "does not contain")]
177+
DoesNotContain,
178+
#[serde(rename = "does not begin with")]
179+
DoesNotBeginWith,
180+
#[serde(rename = "does not end with")]
181+
DoesNotEndWith,
182+
}
183+
184+
impl WhereConfigOperator {
185+
/// Convert the enum value to its string representation
186+
pub fn as_str(&self) -> &'static str {
187+
match self {
188+
Self::Equal => "=",
189+
Self::NotEqual => "!=",
190+
Self::LessThan => "<",
191+
Self::GreaterThan => ">",
192+
Self::LessThanOrEqual => "<=",
193+
Self::GreaterThanOrEqual => ">=",
194+
Self::IsNull => "is null",
195+
Self::IsNotNull => "is not null",
196+
Self::ILike => "ilike",
197+
Self::Contains => "contains",
198+
Self::BeginsWith => "begins with",
199+
Self::EndsWith => "ends with",
200+
Self::DoesNotContain => "does not contain",
201+
Self::DoesNotBeginWith => "does not begin with",
202+
Self::DoesNotEndWith => "does not end with",
203+
}
204+
}
205+
}
206+
207+
impl Display for WhereConfigOperator {
208+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209+
// We can reuse our as_str method to get the string representation
210+
write!(f, "{}", self.as_str())
211+
}
212+
}
213+
214+
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)]
215+
#[serde(rename_all = "camelCase")]
216+
pub enum AggregateFunction {
217+
Avg,
218+
Count,
219+
CountDistinct,
220+
Min,
221+
Max,
222+
Sum,
223+
}
224+
225+
impl Display for AggregateFunction {
226+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227+
match self {
228+
AggregateFunction::Avg => write!(f, "Avg"),
229+
AggregateFunction::Count => write!(f, "Count"),
230+
AggregateFunction::CountDistinct => write!(f, "CountDistinct"),
231+
AggregateFunction::Min => write!(f, "Min"),
232+
AggregateFunction::Max => write!(f, "Max"),
233+
AggregateFunction::Sum => write!(f, "Sum"),
234+
}
235+
}
236+
}
237+
238+
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)]
239+
#[serde(rename_all = "camelCase")]
240+
pub enum EvalConfig {
241+
RollingWindow(RollingWindow),
242+
}
243+
244+
#[derive(
245+
Debug,
246+
serde::Serialize,
247+
serde::Deserialize,
248+
Clone,
249+
Copy,
250+
PartialEq,
251+
Default,
252+
FromStr,
253+
Eq,
254+
PartialOrd,
255+
Ord,
256+
)]
257+
#[serde(rename_all = "camelCase")]
258+
pub enum AlertState {
259+
Triggered,
260+
#[default]
261+
#[serde(rename = "not-triggered")]
262+
NotTriggered,
263+
Disabled,
264+
}
265+
266+
impl Display for AlertState {
267+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
268+
match self {
269+
AlertState::Triggered => write!(f, "triggered"),
270+
AlertState::Disabled => write!(f, "disabled"),
271+
AlertState::NotTriggered => write!(f, "not-triggered"),
272+
}
273+
}
274+
}
275+
276+
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Default)]
277+
#[serde(rename_all = "camelCase")]
278+
pub enum NotificationState {
279+
#[default]
280+
Notify,
281+
/// Mute means the alert will evaluate but no notifications will be sent out
282+
///
283+
/// It is a state which can only be set manually
284+
///
285+
/// user needs to pass the timestamp or the duration (in human time) till which the alert is silenced
286+
Mute(String),
287+
}
288+
289+
impl Display for NotificationState {
290+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291+
match self {
292+
NotificationState::Notify => write!(f, "notify"),
293+
NotificationState::Mute(till_time) => {
294+
let till = match till_time.as_str() {
295+
"indefinite" => &DateTime::<Utc>::MAX_UTC.to_rfc3339(),
296+
_ => till_time,
297+
};
298+
write!(f, "{till}")
299+
}
300+
}
301+
}
302+
}

0 commit comments

Comments
 (0)