19
19
use actix_web:: http:: header:: ContentType ;
20
20
use arrow_schema:: { DataType , Schema } ;
21
21
use async_trait:: async_trait;
22
- use chrono:: Utc ;
22
+ use chrono:: { DateTime , Utc } ;
23
23
use datafusion:: logical_expr:: { LogicalPlan , Projection } ;
24
24
use datafusion:: sql:: sqlparser:: parser:: ParserError ;
25
25
use derive_more:: FromStrError ;
@@ -197,6 +197,14 @@ pub enum AlertType {
197
197
Threshold ,
198
198
}
199
199
200
+ impl Display for AlertType {
201
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
202
+ match self {
203
+ AlertType :: Threshold => write ! ( f, "threshold" ) ,
204
+ }
205
+ }
206
+ }
207
+
200
208
#[ derive( Debug , serde:: Serialize , serde:: Deserialize , Clone ) ]
201
209
#[ serde( rename_all = "camelCase" ) ]
202
210
pub enum AlertOperator {
@@ -528,6 +536,7 @@ pub struct AlertRequest {
528
536
pub threshold_config : ThresholdConfig ,
529
537
pub eval_config : EvalConfig ,
530
538
pub targets : Vec < Ulid > ,
539
+ pub tags : Option < Vec < String > > ,
531
540
}
532
541
533
542
impl AlertRequest {
@@ -536,17 +545,21 @@ impl AlertRequest {
536
545
for id in & self . targets {
537
546
TARGETS . get_target_by_id ( id) . await ?;
538
547
}
548
+ let datasets = resolve_stream_names ( & self . query ) ?;
539
549
let config = AlertConfig {
540
550
version : AlertVerison :: from ( CURRENT_ALERTS_VERSION ) ,
541
551
id : Ulid :: new ( ) ,
542
552
severity : self . severity ,
543
553
title : self . title ,
544
554
query : self . query ,
555
+ datasets,
545
556
alert_type : self . alert_type ,
546
557
threshold_config : self . threshold_config ,
547
558
eval_config : self . eval_config ,
548
559
targets : self . targets ,
549
560
state : AlertState :: default ( ) ,
561
+ created : Utc :: now ( ) ,
562
+ tags : self . tags ,
550
563
} ;
551
564
Ok ( config)
552
565
}
@@ -561,13 +574,16 @@ pub struct AlertConfig {
561
574
pub severity : Severity ,
562
575
pub title : String ,
563
576
pub query : String ,
577
+ pub datasets : Vec < String > ,
564
578
pub alert_type : AlertType ,
565
579
pub threshold_config : ThresholdConfig ,
566
580
pub eval_config : EvalConfig ,
567
581
pub targets : Vec < Ulid > ,
568
582
// for new alerts, state should be resolved
569
583
#[ serde( default ) ]
570
584
pub state : AlertState ,
585
+ pub created : DateTime < Utc > ,
586
+ pub tags : Option < Vec < String > > ,
571
587
}
572
588
573
589
impl AlertConfig {
@@ -580,6 +596,7 @@ impl AlertConfig {
580
596
let alert_info = format ! ( "Alert '{}' (ID: {})" , basic_fields. title, basic_fields. id) ;
581
597
582
598
let query = Self :: build_query_from_v1 ( alert_json, & alert_info) . await ?;
599
+ let datasets = resolve_stream_names ( & query) ?;
583
600
let threshold_config = Self :: extract_threshold_config ( alert_json, & alert_info) ?;
584
601
let eval_config = Self :: extract_eval_config ( alert_json, & alert_info) ?;
585
602
let targets = Self :: extract_targets ( alert_json, & alert_info) ?;
@@ -592,11 +609,14 @@ impl AlertConfig {
592
609
severity : basic_fields. severity ,
593
610
title : basic_fields. title ,
594
611
query,
612
+ datasets,
595
613
alert_type : AlertType :: Threshold ,
596
614
threshold_config,
597
615
eval_config,
598
616
targets,
599
617
state,
618
+ created : Utc :: now ( ) ,
619
+ tags : None ,
600
620
} ;
601
621
602
622
// Save the migrated alert back to storage
@@ -1183,6 +1203,65 @@ impl AlertConfig {
1183
1203
}
1184
1204
Ok ( ( ) )
1185
1205
}
1206
+
1207
+ /// create a summary of the dashboard
1208
+ /// used for listing dashboards
1209
+ pub fn to_summary ( & self ) -> serde_json:: Map < String , serde_json:: Value > {
1210
+ let mut map = serde_json:: Map :: new ( ) ;
1211
+
1212
+ map. insert (
1213
+ "title" . to_string ( ) ,
1214
+ serde_json:: Value :: String ( self . title . clone ( ) ) ,
1215
+ ) ;
1216
+
1217
+ map. insert (
1218
+ "created" . to_string ( ) ,
1219
+ serde_json:: Value :: String ( self . created . to_string ( ) ) ,
1220
+ ) ;
1221
+
1222
+ map. insert (
1223
+ "alertType" . to_string ( ) ,
1224
+ serde_json:: Value :: String ( self . alert_type . to_string ( ) ) ,
1225
+ ) ;
1226
+
1227
+ map. insert (
1228
+ "id" . to_string ( ) ,
1229
+ serde_json:: Value :: String ( self . id . to_string ( ) ) ,
1230
+ ) ;
1231
+
1232
+ map. insert (
1233
+ "severity" . to_string ( ) ,
1234
+ serde_json:: Value :: String ( self . severity . to_string ( ) ) ,
1235
+ ) ;
1236
+
1237
+ map. insert (
1238
+ "state" . to_string ( ) ,
1239
+ serde_json:: Value :: String ( self . state . to_string ( ) ) ,
1240
+ ) ;
1241
+
1242
+ if let Some ( tags) = & self . tags {
1243
+ map. insert (
1244
+ "tags" . to_string ( ) ,
1245
+ serde_json:: Value :: Array (
1246
+ tags. iter ( )
1247
+ . map ( |tag| serde_json:: Value :: String ( tag. clone ( ) ) )
1248
+ . collect ( ) ,
1249
+ ) ,
1250
+ ) ;
1251
+ }
1252
+
1253
+ map. insert (
1254
+ "datasets" . to_string ( ) ,
1255
+ serde_json:: Value :: Array (
1256
+ self . datasets
1257
+ . iter ( )
1258
+ . map ( |dataset| serde_json:: Value :: String ( dataset. clone ( ) ) )
1259
+ . collect ( ) ,
1260
+ ) ,
1261
+ ) ;
1262
+
1263
+ map
1264
+ }
1186
1265
}
1187
1266
1188
1267
#[ derive( Debug , thiserror:: Error ) ]
@@ -1221,6 +1300,8 @@ pub enum AlertError {
1221
1300
ParserError ( #[ from] ParserError ) ,
1222
1301
#[ error( "Invalid alert query" ) ]
1223
1302
InvalidAlertQuery ,
1303
+ #[ error( "Invalid query parameter" ) ]
1304
+ InvalidQueryParameter ,
1224
1305
}
1225
1306
1226
1307
impl actix_web:: ResponseError for AlertError {
@@ -1243,6 +1324,7 @@ impl actix_web::ResponseError for AlertError {
1243
1324
Self :: TargetInUse => StatusCode :: CONFLICT ,
1244
1325
Self :: ParserError ( _) => StatusCode :: BAD_REQUEST ,
1245
1326
Self :: InvalidAlertQuery => StatusCode :: BAD_REQUEST ,
1327
+ Self :: InvalidQueryParameter => StatusCode :: BAD_REQUEST ,
1246
1328
}
1247
1329
}
1248
1330
@@ -1350,6 +1432,7 @@ impl Alerts {
1350
1432
pub async fn list_alerts_for_user (
1351
1433
& self ,
1352
1434
session : SessionKey ,
1435
+ tags : Vec < String > ,
1353
1436
) -> Result < Vec < AlertConfig > , AlertError > {
1354
1437
let mut alerts: Vec < AlertConfig > = Vec :: new ( ) ;
1355
1438
for ( _, alert) in self . alerts . read ( ) . await . iter ( ) {
@@ -1358,6 +1441,17 @@ impl Alerts {
1358
1441
alerts. push ( alert. to_owned ( ) ) ;
1359
1442
}
1360
1443
}
1444
+ if tags. is_empty ( ) {
1445
+ return Ok ( alerts) ;
1446
+ }
1447
+ // filter alerts based on tags
1448
+ alerts. retain ( |alert| {
1449
+ if let Some ( alert_tags) = & alert. tags {
1450
+ alert_tags. iter ( ) . any ( |tag| tags. contains ( tag) )
1451
+ } else {
1452
+ false
1453
+ }
1454
+ } ) ;
1361
1455
1362
1456
Ok ( alerts)
1363
1457
}
@@ -1456,6 +1550,20 @@ impl Alerts {
1456
1550
1457
1551
Ok ( ( ) )
1458
1552
}
1553
+
1554
+ /// List tags from all alerts
1555
+ /// This function returns a list of unique tags from all alerts
1556
+ pub async fn list_tags ( & self ) -> Vec < String > {
1557
+ let alerts = self . alerts . read ( ) . await ;
1558
+ let mut tags = alerts
1559
+ . iter ( )
1560
+ . filter_map ( |( _, alert) | alert. tags . as_ref ( ) )
1561
+ . flat_map ( |t| t. iter ( ) . cloned ( ) )
1562
+ . collect :: < Vec < String > > ( ) ;
1563
+ tags. sort ( ) ;
1564
+ tags. dedup ( ) ;
1565
+ tags
1566
+ }
1459
1567
}
1460
1568
1461
1569
#[ derive( Debug , Serialize ) ]
0 commit comments