Compute alert content fingerprints on the fly

This will be more expensive but will simplify the code
This commit is contained in:
Łukasz Mierzwa
2017-06-25 11:01:36 -07:00
parent 6311f9edc7
commit 97e3728dab
4 changed files with 34 additions and 39 deletions

View File

@@ -128,7 +128,6 @@ func (am *Alertmanager) pullAlerts(version string) error {
uniqueAlerts[agID] = map[string]models.Alert{}
}
if _, found := uniqueAlerts[agID][fp]; !found {
alert.Fingerprint = fp
uniqueAlerts[agID][fp] = alert
}
}

View File

@@ -1,6 +1,11 @@
package models
import "time"
import (
"fmt"
"time"
"github.com/cnf/structhash"
)
// AlertStateUnprocessed means that Alertmanager notify didn't yet process it
// and AM doesn't know if alert is active or suppressed
@@ -24,7 +29,6 @@ var AlertStateList = []string{
// * Links map, it's generated from annotations if annotation value is an url
// it's pulled out of annotation map and returned under links field,
// unsee UI used this to show links differently than other annotations
// * Fingerprint, which is a sha1 of the entire alert
type Alert struct {
Annotations map[string]string `json:"annotations"`
Labels map[string]string `json:"labels"`
@@ -39,7 +43,11 @@ type Alert struct {
Receiver string `json:"receiver"`
Links map[string]string `json:"links"`
ID string `json:"-"`
Fingerprint string `json:"-"`
}
// ContentFingerprint is a checksum computed from entire alert object
func (a Alert) ContentFingerprint() string {
return fmt.Sprintf("%x", structhash.Sha1(a, 1))
}
// IsSilenced will return true if alert should be considered silenced

View File

@@ -24,7 +24,7 @@ func (a AlertList) Less(i, j int) bool {
if a[i].StartsAt.Before(a[j].StartsAt) {
return false
}
return a[i].Fingerprint < a[j].Fingerprint
return a[i].ContentFingerprint() < a[j].ContentFingerprint()
}
// AlertGroup is vanilla Alertmanager group, but alerts are flattened
@@ -43,7 +43,7 @@ type AlertGroup struct {
func (ag AlertGroup) ContentFingerprint() string {
h := sha1.New()
for _, alert := range ag.Alerts {
io.WriteString(h, alert.Fingerprint)
io.WriteString(h, alert.ContentFingerprint())
}
return fmt.Sprintf("%x", h.Sum(nil))
}

View File

@@ -9,56 +9,45 @@ import (
)
type alertListSortTest struct {
startsAt time.Time
fingerprint string
position int
alert models.Alert
position int
}
var alertListSortTests = []alertListSortTest{
alertListSortTest{
startsAt: time.Date(2017, time.January, 10, 0, 0, 0, 5, time.UTC),
fingerprint: "abcdefg",
position: 0,
alert: models.Alert{StartsAt: time.Date(2017, time.January, 10, 0, 0, 0, 5, time.UTC)},
position: 0,
},
alertListSortTest{
startsAt: time.Date(2017, time.January, 10, 0, 0, 0, 1, time.UTC),
fingerprint: "bbbbbb",
position: 1,
alert: models.Alert{StartsAt: time.Date(2017, time.January, 10, 0, 0, 0, 1, time.UTC)},
position: 1,
},
alertListSortTest{
startsAt: time.Date(2017, time.January, 10, 0, 0, 0, 0, time.UTC),
fingerprint: "cdfddfg",
position: 2,
alert: models.Alert{StartsAt: time.Date(2017, time.January, 10, 0, 0, 0, 0, time.UTC)},
position: 2,
},
alertListSortTest{
startsAt: time.Date(2015, time.March, 10, 0, 0, 0, 0, time.UTC),
fingerprint: "xlfjdf",
position: 6,
alert: models.Alert{StartsAt: time.Date(2015, time.March, 10, 0, 0, 0, 0, time.UTC)},
position: 6,
},
alertListSortTest{
startsAt: time.Date(2016, time.December, 10, 0, 0, 0, 0, time.UTC),
fingerprint: "011m",
position: 4,
alert: models.Alert{StartsAt: time.Date(2016, time.December, 10, 0, 0, 0, 0, time.UTC)},
position: 4,
},
alertListSortTest{
startsAt: time.Date(2017, time.January, 10, 0, 0, 0, 0, time.UTC),
fingerprint: "cxzfg",
position: 3,
alert: models.Alert{StartsAt: time.Date(2017, time.January, 10, 0, 0, 0, 0, time.UTC)},
position: 3,
},
alertListSortTest{
startsAt: time.Date(2015, time.March, 10, 0, 0, 0, 0, time.UTC),
fingerprint: "abv",
position: 5,
alert: models.Alert{StartsAt: time.Date(2015, time.March, 10, 0, 0, 0, 0, time.UTC)},
position: 5,
},
}
func TestUnseeAlertListSort(t *testing.T) {
al := models.AlertList{}
for _, testCase := range alertListSortTests {
a := models.Alert{}
a.StartsAt = testCase.startsAt
a.Fingerprint = testCase.fingerprint
al = append(al, a)
al = append(al, testCase.alert)
}
// repeat sort 100 times to ensure we're always sorting same way
@@ -67,7 +56,7 @@ func TestUnseeAlertListSort(t *testing.T) {
for i := 1; i <= iterations; i++ {
sort.Sort(al)
for _, testCase := range alertListSortTests {
if al[testCase.position].Fingerprint != testCase.fingerprint {
if al[testCase.position].ContentFingerprint() != testCase.alert.ContentFingerprint() {
failures++
}
}
@@ -119,14 +108,13 @@ var agFPTests = []agFPTest{
Labels: map[string]string{"foo": "bar"},
Alerts: models.AlertList{
models.Alert{
Labels: map[string]string{"foo1": "bar"},
State: models.AlertStateActive,
Fingerprint: "xxx",
Labels: map[string]string{"foo1": "bar"},
State: models.AlertStateActive,
},
},
StateCount: map[string]int{"default": 0},
},
fingerprint: "b60d121b438a380c343d5ec3c2037564b82ffef3",
fingerprint: "c4a76e2d59f7ef3d49b20da06c4a89f63fdf9e3f",
},
}