mirror of
https://github.com/prymitive/karma
synced 2026-05-05 03:16:51 +00:00
Merge pull request #129 from cloudflare/speedup-fingerprints
Speed up alert fingerprint generation
This commit is contained in:
2
Makefile
2
Makefile
@@ -88,7 +88,7 @@ endif
|
||||
|
||||
.PHONY: test
|
||||
test: lint bindata_assetfs.go
|
||||
go test -cover `go list ./... | grep -v /vendor/`
|
||||
go test -bench=. -cover `go list ./... | grep -v /vendor/`
|
||||
|
||||
.build/vendor.ok:
|
||||
go get -u github.com/kardianos/govendor
|
||||
|
||||
@@ -168,6 +168,8 @@ func (am *Alertmanager) pullAlerts(version string) error {
|
||||
for k, v := range alert.Labels {
|
||||
transform.ColorLabel(colors, k, v)
|
||||
}
|
||||
|
||||
alert.UpdateFingerprints()
|
||||
alerts = append(alerts, alert)
|
||||
|
||||
// update internal metrics
|
||||
|
||||
@@ -45,30 +45,41 @@ type Alert struct {
|
||||
Alertmanager []AlertmanagerInstance `json:"alertmanager"`
|
||||
Receiver string `json:"receiver"`
|
||||
Links map[string]string `json:"links"`
|
||||
// fingerprints are precomputed for speed
|
||||
labelsFP string `hash:"-"`
|
||||
contentFP string `hash:"-"`
|
||||
}
|
||||
|
||||
// UpdateFingerprints will generate a new set of fingerprints for this alert
|
||||
// it should be called after modifying any field that isn't tagged with hash:"-"
|
||||
func (a *Alert) UpdateFingerprints() {
|
||||
a.labelsFP = fmt.Sprintf("%x", structhash.Sha1(a.Labels, 1))
|
||||
a.contentFP = fmt.Sprintf("%x", structhash.Sha1(a, 1))
|
||||
}
|
||||
|
||||
// LabelsFingerprint is a checksum computed only from labels which should be
|
||||
// unique for every alert
|
||||
func (a Alert) LabelsFingerprint() string {
|
||||
return fmt.Sprintf("%x", structhash.Sha1(a.Labels, 1))
|
||||
func (a *Alert) LabelsFingerprint() string {
|
||||
return a.labelsFP
|
||||
}
|
||||
|
||||
// ContentFingerprint is a checksum computed from entire alert object
|
||||
func (a Alert) ContentFingerprint() string {
|
||||
return fmt.Sprintf("%x", structhash.Sha1(a, 1))
|
||||
// except some blacklisted fields tagged with hash:"-"
|
||||
func (a *Alert) ContentFingerprint() string {
|
||||
return a.contentFP
|
||||
}
|
||||
|
||||
// IsSilenced will return true if alert should be considered silenced
|
||||
func (a Alert) IsSilenced() bool {
|
||||
func (a *Alert) IsSilenced() bool {
|
||||
return (a.State == AlertStateSuppressed && len(a.SilencedBy) > 0)
|
||||
}
|
||||
|
||||
// IsInhibited will return true if alert should be considered silenced
|
||||
func (a Alert) IsInhibited() bool {
|
||||
func (a *Alert) IsInhibited() bool {
|
||||
return (a.State == AlertStateSuppressed && len(a.InhibitedBy) > 0)
|
||||
}
|
||||
|
||||
// IsActive will return true if alert is not suppressed in any way
|
||||
func (a Alert) IsActive() bool {
|
||||
func (a *Alert) IsActive() bool {
|
||||
return (a.State == AlertStateActive)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package models_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/unsee/models"
|
||||
)
|
||||
@@ -52,3 +53,49 @@ func TestAlertState(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLabelsFingerprint(b *testing.B) {
|
||||
alert := models.Alert{
|
||||
Labels: map[string]string{
|
||||
"foo1": "bar1",
|
||||
"foo1bar1": "545jjjssd",
|
||||
"foo1xxxx": "bdjjs88ff",
|
||||
"agdfdfd": "bar1",
|
||||
"fossdsf3o1": "bar11111",
|
||||
"fdfdgfdgoo1": "bar1",
|
||||
},
|
||||
}
|
||||
for n := 0; n < b.N; n++ {
|
||||
alert.LabelsFingerprint()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLabelsContent(b *testing.B) {
|
||||
alert := models.Alert{
|
||||
Annotations: map[string]string{
|
||||
"foo": "bar",
|
||||
"abc": "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit...",
|
||||
},
|
||||
Labels: map[string]string{
|
||||
"foo1": "bar1",
|
||||
"foo1bar1": "545jjjssd",
|
||||
"foo1xxxx": "bdjjs88ff",
|
||||
"agdfdfd": "bar1",
|
||||
"fossdsf3o1": "bar11111",
|
||||
"fdfdgfdgoo1": "bar1",
|
||||
},
|
||||
State: models.AlertStateActive,
|
||||
StartsAt: time.Date(2015, time.March, 10, 0, 0, 0, 0, time.UTC),
|
||||
Alertmanager: []models.AlertmanagerInstance{
|
||||
models.AlertmanagerInstance{
|
||||
Name: "default",
|
||||
URI: "http://localhost",
|
||||
State: models.AlertStateActive,
|
||||
},
|
||||
},
|
||||
}
|
||||
alert.UpdateFingerprints()
|
||||
for n := 0; n < b.N; n++ {
|
||||
alert.LabelsFingerprint()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ var alertListSortTests = []alertListSortTest{
|
||||
func TestUnseeAlertListSort(t *testing.T) {
|
||||
al := models.AlertList{}
|
||||
for _, testCase := range alertListSortTests {
|
||||
testCase.alert.UpdateFingerprints()
|
||||
al = append(al, testCase.alert)
|
||||
}
|
||||
|
||||
@@ -56,6 +57,7 @@ func TestUnseeAlertListSort(t *testing.T) {
|
||||
for i := 1; i <= iterations; i++ {
|
||||
sort.Sort(al)
|
||||
for _, testCase := range alertListSortTests {
|
||||
testCase.alert.UpdateFingerprints()
|
||||
if al[testCase.position].ContentFingerprint() != testCase.alert.ContentFingerprint() {
|
||||
failures++
|
||||
}
|
||||
@@ -120,6 +122,13 @@ var agFPTests = []agFPTest{
|
||||
|
||||
func TestAlertGroupContentFingerprint(t *testing.T) {
|
||||
for _, testCase := range agFPTests {
|
||||
alerts := models.AlertList{}
|
||||
for _, alert := range testCase.ag.Alerts {
|
||||
alert.UpdateFingerprints()
|
||||
alerts = append(alerts, alert)
|
||||
}
|
||||
sort.Sort(alerts)
|
||||
testCase.ag.Alerts = alerts
|
||||
if testCase.ag.ContentFingerprint() != testCase.fingerprint {
|
||||
t.Errorf("Invalid AlertGroup ContentFingerprint(), expected '%s', got '%s', AlertGroup: %v",
|
||||
testCase.fingerprint, testCase.ag.ContentFingerprint(), testCase.ag)
|
||||
|
||||
5
views.go
5
views.go
@@ -133,6 +133,11 @@ func alerts(c *gin.Context) {
|
||||
}
|
||||
if !validFilters || (slices.BoolInSlice(results, true) && !slices.BoolInSlice(results, false)) {
|
||||
matches++
|
||||
// we need to update fingerprints since we've modified some fields in dedup
|
||||
// and agCopy.ContentFingerprint() depends on per alert fingerprint
|
||||
// we update it here rather than in dedup since here we can apply it
|
||||
// only for alerts left after filtering
|
||||
alert.UpdateFingerprints()
|
||||
agCopy.Alerts = append(agCopy.Alerts, alert)
|
||||
|
||||
countLabel(counters, "@state", alert.State)
|
||||
|
||||
Reference in New Issue
Block a user