mirror of
https://github.com/grafana/grafana.git
synced 2025-02-12 08:35:43 -06:00
* 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>
135 lines
3.3 KiB
Go
135 lines
3.3 KiB
Go
package template
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/url"
|
|
"regexp"
|
|
"strings"
|
|
"text/template"
|
|
|
|
"golang.org/x/exp/slices"
|
|
)
|
|
|
|
type query struct {
|
|
Datasource string `json:"datasource"`
|
|
Expr string `json:"expr"`
|
|
}
|
|
|
|
const (
|
|
FilterLabelFuncName = "filterLabels"
|
|
FilterLabelReFuncName = "filterLabelsRe"
|
|
GraphLinkFuncName = "graphLink"
|
|
RemoveLabelsFuncName = "removeLabels"
|
|
RemoveLabelsReFuncName = "removeLabelsRe"
|
|
TableLinkFuncName = "tableLink"
|
|
MergeLabelValuesFuncName = "mergeLabelValues"
|
|
)
|
|
|
|
var (
|
|
defaultFuncs = template.FuncMap{
|
|
FilterLabelFuncName: filterLabelsFunc,
|
|
FilterLabelReFuncName: filterLabelsReFunc,
|
|
GraphLinkFuncName: graphLinkFunc,
|
|
RemoveLabelsFuncName: removeLabelsFunc,
|
|
RemoveLabelsReFuncName: removeLabelsReFunc,
|
|
TableLinkFuncName: tableLinkFunc,
|
|
MergeLabelValuesFuncName: mergeLabelValuesFunc,
|
|
}
|
|
)
|
|
|
|
// filterLabelsFunc removes all labels that do not match the string.
|
|
func filterLabelsFunc(m Labels, match string) Labels {
|
|
res := make(Labels)
|
|
for k, v := range m {
|
|
if k == match {
|
|
res[k] = v
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
// filterLabelsReFunc removes all labels that do not match the regex.
|
|
func filterLabelsReFunc(m Labels, pattern string) Labels {
|
|
re := regexp.MustCompile(pattern)
|
|
res := make(Labels)
|
|
for k, v := range m {
|
|
if re.MatchString(k) {
|
|
res[k] = v
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
func graphLinkFunc(data string) string {
|
|
var q query
|
|
if err := json.Unmarshal([]byte(data), &q); err != nil {
|
|
return ""
|
|
}
|
|
datasource := url.QueryEscape(q.Datasource)
|
|
expr := url.QueryEscape(q.Expr)
|
|
return fmt.Sprintf(`/explore?left={"datasource":%[1]q,"queries":[{"datasource":%[1]q,"expr":%q,"instant":false,"range":true,"refId":"A"}],"range":{"from":"now-1h","to":"now"}}`, datasource, expr)
|
|
}
|
|
|
|
// removeLabelsFunc removes all labels that match the string.
|
|
func removeLabelsFunc(m Labels, match string) Labels {
|
|
res := make(Labels)
|
|
for k, v := range m {
|
|
if k != match {
|
|
res[k] = v
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
// removeLabelsReFunc removes all labels that match the regex.
|
|
func removeLabelsReFunc(m Labels, pattern string) Labels {
|
|
re := regexp.MustCompile(pattern)
|
|
res := make(Labels)
|
|
for k, v := range m {
|
|
if !re.MatchString(k) {
|
|
res[k] = v
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
func tableLinkFunc(data string) string {
|
|
var q query
|
|
if err := json.Unmarshal([]byte(data), &q); err != nil {
|
|
return ""
|
|
}
|
|
datasource := url.QueryEscape(q.Datasource)
|
|
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
|
|
}
|