diff --git a/docs/changelog.md b/docs/changelog.md index 9332687a..490af22a 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,12 @@ # Changelog +## v0.42.2 + +### Fixed + +- `alerts/template` check didn't correctly handle `label_replace()` calls + in queries - #568. + ## v0.42.1 ### Fixed diff --git a/internal/checks/alerts_template.go b/internal/checks/alerts_template.go index 1fb07665..94a0ca1d 100644 --- a/internal/checks/alerts_template.go +++ b/internal/checks/alerts_template.go @@ -108,6 +108,16 @@ func (c TemplateCheck) Check(ctx context.Context, path string, rule parser.Rule, safeLabels = append(safeLabels, be.VectorMatching.Include...) } } + for _, cl := range calls(rule.AlertingRule.Expr.Query, "label_replace") { + for i, v := range cl.Args { + if i == 1 { + if s, ok := v.(*promParser.StringLiteral); ok { + safeLabels = append(safeLabels, s.Val) + } + break + } + } + } data := promTemplate.AlertTemplateData(map[string]string{}, map[string]string{}, "", 0) @@ -477,11 +487,8 @@ func checkMetricLabels(msg, name, text string, metricLabels []string, excludeLab found = true } } - if found && slices.Contains(safeLabels, v[1]) { - found = !excludeLabels - } if found == excludeLabels { - if _, ok := done[v[1]]; !ok { + if _, ok := done[v[1]]; !ok && !slices.Contains(safeLabels, v[1]) { msgs = append(msgs, fmt.Sprintf(msg, v[1])) done[v[1]] = struct{}{} } @@ -539,3 +546,15 @@ func binaryExprs(node *parser.PromQLNode) (be []*promParser.BinaryExpr) { return be } + +func calls(node *parser.PromQLNode, name string) (cl []*promParser.Call) { + if n, ok := node.Node.(*promParser.Call); ok && n.Func.Name == name { + cl = append(cl, n) + } + + for _, child := range node.Children { + cl = append(cl, calls(child, name)...) + } + + return cl +} diff --git a/internal/checks/alerts_template_test.go b/internal/checks/alerts_template_test.go index 01e55abd..a539caeb 100644 --- a/internal/checks/alerts_template_test.go +++ b/internal/checks/alerts_template_test.go @@ -426,6 +426,22 @@ func TestTemplateCheck(t *testing.T) { } }, }, + { + description: "don't trigger for label_replace() provided labels", + content: ` +- alert: label_replace_not_checked_correctly + expr: | + label_replace( + sum by (pod) (pod_status) > 0 + ,"cluster", "$1", "pod", "(.*)" + ) + annotations: + summary: "Some error found in {{ $labels.cluster }}" +`, + checker: newTemplateCheck, + prometheus: noProm, + problems: noProblems, + }, { description: "annotation label present on metrics (absent)", content: `