mirror of
https://github.com/prymitive/karma
synced 2026-05-05 03:16:51 +00:00
Merge pull request #540 from prymitive/wildcard-colors
feat(api): allow using wildcards with custom colors
This commit is contained in:
@@ -137,7 +137,7 @@ class AlwaysOnAlert(AlertGenerator):
|
||||
def _gen(size, cluster):
|
||||
return [newAlert(
|
||||
self._labels(instance="server{}".format(i), cluster=cluster,
|
||||
severity="info"),
|
||||
severity="info", job="node_exporter", region="US"),
|
||||
self._annotations(
|
||||
summary="Silence this alert, it's always firing")
|
||||
) for i in xrange(1, size)]
|
||||
@@ -153,7 +153,8 @@ class RandomInstances(AlertGenerator):
|
||||
return [
|
||||
newAlert(
|
||||
self._labels(instance="server{}".format(i), cluster="staging",
|
||||
severity="warning"),
|
||||
severity="warning", job="node_exporter",
|
||||
region="US"),
|
||||
self._annotations(
|
||||
dashboard="https://www.google.com/search?q="
|
||||
"server{}".format(i))
|
||||
@@ -173,7 +174,8 @@ class RandomName(AlertGenerator):
|
||||
newAlert(
|
||||
self._labels(alertname="Alert Nr {}".format(throw),
|
||||
instance="server{}".format(i),
|
||||
cluster="dev", severity="info"),
|
||||
cluster="dev", severity="info",
|
||||
job="random_exporter", region="EU"),
|
||||
self._annotations(
|
||||
summary="This is a random alert",
|
||||
dashboard="https://www.google.com/search?q="
|
||||
@@ -194,7 +196,8 @@ class LowChance(AlertGenerator):
|
||||
return [
|
||||
newAlert(
|
||||
self._labels(instance="server{}".format(i), cluster="dev",
|
||||
severity="critical"),
|
||||
severity="critical", job="random_exporter",
|
||||
region="EU"),
|
||||
self._annotations()
|
||||
) for i in xrange(0, 3)
|
||||
]
|
||||
@@ -208,7 +211,8 @@ class TimeAnnotation(AlertGenerator):
|
||||
def alerts(self):
|
||||
return [
|
||||
newAlert(self._labels(instance="server1", cluster="prod",
|
||||
severity="warning"),
|
||||
severity="warning", job="ntp_exporter",
|
||||
region="AP"),
|
||||
self._annotations(time=str(int(time.time())))
|
||||
)
|
||||
]
|
||||
@@ -226,7 +230,8 @@ class DiskFreeLowAlert(AlertGenerator):
|
||||
newAlert(self._labels(instance="server{}".format(i),
|
||||
cluster="prod",
|
||||
device="/dev/sda{}".format(i),
|
||||
mount_point="/disk", severity="critical"),
|
||||
mount_point="/disk", severity="critical",
|
||||
job="node_exporter", region="AP"),
|
||||
self._annotations(
|
||||
summary="Only {}% free space left on /disk".format(
|
||||
spaceFree),
|
||||
@@ -243,7 +248,8 @@ class SilencedAlert(AlertGenerator):
|
||||
def alerts(self):
|
||||
return [
|
||||
newAlert(self._labels(instance="server1", cluster="prod",
|
||||
severity="info"),
|
||||
severity="info", job="mysql_exporter",
|
||||
region="SA"),
|
||||
self._annotations(
|
||||
alertReference="https://www."
|
||||
"youtube.com/watch?v=dQw4w9WgXcQ")
|
||||
@@ -279,7 +285,8 @@ class MixedAlerts(AlertGenerator):
|
||||
def alerts(self):
|
||||
return [
|
||||
newAlert(self._labels(instance="server{}".format(i), cluster="prod",
|
||||
severity="warning"),
|
||||
severity="warning", job="node_exporter",
|
||||
region="SA"),
|
||||
self._annotations(
|
||||
alertReference="https://www."
|
||||
"youtube.com/watch?v=dQw4w9WgXcQ")
|
||||
@@ -310,7 +317,8 @@ class LongNameAlerts(AlertGenerator):
|
||||
def _gen(size, cluster):
|
||||
return [newAlert(
|
||||
self._labels(instance="server{}".format(i), cluster=cluster,
|
||||
severity="info"),
|
||||
severity="info", job="textfile_exporter",
|
||||
region="CN"),
|
||||
self._annotations(
|
||||
verylong="Lorem ipsum dolor sit amet, consectetur "
|
||||
"adipiscing elit, sed do eiusmod tempor incididunt"
|
||||
@@ -336,7 +344,8 @@ class InhibitedAlert(AlertGenerator):
|
||||
def alerts(self):
|
||||
return [
|
||||
newAlert(self._labels(instance="server1", cluster="prod",
|
||||
severity="warning"),
|
||||
severity="warning", job="textfile_exporter",
|
||||
region="CN"),
|
||||
self._annotations()
|
||||
)
|
||||
]
|
||||
@@ -349,7 +358,8 @@ class InhibitingAlert(AlertGenerator):
|
||||
def alerts(self):
|
||||
return [
|
||||
newAlert(self._labels(instance="server1", cluster="prod",
|
||||
severity="critical"),
|
||||
severity="critical", job="textfile_exporter",
|
||||
region="CN"),
|
||||
self._annotations()
|
||||
)
|
||||
]
|
||||
@@ -362,7 +372,8 @@ class SilencedAlertWithJiraLink(AlertGenerator):
|
||||
def alerts(self):
|
||||
return [
|
||||
newAlert(self._labels(instance="server%d" % i, cluster="staging",
|
||||
severity="critical"),
|
||||
severity="critical", job="node_exporter",
|
||||
region="AF"),
|
||||
self._annotations(
|
||||
dashboard="https://www.atlassian.com/software/jira")
|
||||
) for i in xrange(1, 9)
|
||||
|
||||
@@ -41,6 +41,8 @@ labels:
|
||||
- instance
|
||||
- "@receiver"
|
||||
custom:
|
||||
region:
|
||||
"*": "#736598"
|
||||
severity:
|
||||
info: "#87c4e0"
|
||||
warning: "#ffae42"
|
||||
|
||||
@@ -345,7 +345,10 @@ labels:
|
||||
to configure a set of labels with custom predefined colors applied to them
|
||||
rather than generated. Colors can be defined as RGB or HEX values.
|
||||
Value is a mapping with `label name` -> `label value` -> `color`, see examples
|
||||
below.
|
||||
below. Wildcard values (`*`) are allowed to provide a fallback custom color,
|
||||
which can also be used instead of `color:static` option. Wildcard options
|
||||
are evaluated after exact matches, so it's possible to mix explicit and
|
||||
wildcard values.
|
||||
Note: this option is not available via environment variables, you can only set
|
||||
it via the config file.
|
||||
- `keep` - list of allowed labels, if empty all labels are allowed.
|
||||
@@ -398,6 +401,20 @@ labels:
|
||||
critical: "#ff220c"
|
||||
```
|
||||
|
||||
Example with a wildcard value, `info`, `warning` and `critical` will get colors
|
||||
as below, but any value not matching those 3 values will use the color from `*`:
|
||||
|
||||
```YAML
|
||||
labels:
|
||||
color:
|
||||
custom:
|
||||
severity:
|
||||
"*": "#736598"
|
||||
info: "#87c4e0"
|
||||
warning: "#ffae42"
|
||||
critical: "#ff220c"
|
||||
```
|
||||
|
||||
Defaults:
|
||||
|
||||
```YAML
|
||||
|
||||
@@ -75,6 +75,15 @@ var colorTests = []colorTest{
|
||||
},
|
||||
colors: map[string]string{},
|
||||
},
|
||||
{
|
||||
customLabels: map[string]map[string]string{
|
||||
"node": map[string]string{"*": "#123"},
|
||||
},
|
||||
labels: map[string]string{
|
||||
"node": "localhost",
|
||||
},
|
||||
colors: map[string]string{"node": "localhost"},
|
||||
},
|
||||
}
|
||||
|
||||
func TestColorLabel(t *testing.T) {
|
||||
|
||||
@@ -39,6 +39,29 @@ func rgbToBrightness(r, g, b uint8) int32 {
|
||||
return ((int32(r) * 299) + (int32(g) * 587) + (int32(b) * 114)) / 1000
|
||||
}
|
||||
|
||||
func parseCustomColor(colorStore models.LabelsColorMap, key, val, customColor string) {
|
||||
color, err := plcolors.Parse(customColor)
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -46,30 +69,19 @@ 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,
|
||||
}
|
||||
// try matching both key and value
|
||||
customColor, found := config.Config.Labels.Color.Custom[key][val]
|
||||
if found {
|
||||
parseCustomColor(colorStore, key, val, customColor)
|
||||
return
|
||||
}
|
||||
|
||||
// if not found try matching key and wildcard (*)
|
||||
customColor, found = config.Config.Labels.Color.Custom[key]["*"]
|
||||
if found {
|
||||
parseCustomColor(colorStore, key, val, customColor)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// if no custom color is found then generate unique colors if needed
|
||||
|
||||
Reference in New Issue
Block a user