feat(backend): allow setting custom colors for labels

This allows to have a user defined color (rgb or hex) for label values configured in the config file
This commit is contained in:
Łukasz Mierzwa
2019-02-04 13:18:47 +00:00
parent a92a587811
commit 9e4abbd42b
7 changed files with 81 additions and 13 deletions

1
go.mod
View File

@@ -25,6 +25,7 @@ require (
github.com/spf13/pflag v1.0.3
github.com/spf13/viper v1.3.1
github.com/terinjokes/bakelite v0.2.0 // indirect
gopkg.in/go-playground/colors.v1 v1.2.0
gopkg.in/jarcoal/httpmock.v1 v1.0.0-20181117152235-275e9df93516
gopkg.in/yaml.v2 v2.2.2
)

2
go.sum
View File

@@ -275,6 +275,8 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/colors.v1 v1.2.0 h1:SPweMUve+ywPrfwao+UvfD5Ah78aOLUkT5RlJiZn52c=
gopkg.in/go-playground/colors.v1 v1.2.0/go.mod h1:AvbqcMpNXVl5gBrM20jBm3VjjKBbH/kI5UnqjU7lxFI=
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/jarcoal/httpmock.v1 v1.0.0-20181117152235-275e9df93516 h1:H6trpavCIuipdInWrab8l34Mf+GGVfphniHostMdMaQ=

View File

@@ -137,6 +137,7 @@ func (config *configSchema) Read() {
config.Custom.JS = v.GetString("custom.js")
config.Debug = v.GetBool("debug")
config.Filters.Default = v.GetStringSlice("filters.default")
config.Labels.Color.Custom = map[string]map[string]string{}
config.Labels.Color.Static = v.GetStringSlice("labels.color.static")
config.Labels.Color.Unique = v.GetStringSlice("labels.color.unique")
config.Labels.Keep = v.GetStringSlice("labels.keep")
@@ -161,6 +162,11 @@ func (config *configSchema) Read() {
log.Fatal(err)
}
err = v.UnmarshalKey("labels.color.custom", &config.Labels.Color.Custom)
if err != nil {
log.Fatal(err)
}
// accept single Alertmanager server from flag/env if nothing is set yet
if len(config.Alertmanager.Servers) == 0 && v.GetString("alertmanager.uri") != "" {
log.Info("Using simple config with a single Alertmanager server")

View File

@@ -90,6 +90,7 @@ labels:
- abc
- def
color:
custom: {}
static:
- a
- bb

View File

@@ -47,6 +47,7 @@ type configSchema struct {
Keep []string
Strip []string
Color struct {
Custom map[string]map[string]string
Static []string
Unique []string
}

View File

@@ -9,22 +9,23 @@ import (
)
type colorTest struct {
config []string
labels map[string]string
colors map[string]string
uniqueLabels []string
customLabels map[string]map[string]string
labels map[string]string
colors map[string]string
}
var colorTests = []colorTest{
colorTest{
{
labels: map[string]string{},
},
colorTest{
{
labels: map[string]string{
"node": "localhost",
},
},
colorTest{
config: []string{"node"},
{
uniqueLabels: []string{"node"},
labels: map[string]string{
"node": "localhost",
},
@@ -32,8 +33,8 @@ var colorTests = []colorTest{
"node": "localhost",
},
},
colorTest{
config: []string{"node", "instance"},
{
uniqueLabels: []string{"node", "instance"},
labels: map[string]string{
"node": "instance",
"env": "instance",
@@ -45,8 +46,8 @@ var colorTests = []colorTest{
"instance": "server1",
},
},
colorTest{
config: []string{"job", "node", "instance"},
{
uniqueLabels: []string{"job", "node", "instance"},
labels: map[string]string{
"job": "node_ping",
},
@@ -54,11 +55,32 @@ var colorTests = []colorTest{
"job": "node_ping",
},
},
{
customLabels: map[string]map[string]string{
"node": map[string]string{"localhost": "#fff"},
},
labels: map[string]string{
"node": "localhost",
},
colors: map[string]string{
"node": "localhost",
},
},
{
customLabels: map[string]map[string]string{
"node": map[string]string{"localhost": "not a color"},
},
labels: map[string]string{
"node": "localhost",
},
colors: map[string]string{},
},
}
func TestColorLabel(t *testing.T) {
for _, testCase := range colorTests {
config.Config.Labels.Color.Unique = testCase.config
config.Config.Labels.Color.Unique = testCase.uniqueLabels
config.Config.Labels.Color.Custom = testCase.customLabels
colorStore := models.LabelsColorMap{}
for key, value := range testCase.labels {
transform.ColorLabel(colorStore, key, value)

View File

@@ -10,6 +10,7 @@ import (
"github.com/prymitive/karma/internal/slices"
"github.com/hansrodtang/randomcolor"
plcolors "gopkg.in/go-playground/colors.v1"
log "github.com/sirupsen/logrus"
)
@@ -34,10 +35,44 @@ func labelToSeed(key string, val string) int64 {
return seed
}
func rgbToBrightness(r, g, b uint8) int32 {
return ((int32(r) * 299) + (int32(g) * 587) + (int32(b) * 114)) / 1000
}
// ColorLabel update karmaColorMap object with a color object generated
// from label key and value passed here
// It's used to generate unique colors for configured labels
func ColorLabel(colorStore models.LabelsColorMap, key string, val string) {
// first handle custom colors
_, ok := config.Config.Labels.Color.Custom[key]
if ok {
c, ol := config.Config.Labels.Color.Custom[key][val]
if ol {
color, err := plcolors.Parse(c)
if err != nil {
log.Warningf("Failed to parse custom color for %s=%s: %s", key, val, err)
return
}
rgb := color.ToRGB()
bc := models.Color{
Red: rgb.R,
Green: rgb.G,
Blue: rgb.B,
Alpha: 255,
}
brightness := rgbToBrightness(bc.Red, bc.Green, bc.Blue)
if _, found := colorStore[key]; !found {
colorStore[key] = make(map[string]models.LabelColors)
}
colorStore[key][val] = models.LabelColors{
Brightness: brightness,
Background: bc,
}
}
return
}
// if no custom color is found then generate unique colors if needed
if slices.StringInSlice(config.Config.Labels.Color.Unique, key) {
if _, found := colorStore[key]; !found {
colorStore[key] = make(map[string]models.LabelColors)
@@ -54,7 +89,7 @@ func ColorLabel(colorStore models.LabelsColorMap, key string, val string) {
}
// check if color is bright or dark and pick the right background
// uses https://www.w3.org/WAI/ER/WD-AERT/#color-contrast method
brightness := ((int32(bc.Red) * 299) + (int32(bc.Green) * 587) + (int32(bc.Blue) * 114)) / 1000
brightness := rgbToBrightness(bc.Red, bc.Green, bc.Blue)
colorStore[key][val] = models.LabelColors{
Brightness: brightness,
Background: bc,