mirror of
https://github.com/prymitive/karma
synced 2026-05-17 04:16:42 +00:00
Compute alert content fingerprints on the fly
This will be more expensive but will simplify the code
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user