cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.44.2

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/checks/alerts_comparison.go

102lines · modecode

1package checks
2
3import (
4 "context"
5
6 "github.com/cloudflare/pint/internal/discovery"
7 "github.com/cloudflare/pint/internal/parser"
8
9 promParser "github.com/prometheus/prometheus/promql/parser"
10)
11
12const (
13 ComparisonCheckName = "alerts/comparison"
14)
15
16func NewComparisonCheck() ComparisonCheck {
17 return ComparisonCheck{}
18}
19
20type ComparisonCheck struct{}
21
22func (c ComparisonCheck) Meta() CheckMeta {
23 return CheckMeta{IsOnline: false}
24}
25
26func (c ComparisonCheck) String() string {
27 return ComparisonCheckName
28}
29
30func (c ComparisonCheck) Reporter() string {
31 return ComparisonCheckName
32}
33
34func (c ComparisonCheck) Check(_ context.Context, _ string, rule parser.Rule, _ []discovery.Entry) (problems []Problem) {
35 if rule.AlertingRule == nil {
36 return problems
37 }
38
39 if rule.AlertingRule.Expr.SyntaxError != nil {
40 return problems
41 }
42
43 expr := rule.Expr().Query
44
45 if n := hasComparision(expr.Node); n != nil {
46 if n.ReturnBool && hasComparision(n.LHS) == nil && hasComparision(n.RHS) == nil {
47 problems = append(problems, Problem{
48 Fragment: rule.AlertingRule.Expr.Value.Value,
49 Lines: rule.AlertingRule.Expr.Lines(),
50 Reporter: c.Reporter(),
51 Text: "alert query uses bool modifier for comparison, this means it will always return a result and the alert will always fire",
52 Severity: Bug,
53 })
54 }
55 return problems
56 }
57
58 if hasAbsent(expr) {
59 return problems
60 }
61
62 problems = append(problems, Problem{
63 Fragment: rule.AlertingRule.Expr.Value.Value,
64 Lines: rule.AlertingRule.Expr.Lines(),
65 Reporter: c.Reporter(),
66 Text: "alert query doesn't have any condition, it will always fire if the metric exists",
67 Severity: Warning,
68 })
69
70 return problems
71}
72
73func hasComparision(n promParser.Node) *promParser.BinaryExpr {
74 if node, ok := n.(*promParser.BinaryExpr); ok {
75 if node.Op.IsComparisonOperator() {
76 return node
77 }
78 if node.Op == promParser.LUNLESS {
79 return node
80 }
81 }
82
83 for _, child := range promParser.Children(n) {
84 if node := hasComparision(child); node != nil {
85 return node
86 }
87 }
88
89 return nil
90}
91
92func hasAbsent(n *parser.PromQLNode) bool {
93 if node, ok := n.Node.(*promParser.Call); ok && (node.Func.Name == "absent") {
94 return true
95 }
96 for _, child := range n.Children {
97 if hasAbsent(child) {
98 return true
99 }
100 }
101 return false
102}
103