1- // Copyright 2018 Prometheus Team
1+ // Copyright The Prometheus Authors
22// Licensed under the Apache License, Version 2.0 (the "License");
33// you may not use this file except in compliance with the License.
44// You may obtain a copy of the License at
@@ -57,7 +57,7 @@ type API struct {
5757 peer cluster.ClusterPeer
5858 silences * silence.Silences
5959 alerts provider.Alerts
60- alertGroups groupsFn
60+ dispatchGroups dispatchGroupsFn
6161 getAlertStatus getAlertStatusFn
6262 groupMutedFunc groupMutedFunc
6363 uptime time.Time
@@ -67,7 +67,7 @@ type API struct {
6767 // resolveTimeout represents the default resolve timeout that an alert is
6868 // assigned if no end time is specified.
6969 alertmanagerConfig * config.Config
70- route * dispatch.Route
70+ route dispatch.Route
7171 setAlertStatus setAlertStatusFn
7272
7373 logger * slog.Logger
@@ -77,7 +77,7 @@ type API struct {
7777}
7878
7979type (
80- groupsFn func (func (* dispatch.Route ) bool , func (* types.Alert , time.Time ) bool ) ( dispatch.AlertGroups , map [prometheus_model.Fingerprint ][] string )
80+ dispatchGroupsFn func (func (dispatch.Route ) bool , func (* types.Alert , time.Time ) bool ) map [ dispatch.Route ] map [prometheus_model.Fingerprint ]dispatch. AggregationGroup
8181 groupMutedFunc func (routeID , groupKey string ) ([]string , bool )
8282 getAlertStatusFn func (prometheus_model.Fingerprint ) types.AlertStatus
8383 setAlertStatusFn func (prometheus_model.LabelSet )
8686// NewAPI returns a new Alertmanager API v2.
8787func NewAPI (
8888 alerts provider.Alerts ,
89- gf groupsFn ,
89+ dgf dispatchGroupsFn ,
9090 asf getAlertStatusFn ,
9191 gmf groupMutedFunc ,
9292 silences * silence.Silences ,
@@ -97,7 +97,7 @@ func NewAPI(
9797 api := API {
9898 alerts : alerts ,
9999 getAlertStatus : asf ,
100- alertGroups : gf ,
100+ dispatchGroups : dgf ,
101101 groupMutedFunc : gmf ,
102102 peer : peer ,
103103 silences : silences ,
@@ -282,7 +282,7 @@ func (api *API) getAlertsHandler(params alert_ops.GetAlertsParams) middleware.Re
282282 routes := api .route .Match (a .Labels )
283283 receivers := make ([]string , 0 , len (routes ))
284284 for _ , r := range routes {
285- receivers = append (receivers , r .RouteOpts .Receiver )
285+ receivers = append (receivers , r .Options () .Receiver )
286286 }
287287
288288 if receiverFilter != nil && ! receiversMatchFilter (receivers , receiverFilter ) {
@@ -394,9 +394,9 @@ func (api *API) getAlertGroupsHandler(params alertgroup_ops.GetAlertGroupsParams
394394 }
395395 }
396396
397- rf := func (receiverFilter * regexp.Regexp ) func (r * dispatch.Route ) bool {
398- return func (r * dispatch.Route ) bool {
399- receiver := r .RouteOpts .Receiver
397+ rf := func (receiverFilter * regexp.Regexp ) func (r dispatch.Route ) bool {
398+ return func (r dispatch.Route ) bool {
399+ receiver := r .Options () .Receiver
400400 if receiverFilter != nil && ! receiverFilter .MatchString (receiver ) {
401401 return false
402402 }
@@ -405,11 +405,68 @@ func (api *API) getAlertGroupsHandler(params alertgroup_ops.GetAlertGroupsParams
405405 }(receiverFilter )
406406
407407 af := api .alertFilter (matchers , * params .Silenced , * params .Inhibited , * params .Active )
408- alertGroups , allReceivers := api .alertGroups (rf , af )
408+ dispatchGroups := api .dispatchGroups (rf , af )
409409
410- res := make (open_api_models.AlertGroups , 0 , len (alertGroups ))
410+ groups := AlertGroups {}
411+ // Keep a list of receivers for an alert to prevent checking each alert
412+ // again against all routes. The alert has already matched against this
413+ // route on ingestion.
414+ receivers := map [prometheus_model.Fingerprint ][]string {}
411415
412- for _ , alertGroup := range alertGroups {
416+ now := time .Now ()
417+ for route , ags := range dispatchGroups {
418+ if ! rf (route ) {
419+ continue
420+ }
421+
422+ for _ , ag := range ags {
423+ receiver := route .Options ().Receiver
424+ alertGroup := & AlertGroup {
425+ Labels : ag .Labels (),
426+ Receiver : receiver ,
427+ GroupKey : ag .GroupKey (),
428+ RouteID : ag .RouteID (),
429+ }
430+
431+ alerts := ag .Alerts ()
432+ filteredAlerts := make ([]* types.Alert , 0 , len (alerts ))
433+ for _ , a := range alerts {
434+ if ! af (a , now ) {
435+ continue
436+ }
437+
438+ fp := a .Fingerprint ()
439+ if r , ok := receivers [fp ]; ok {
440+ // Receivers slice already exists. Add
441+ // the current receiver to the slice.
442+ receivers [fp ] = append (r , receiver )
443+ } else {
444+ // First time we've seen this alert fingerprint.
445+ // Initialize a new receivers slice.
446+ receivers [fp ] = []string {receiver }
447+ }
448+
449+ filteredAlerts = append (filteredAlerts , a )
450+ }
451+ if len (filteredAlerts ) == 0 {
452+ continue
453+ }
454+ alertGroup .Alerts = filteredAlerts
455+
456+ groups = append (groups , alertGroup )
457+ }
458+ }
459+ sort .Sort (groups )
460+ for i := range groups {
461+ sort .Sort (groups [i ].Alerts )
462+ }
463+ for i := range receivers {
464+ sort .Strings (receivers [i ])
465+ }
466+
467+ res := make (open_api_models.AlertGroups , 0 , len (groups ))
468+
469+ for _ , alertGroup := range groups {
413470 mutedBy , isMuted := api .groupMutedFunc (alertGroup .RouteID , alertGroup .GroupKey )
414471 if ! * params .Muted && isMuted {
415472 continue
@@ -423,7 +480,7 @@ func (api *API) getAlertGroupsHandler(params alertgroup_ops.GetAlertGroupsParams
423480
424481 for _ , alert := range alertGroup .Alerts {
425482 fp := alert .Fingerprint ()
426- receivers := allReceivers [fp ]
483+ receivers := receivers [fp ]
427484 status := api .getAlertStatus (fp )
428485 apiAlert := AlertToOpenAPIAlert (alert , status , receivers , mutedBy )
429486 ag .Alerts = append (ag .Alerts , apiAlert )
0 commit comments