Skip to content

Commit

Permalink
Merge pull request cloudflare#44 from cloudflare/OBS-868
Browse files Browse the repository at this point in the history
Ignore right hand side of aggregation in by/without checks
  • Loading branch information
prymitive authored Sep 9, 2021
2 parents 9af3658 + 01aa6cf commit e93061d
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 2 deletions.
28 changes: 27 additions & 1 deletion internal/checks/by.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"regexp"

"github.com/cloudflare/pint/internal/parser"
"github.com/rs/zerolog/log"

promParser "github.com/prometheus/prometheus/promql/parser"
)
Expand Down Expand Up @@ -60,7 +61,26 @@ func (c ByCheck) Check(rule parser.Rule) (problems []Problem) {
}

func (c ByCheck) checkNode(node *parser.PromQLNode) (problems []exprProblem) {
if n, ok := node.Node.(*promParser.AggregateExpr); ok && !n.Without && n.Op != promParser.TOPK {
if n, ok := node.Node.(*promParser.AggregateExpr); ok && !n.Without {
switch n.Op {
case promParser.SUM:
case promParser.MIN:
case promParser.MAX:
case promParser.AVG:
case promParser.GROUP:
case promParser.STDDEV:
case promParser.STDVAR:
case promParser.COUNT:
case promParser.COUNT_VALUES:
case promParser.BOTTOMK:
goto NEXT
case promParser.TOPK:
goto NEXT
case promParser.QUANTILE:
default:
log.Warn().Str("op", n.Op.String()).Msg("Unsupported aggregation operation")
}

var found bool
for _, g := range n.Grouping {
if g == c.label {
Expand All @@ -84,6 +104,12 @@ func (c ByCheck) checkNode(node *parser.PromQLNode) (problems []exprProblem) {
}
}

NEXT:
if n, ok := node.Node.(*promParser.BinaryExpr); ok && n.Op == promParser.LAND {
problems = append(problems, c.checkNode(node.Children[0])...)
return
}

for _, child := range node.Children {
problems = append(problems, c.checkNode(child)...)
}
Expand Down
19 changes: 19 additions & 0 deletions internal/checks/by_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,25 @@ func TestByCheck(t *testing.T) {
},
},
},
{
description: "Right hand side of AND is ignored",
content: "- record: foo\n expr: foo AND on(instance) max(bar)\n",
checker: checks.NewByCheck(regexp.MustCompile("^.+$"), "job", true, checks.Warning),
},
{
description: "Left hand side of AND is checked",
content: "- record: foo\n expr: max (foo) by(instance) AND on(instance) bar\n",
checker: checks.NewByCheck(regexp.MustCompile("^.+$"), "job", true, checks.Warning),
problems: []checks.Problem{
{
Fragment: "max by(instance) (foo)",
Lines: []int{2},
Reporter: "promql/by",
Text: "job label is required and should be preserved when aggregating \"^.+$\" rules, use by(job, ...)",
Severity: checks.Warning,
},
},
},
}
runTests(t, testCases)
}
28 changes: 27 additions & 1 deletion internal/checks/without.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"regexp"

"github.com/cloudflare/pint/internal/parser"
"github.com/rs/zerolog/log"

promParser "github.com/prometheus/prometheus/promql/parser"
)
Expand Down Expand Up @@ -61,7 +62,26 @@ func (c WithoutCheck) Check(rule parser.Rule) (problems []Problem) {
}

func (c WithoutCheck) checkNode(node *parser.PromQLNode) (problems []exprProblem) {
if n, ok := node.Node.(*promParser.AggregateExpr); ok && n.Without && n.Op != promParser.TOPK {
if n, ok := node.Node.(*promParser.AggregateExpr); ok && n.Without {
switch n.Op {
case promParser.SUM:
case promParser.MIN:
case promParser.MAX:
case promParser.AVG:
case promParser.GROUP:
case promParser.STDDEV:
case promParser.STDVAR:
case promParser.COUNT:
case promParser.COUNT_VALUES:
case promParser.BOTTOMK:
goto NEXT
case promParser.TOPK:
goto NEXT
case promParser.QUANTILE:
default:
log.Warn().Str("op", n.Op.String()).Msg("Unsupported aggregation operation")
}

var found bool
for _, g := range n.Grouping {
if g == c.label {
Expand Down Expand Up @@ -91,6 +111,12 @@ func (c WithoutCheck) checkNode(node *parser.PromQLNode) (problems []exprProblem
}
}

NEXT:
if n, ok := node.Node.(*promParser.BinaryExpr); ok && n.Op == promParser.LAND {
problems = append(problems, c.checkNode(node.Children[0])...)
return
}

for _, child := range node.Children {
problems = append(problems, c.checkNode(child)...)
}
Expand Down
19 changes: 19 additions & 0 deletions internal/checks/without_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,25 @@ func TestWithoutCheck(t *testing.T) {
},
},
},
{
description: "Right hand side of AND is ignored",
content: "- record: foo\n expr: foo AND on(instance) max(bar) without()\n",
checker: checks.NewWithoutCheck(regexp.MustCompile("^.+$"), "job", true, checks.Warning),
},
{
description: "Left hand side of AND is checked",
content: "- record: foo\n expr: max (foo) without(job) AND on(instance) bar\n",
checker: checks.NewWithoutCheck(regexp.MustCompile("^.+$"), "job", true, checks.Warning),
problems: []checks.Problem{
{
Fragment: "max without(job) (foo)",
Lines: []int{2},
Reporter: "promql/without",
Text: "job label is required and should be preserved when aggregating \"^.+$\" rules, remove job from without()",
Severity: checks.Warning,
},
},
},
}
runTests(t, testCases)
}

0 comments on commit e93061d

Please sign in to comment.