Merge pull request #171 from cloudflare/include-labels

Implement KEEP_LABELS option
This commit is contained in:
Łukasz Mierzwa
2017-08-11 12:33:38 -07:00
committed by GitHub
7 changed files with 97 additions and 5 deletions
+15
View File
@@ -281,6 +281,21 @@ This option can also be set using `-jira.regex` flag. Example:
This variable is optional and default is not set (no rule will be applied).
#### KEEP_LABELS
List of label names to show on the UI, all other labels will be stripped.
This allows to hide all labels except selected few that are useful on the
alert dashboard. Accepts space separated list of label names. Examples:
KEEP_LABELS=instance
KEEP_LABELS="host severity"
This option can also be set using `-keep.labels` flag. Example:
$ unsee -keep.labels "host severity"
This variable is optional and default is not set (all labels will be shown).
#### PORT
HTTP port to listen on. Example:
+4
View File
@@ -3,8 +3,10 @@ package alertmanager
import (
"sort"
"github.com/cloudflare/unsee/internal/config"
"github.com/cloudflare/unsee/internal/models"
"github.com/cloudflare/unsee/internal/slices"
"github.com/cloudflare/unsee/internal/transform"
)
// DedupAlerts will collect alert groups from all defined Alertmanager
@@ -61,6 +63,8 @@ func DedupAlerts() []models.AlertGroup {
ag := models.AlertGroup(agList[0])
ag.Alerts = models.AlertList{}
for _, alert := range alerts {
// strip labels user doesn't want to see in the UI
alert.Labels = transform.StripLables(config.Config.KeepLabels, config.Config.StripLabels, alert.Labels)
// calculate final alert state based on the most important value found
// in the list of states from all instances
alertLFP := alert.LabelsFingerprint()
+30
View File
@@ -35,9 +35,39 @@ func TestDedupAlerts(t *testing.T) {
t.Error(err)
}
alertGroups := alertmanager.DedupAlerts()
if len(alertGroups) != 10 {
t.Errorf("Expected %d alert groups, got %d", 10, len(alertGroups))
}
totalAlerts := 0
for _, ag := range alertGroups {
totalAlerts += len(ag.Alerts)
}
if totalAlerts != 24 {
t.Errorf("Expected %d total alerts, got %d", 24, totalAlerts)
}
}
func TestDedupAlertsWithoutLabels(t *testing.T) {
config.Config.KeepLabels = []string{"xyz"}
if err := pullAlerts(); err != nil {
t.Error(err)
}
alertGroups := alertmanager.DedupAlerts()
config.Config.KeepLabels = []string{}
if len(alertGroups) != 10 {
t.Errorf("Expected %d alert groups, got %d", 10, len(alertGroups))
}
totalAlerts := 0
for _, ag := range alertGroups {
totalAlerts += len(ag.Alerts)
}
if totalAlerts != 24 {
t.Errorf("Expected %d total alerts, got %d", 24, totalAlerts)
}
}
func TestDedupAutocomplete(t *testing.T) {
-2
View File
@@ -6,7 +6,6 @@ import (
"sync"
"time"
"github.com/cloudflare/unsee/internal/config"
"github.com/cloudflare/unsee/internal/mapper"
"github.com/cloudflare/unsee/internal/models"
"github.com/cloudflare/unsee/internal/transform"
@@ -174,7 +173,6 @@ func (am *Alertmanager) pullAlerts(version string) error {
}
alert.Annotations, alert.Links = transform.DetectLinks(alert.Annotations)
alert.Labels = transform.StripLables(config.Config.StripLabels, alert.Labels)
transform.ColorLabel(colors, "@receiver", alert.Receiver)
for k, v := range alert.Labels {
+1
View File
@@ -36,6 +36,7 @@ type configEnvs struct {
SentryDSN string `envconfig:"SENTRY_DSN" help:"Sentry DSN for Go exceptions"`
SentryPublicDSN string `envconfig:"SENTRY_PUBLIC_DSN" help:"Sentry DSN for javascript exceptions"`
StripLabels spaceSeparatedList `envconfig:"STRIP_LABELS" help:"List of labels to ignore"`
KeepLabels spaceSeparatedList `envconfig:"KEEP_LABELS" help:"List of labels to keep, all other labels will be stripped"`
WebPrefix string `envconfig:"WEB_PREFIX" default:"/" help:"URL prefix"`
}
+8 -2
View File
@@ -9,10 +9,16 @@ import (
// StripLables allows filtering out some labels from alerts
// it takes the list of label keys to ignore and alert label map
// it will return label map without labels found on the ignore list
func StripLables(ignoredLabels []string, sourceLabels map[string]string) map[string]string {
func StripLables(keptLabels, ignoredLabels []string, sourceLabels map[string]string) map[string]string {
// empty keep list means keep everything by default
keepAll := len(keptLabels) == 0
labels := map[string]string{}
for label, value := range sourceLabels {
if !slices.StringInSlice(ignoredLabels, label) {
// is explicitly marked to be kept
inKeep := slices.StringInSlice(keptLabels, label)
// is explicitly marked to be stripped
inStrip := slices.StringInSlice(ignoredLabels, label)
if (keepAll || inKeep) && !inStrip {
// strip leading and trailung space in label value
// this is to normalize values in case space is added by Alertmanager rules
labels[label] = strings.TrimSpace(value)
+39 -1
View File
@@ -9,6 +9,7 @@ import (
type stripTest struct {
strip []string
keep []string
before map[string]string
after map[string]string
}
@@ -16,6 +17,7 @@ type stripTest struct {
var stripTests = []stripTest{
stripTest{
strip: []string{"env"},
keep: []string{},
before: map[string]string{
"host": "localhost",
"env": "production",
@@ -28,6 +30,7 @@ var stripTests = []stripTest{
},
stripTest{
strip: []string{"server"},
keep: []string{},
before: map[string]string{
"host": "localhost",
"env": "production",
@@ -41,6 +44,7 @@ var stripTests = []stripTest{
},
stripTest{
strip: []string{},
keep: []string{},
before: map[string]string{
"host": "localhost",
"env": "production",
@@ -54,16 +58,50 @@ var stripTests = []stripTest{
},
stripTest{
strip: []string{"host"},
keep: []string{},
before: map[string]string{
"host": "localhost",
},
after: map[string]string{},
},
stripTest{
strip: []string{},
keep: []string{"env"},
before: map[string]string{
"host": "localhost",
"env": "production",
"level": "info",
},
after: map[string]string{
"env": "production",
},
},
stripTest{
strip: []string{"env"},
keep: []string{"host"},
before: map[string]string{
"host": "localhost",
"env": "production",
"level": "info",
},
after: map[string]string{
"host": "localhost",
},
},
stripTest{
strip: []string{},
keep: []string{"env"},
before: map[string]string{
"host": "localhost",
"level": "info",
},
after: map[string]string{},
},
}
func TestStripLables(t *testing.T) {
for _, testCase := range stripTests {
labels := transform.StripLables(testCase.strip, testCase.before)
labels := transform.StripLables(testCase.keep, testCase.strip, testCase.before)
if !reflect.DeepEqual(labels, testCase.after) {
t.Errorf("StripLables failed, expected %v, got %v", testCase.after, labels)
}