44 "fmt"
55 "strings"
66
7+ promql "github.com/cortexproject/cortex/pkg/configs/legacy_promql"
78 rulefmt "github.com/cortexproject/cortex/pkg/ruler/legacy_rulefmt"
89 "github.com/prometheus/prometheus/promql/parser"
910 log "github.com/sirupsen/logrus"
@@ -29,7 +30,7 @@ func (r RuleNamespace) LintPromQLExpressions() (int, int, error) {
2930 for i , group := range r .Groups {
3031 for j , rule := range group .Rules {
3132 log .WithFields (log.Fields {"rule" : getRuleName (rule )}).Debugf ("linting PromQL" )
32- exp , err := parser .ParseExpr (rule .Expr )
33+ exp , err := promql .ParseExpr (rule .Expr )
3334 if err != nil {
3435 return count , mod , err
3536 }
@@ -122,34 +123,68 @@ func (r RuleNamespace) AggregateBy(label string) (int, int, error) {
122123}
123124
124125// exprNodeInspectorFunc returns a PromQL inspector.
125- // It modifies most PromQL aggregations to include a given label.
126+ // It modifies most PromQL expressions to include a given label.
126127func exprNodeInspectorFunc (rule rulefmt.Rule , label string ) func (node parser.Node , path []parser.Node ) error {
127128 return func (node parser.Node , path []parser.Node ) error {
128- aggregation , ok := node .(* parser.AggregateExpr )
129- if ! ok {
130- return nil
129+ var err error
130+ switch n := node .(type ) {
131+ case * parser.AggregateExpr :
132+ err = prepareAggregationExpr (n , label , getRuleName (rule ))
133+ case * parser.BinaryExpr :
134+ err = prepareBinaryExpr (n , label , getRuleName (rule ))
135+ default :
136+ return err
131137 }
132138
133- // If the aggregation is about dropping labels (e.g. without), we don't want to modify
134- // this expression. Omission as long as it is not the cluster label will include it.
135- // TODO: We probably want to check whenever the label we're trying to include is included in the omission.
136- if aggregation .Without {
139+ return err
140+ }
141+ }
142+
143+ func prepareAggregationExpr (e * parser.AggregateExpr , label string , ruleName string ) error {
144+ // If the aggregation is about dropping labels (e.g. without), we don't want to modify
145+ // this expression. Omission as long as it is not the cluster label will include it.
146+ // TODO: We probably want to check whenever the label we're trying to include is included in the omission.
147+ if e .Without {
148+ return nil
149+ }
150+
151+ for _ , lbl := range e .Grouping {
152+ // It already has the label we want to aggregate by.
153+ if lbl == label {
137154 return nil
138155 }
156+ }
139157
140- for _ , lbl := range aggregation .Grouping {
141- if lbl == label {
142- return nil
143- }
144- }
158+ log .WithFields (
159+ log.Fields {"rule" : ruleName , "lbls" : strings .Join (e .Grouping , ", " )},
160+ ).Debugf ("aggregation without '%s' label, adding." , label )
145161
146- log . WithFields (
147- log. Fields { "rule" : getRuleName ( rule ), "lbls" : strings . Join ( aggregation . Grouping , ", " )},
148- ). Debugf ( "aggregation without '%s' label, adding." , label )
162+ e . Grouping = append ( e . Grouping , label )
163+ return nil
164+ }
149165
150- aggregation .Grouping = append (aggregation .Grouping , label )
166+ func prepareBinaryExpr (e * parser.BinaryExpr , label string , rule string ) error {
167+ if e .VectorMatching == nil {
151168 return nil
152169 }
170+
171+ if ! e .VectorMatching .On {
172+ return nil
173+ }
174+
175+ for _ , lbl := range e .VectorMatching .MatchingLabels {
176+ // It already has the label we want to add in the expression.
177+ if lbl == label {
178+ return nil
179+ }
180+ }
181+
182+ log .WithFields (
183+ log.Fields {"rule" : rule , "lbls" : strings .Join (e .VectorMatching .MatchingLabels , ", " )},
184+ ).Debugf ("binary expression without '%s' label, adding." , label )
185+
186+ e .VectorMatching .MatchingLabels = append (e .VectorMatching .MatchingLabels , label )
187+ return nil
153188}
154189
155190// Validate each rule in the rule namespace is valid
0 commit comments