Alerting: Migrate old alerting templates to Go templates (#62911)

* Migrate old alerting templates to use $labels

* Fix imports

* Add test coverage and separate rewriting to Go templates

* Fix lint

* Check for additional closing braces

* Add logging of invalid message templates

* Fix tests

* Small fixes

* Update comments

* Panic on empty token

* Use logtest.Fake

* Fix lint

* Allow for spaces in variable names by not tokenizing spaces

* Add template function to deduplicate Labels in a Value map

* Fix behavior of mapLookupString

* Reference deduplicated labels in migrated message template

* Fix behavior of deduplicateLabelsFunc

* Don't create variable for parent logger

* Add more tests for deduplicateLabelsFunc

* Remove unused function

* Apply suggestions from code review

Co-authored by: Yuri Tseretyan <yuriy.tseretyan@grafana.com>

* Give label val merge function better name

* Extract template migration and escape literal tokens

* Consolidate + simplify template migration

---------

Co-authored-by: William Wernert <william.wernert@grafana.com>
This commit is contained in:
George Robinson
2023-10-02 16:25:33 +01:00
committed by GitHub
parent 88347774fb
commit ed7d29f2b9
6 changed files with 619 additions and 8 deletions

View File

@@ -5,7 +5,10 @@ import (
"fmt"
"net/url"
"regexp"
"strings"
"text/template"
"golang.org/x/exp/slices"
)
type query struct {
@@ -13,14 +16,25 @@ type query struct {
Expr string `json:"expr"`
}
const (
FilterLabelFuncName = "filterLabels"
FilterLabelReFuncName = "filterLabelsRe"
GraphLinkFuncName = "graphLink"
RemoveLabelsFuncName = "removeLabels"
RemoveLabelsReFuncName = "removeLabelsRe"
TableLinkFuncName = "tableLink"
MergeLabelValuesFuncName = "mergeLabelValues"
)
var (
defaultFuncs = template.FuncMap{
"filterLabels": filterLabelsFunc,
"filterLabelsRe": filterLabelsReFunc,
"graphLink": graphLinkFunc,
"removeLabels": removeLabelsFunc,
"removeLabelslRe": removeLabelsReFunc,
"tableLink": tableLinkFunc,
FilterLabelFuncName: filterLabelsFunc,
FilterLabelReFuncName: filterLabelsReFunc,
GraphLinkFuncName: graphLinkFunc,
RemoveLabelsFuncName: removeLabelsFunc,
RemoveLabelsReFuncName: removeLabelsReFunc,
TableLinkFuncName: tableLinkFunc,
MergeLabelValuesFuncName: mergeLabelValuesFunc,
}
)
@@ -89,3 +103,32 @@ func tableLinkFunc(data string) string {
expr := url.QueryEscape(q.Expr)
return fmt.Sprintf(`/explore?left={"datasource":%[1]q,"queries":[{"datasource":%[1]q,"expr":%q,"instant":true,"range":false,"refId":"A"}],"range":{"from":"now-1h","to":"now"}}`, datasource, expr)
}
// mergeLabelValuesFunc returns a map of label keys to deduplicated and comma separated values.
func mergeLabelValuesFunc(values map[string]Value) Labels {
type uniqueLabelVals map[string]struct{}
labels := make(map[string]uniqueLabelVals)
for _, value := range values {
for k, v := range value.Labels {
var ul uniqueLabelVals
var ok bool
if ul, ok = labels[k]; !ok {
ul = uniqueLabelVals{}
labels[k] = ul
}
ul[v] = struct{}{}
}
}
res := make(Labels)
for label, vals := range labels {
keys := make([]string, 0, len(vals))
for val := range vals {
keys = append(keys, val)
}
slices.Sort(keys)
res[label] = strings.Join(keys, ", ")
}
return res
}

View File

@@ -25,3 +25,27 @@ func TestRemoveLabelsReFunc(t *testing.T) {
l := Labels{"foo": "bar", "bar": "baz"}
assert.Equal(t, Labels{"bar": "baz"}, removeLabelsReFunc(l, "f.*"))
}
func TestDeduplicateLabelsFunc(t *testing.T) {
v := map[string]Value{
"v1": {Labels: Labels{"foo": "bar", "bar": "foo"}, Value: 1},
"v2": {Labels: Labels{"foo": "bar", "bar": "baz", "baz": "bat"}, Value: 2},
}
assert.Equal(t, Labels{"foo": "bar", "bar": "baz, foo", "baz": "bat"}, mergeLabelValuesFunc(v))
}
func TestDeduplicateLabelsFuncAllSameVal(t *testing.T) {
v := map[string]Value{
"v1": {Labels: Labels{"foo": "bar", "bar": "baz"}, Value: 1},
"v2": {Labels: Labels{"foo": "bar", "bar": "baz"}, Value: 2},
}
assert.Equal(t, Labels{"foo": "bar", "bar": "baz"}, mergeLabelValuesFunc(v))
}
func TestDeduplicateLabelsFuncNoDuplicates(t *testing.T) {
v := map[string]Value{
"v1": {Labels: Labels{"foo": "bar"}, Value: 1},
"v2": {Labels: Labels{"bar": "baz"}, Value: 2},
}
assert.Equal(t, Labels{"foo": "bar", "bar": "baz"}, mergeLabelValuesFunc(v))
}