Skip to content

Commit f5cf518

Browse files
committed
feat(dispatch): expose readonly interfaces
- expose readonly interfaces for AggregationGroup and Route - move Groups logic out of dispatcher and into the api handler Signed-off-by: Siavash Safi <siavash@cloudflare.com>
1 parent 9a205b2 commit f5cf518

File tree

13 files changed

+611
-423
lines changed

13 files changed

+611
-423
lines changed

api/api.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ type Options struct {
8383
// GroupFunc returns a list of alert groups. The alerts are grouped
8484
// according to the current active configuration. Alerts returned are
8585
// filtered by the arguments provided to the function.
86-
GroupFunc func(func(*dispatch.Route) bool, func(*types.Alert, time.Time) bool) (dispatch.AlertGroups, map[model.Fingerprint][]string)
86+
GroupFunc func(func(dispatch.Route) bool, func(*types.Alert, time.Time) bool) map[dispatch.Route]map[model.Fingerprint]dispatch.AggregationGroup
8787
}
8888

8989
func (o Options) validate() error {

api/v2/api.go

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
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

7979
type (
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)
@@ -86,7 +86,7 @@ type (
8686
// NewAPI returns a new Alertmanager API v2.
8787
func 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

Comments
 (0)