mirror of
https://github.com/prometheus/alertmanager
synced 2024-12-27 08:32:15 +00:00
Implement deterministic alert group order, cleanup
This commit is contained in:
parent
dc656a44ea
commit
ede4b63a91
4
api.go
4
api.go
@ -38,7 +38,7 @@ type API struct {
|
|||||||
config string
|
config string
|
||||||
uptime time.Time
|
uptime time.Time
|
||||||
|
|
||||||
groups func() []*UIGroups
|
groups func() AlertOverview
|
||||||
|
|
||||||
// context is an indirection for testing.
|
// context is an indirection for testing.
|
||||||
context func(r *http.Request) context.Context
|
context func(r *http.Request) context.Context
|
||||||
@ -46,7 +46,7 @@ type API struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewAPI returns a new API.
|
// NewAPI returns a new API.
|
||||||
func NewAPI(alerts provider.Alerts, silences provider.Silences, gf func() []*UIGroups) *API {
|
func NewAPI(alerts provider.Alerts, silences provider.Silences, gf func() AlertOverview) *API {
|
||||||
return &API{
|
return &API{
|
||||||
context: route.Context,
|
context: route.Context,
|
||||||
alerts: alerts,
|
alerts: alerts,
|
||||||
|
60
dispatch.go
60
dispatch.go
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -59,29 +60,40 @@ func (d *Dispatcher) Run() {
|
|||||||
close(d.done)
|
close(d.done)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UIGroup is the representation of a group of alerts as provided by
|
// AlertBlock contains a list of alerts associated with a set of
|
||||||
// the API.
|
// routing options.
|
||||||
type UIGroup struct {
|
type AlertBlock struct {
|
||||||
RouteOpts *RouteOpts `json:"routeOpts"`
|
RouteOpts *RouteOpts `json:"routeOpts"`
|
||||||
Alerts []*UIAlert `json:"alerts"`
|
Alerts []*APIAlert `json:"alerts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UIGroups struct {
|
// APIAlert is the API representation of an alert, which is a regular alert
|
||||||
Labels model.LabelSet `json:"labels"`
|
// annotated with silencing and inhibition info.
|
||||||
Groups []*UIGroup `json:"groups"`
|
type APIAlert struct {
|
||||||
}
|
|
||||||
|
|
||||||
type UIAlert struct {
|
|
||||||
*model.Alert
|
*model.Alert
|
||||||
|
|
||||||
Inhibited bool `json:"inhibited"`
|
Inhibited bool `json:"inhibited"`
|
||||||
Silenced uint64 `json:"silenced,omitempty"`
|
Silenced uint64 `json:"silenced,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dispatcher) Groups() []*UIGroups {
|
// AlertGroup is a list of alert blocks grouped by the same label set.
|
||||||
var groups []*UIGroups
|
type AlertGroup struct {
|
||||||
|
Labels model.LabelSet `json:"labels"`
|
||||||
|
Blocks []*AlertBlock `json:"blocks"`
|
||||||
|
}
|
||||||
|
|
||||||
seen := map[model.Fingerprint]*UIGroups{}
|
// AlertOverview is a representation of all active alerts in the system.
|
||||||
|
type AlertOverview []*AlertGroup
|
||||||
|
|
||||||
|
func (ao AlertOverview) Swap(i, j int) { ao[i], ao[j] = ao[j], ao[i] }
|
||||||
|
func (ao AlertOverview) Less(i, j int) bool { return ao[i].Labels.Before(ao[j].Labels) }
|
||||||
|
func (ao AlertOverview) Len() int { return len(ao) }
|
||||||
|
|
||||||
|
// Groups populates an AlertOverview from the dispatcher's internal state.
|
||||||
|
func (d *Dispatcher) Groups() AlertOverview {
|
||||||
|
var overview AlertOverview
|
||||||
|
|
||||||
|
seen := map[model.Fingerprint]*AlertGroup{}
|
||||||
|
|
||||||
for route, ags := range d.aggrGroups {
|
for route, ags := range d.aggrGroups {
|
||||||
for _, ag := range ags {
|
for _, ag := range ags {
|
||||||
@ -90,39 +102,41 @@ func (d *Dispatcher) Groups() []*UIGroups {
|
|||||||
alerts = append(alerts, a)
|
alerts = append(alerts, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
uig, ok := seen[ag.labels.Fingerprint()]
|
alertGroup, ok := seen[ag.labels.Fingerprint()]
|
||||||
if !ok {
|
if !ok {
|
||||||
uig = &UIGroups{Labels: ag.labels}
|
alertGroup = &AlertGroup{Labels: ag.labels}
|
||||||
|
|
||||||
seen[ag.labels.Fingerprint()] = uig
|
seen[ag.labels.Fingerprint()] = alertGroup
|
||||||
groups = append(groups, uig)
|
overview = append(overview, alertGroup)
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
var uiAlerts []*UIAlert
|
var apiAlerts []*APIAlert
|
||||||
for _, a := range types.Alerts(alerts...) {
|
for _, a := range types.Alerts(alerts...) {
|
||||||
if a.EndsAt.Before(now) {
|
if !a.EndsAt.IsZero() && a.EndsAt.Before(now) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
sid, _ := d.marker.Silenced(a.Fingerprint())
|
sid, _ := d.marker.Silenced(a.Fingerprint())
|
||||||
|
|
||||||
uiAlerts = append(uiAlerts, &UIAlert{
|
apiAlerts = append(apiAlerts, &APIAlert{
|
||||||
Alert: a,
|
Alert: a,
|
||||||
Inhibited: d.marker.Inhibited(a.Fingerprint()),
|
Inhibited: d.marker.Inhibited(a.Fingerprint()),
|
||||||
Silenced: sid,
|
Silenced: sid,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
uig.Groups = append(uig.Groups, &UIGroup{
|
alertGroup.Blocks = append(alertGroup.Blocks, &AlertBlock{
|
||||||
RouteOpts: &route.RouteOpts,
|
RouteOpts: &route.RouteOpts,
|
||||||
Alerts: uiAlerts,
|
Alerts: apiAlerts,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return groups
|
sort.Sort(overview)
|
||||||
|
|
||||||
|
return overview
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dispatcher) run(it provider.AlertIterator) {
|
func (d *Dispatcher) run(it provider.AlertIterator) {
|
||||||
|
2
main.go
2
main.go
@ -69,7 +69,7 @@ func main() {
|
|||||||
)
|
)
|
||||||
defer disp.Stop()
|
defer disp.Stop()
|
||||||
|
|
||||||
api := NewAPI(alerts, silences, func() []*UIGroups {
|
api := NewAPI(alerts, silences, func() AlertOverview {
|
||||||
return disp.Groups()
|
return disp.Groups()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -174,9 +174,9 @@ angular.module('am.controllers').controller('AlertsCtrl',
|
|||||||
|
|
||||||
$scope.notEmpty = function(group) {
|
$scope.notEmpty = function(group) {
|
||||||
var l = 0;
|
var l = 0;
|
||||||
angular.forEach(group.groups, function(g) {
|
angular.forEach(group.blocks, function(blk) {
|
||||||
if ($scope.receiver.indexOf(g.routeOpts.receiver) >= 0) {
|
if ($scope.receivers.indexOf(blk.routeOpts.receiver) >= 0) {
|
||||||
l += g.alerts.length;
|
l += blk.alerts.length || 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -190,9 +190,9 @@ angular.module('am.controllers').controller('AlertsCtrl',
|
|||||||
|
|
||||||
$scope.allReceivers = [];
|
$scope.allReceivers = [];
|
||||||
angular.forEach($scope.groups, function(group) {
|
angular.forEach($scope.groups, function(group) {
|
||||||
angular.forEach(group.groups, function(g) {
|
angular.forEach(group.blocks, function(blk) {
|
||||||
if ($scope.allReceivers.indexOf(g.routeOpts.receiver) < 0) {
|
if ($scope.allReceivers.indexOf(blk.routeOpts.receiver) < 0) {
|
||||||
$scope.allReceivers.push(g.routeOpts.receiver);
|
$scope.allReceivers.push(blk.routeOpts.receiver);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
@ -13,9 +13,9 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ng-repeat="g in group.groups">
|
<div ng-repeat="blk in group.blocks">
|
||||||
<div ng-show="receivers.indexOf(g.routeOpts.receiver) >= 0" ng-show"g.alerts">
|
<div ng-show="receivers.indexOf(blk.routeOpts.receiver) >= 0" ng-show"blk.alerts">
|
||||||
<div ng-repeat="a in g.alerts">
|
<div ng-repeat="a in blk.alerts">
|
||||||
<alert class="list-item" alert="a" group="group.labels"></alert>
|
<alert class="list-item" alert="a" group="group.labels"></alert>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user