mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com> Co-authored-by: Bogdan Matei <bogdan.matei@grafana.com>
117 lines
3.1 KiB
Go
117 lines
3.1 KiB
Go
package models
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/prometheus/prometheus/model/labels"
|
|
"github.com/prometheus/prometheus/promql/parser"
|
|
)
|
|
|
|
// ApplyFiltersAndGroupBy takes a raw promQL expression, converts the filters into PromQL matchers, and applies these matchers to the parsed expression. It also applies the group by clause to any aggregate expressions in the parsed expression.
|
|
func ApplyFiltersAndGroupBy(rawExpr string, scopeFilters, adHocFilters []ScopeFilter, groupBy []string) (string, error) {
|
|
expr, err := parser.ParseExpr(rawExpr)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
matchers, err := FiltersToMatchers(scopeFilters, adHocFilters)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
matcherNamesToIdx := make(map[string]int, len(matchers))
|
|
for i, matcher := range matchers {
|
|
if matcher == nil {
|
|
continue
|
|
}
|
|
matcherNamesToIdx[matcher.Name] = i
|
|
}
|
|
|
|
parser.Inspect(expr, func(node parser.Node, nodes []parser.Node) error {
|
|
switch v := node.(type) {
|
|
case *parser.VectorSelector:
|
|
found := make([]bool, len(matchers))
|
|
for _, matcher := range v.LabelMatchers {
|
|
if matcher == nil || matcher.Name == "__name__" { // const prob
|
|
continue
|
|
}
|
|
if _, ok := matcherNamesToIdx[matcher.Name]; ok {
|
|
found[matcherNamesToIdx[matcher.Name]] = true
|
|
newM := matchers[matcherNamesToIdx[matcher.Name]]
|
|
matcher.Name = newM.Name
|
|
matcher.Type = newM.Type
|
|
matcher.Value = newM.Value
|
|
}
|
|
}
|
|
for i, f := range found {
|
|
if f {
|
|
continue
|
|
}
|
|
v.LabelMatchers = append(v.LabelMatchers, matchers[i])
|
|
}
|
|
|
|
return nil
|
|
case *parser.AggregateExpr:
|
|
found := make(map[string]bool)
|
|
for _, lName := range v.Grouping {
|
|
found[lName] = true
|
|
}
|
|
for _, k := range groupBy {
|
|
if !found[k] {
|
|
v.Grouping = append(v.Grouping, k)
|
|
}
|
|
}
|
|
return nil
|
|
default:
|
|
return nil
|
|
}
|
|
})
|
|
return expr.String(), nil
|
|
}
|
|
|
|
func FiltersToMatchers(scopeFilters, adhocFilters []ScopeFilter) ([]*labels.Matcher, error) {
|
|
filterMap := make(map[string]*labels.Matcher)
|
|
|
|
for _, filter := range append(scopeFilters, adhocFilters...) {
|
|
matcher, err := filterToMatcher(filter)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
filterMap[filter.Key] = matcher
|
|
}
|
|
|
|
matchers := make([]*labels.Matcher, 0, len(filterMap))
|
|
for _, matcher := range filterMap {
|
|
matchers = append(matchers, matcher)
|
|
}
|
|
|
|
return matchers, nil
|
|
}
|
|
|
|
func filterToMatcher(f ScopeFilter) (*labels.Matcher, error) {
|
|
var mt labels.MatchType
|
|
switch f.Operator {
|
|
case FilterOperatorEquals:
|
|
mt = labels.MatchEqual
|
|
case FilterOperatorNotEquals:
|
|
mt = labels.MatchNotEqual
|
|
case FilterOperatorRegexMatch:
|
|
mt = labels.MatchRegexp
|
|
case FilterOperatorRegexNotMatch:
|
|
mt = labels.MatchNotRegexp
|
|
case FilterOperatorOneOf:
|
|
mt = labels.MatchRegexp
|
|
case FilterOperatorNotOneOf:
|
|
mt = labels.MatchNotRegexp
|
|
default:
|
|
return nil, fmt.Errorf("unknown operator %q", f.Operator)
|
|
}
|
|
if f.Operator == FilterOperatorOneOf || f.Operator == FilterOperatorNotOneOf {
|
|
if len(f.Values) > 0 {
|
|
return labels.NewMatcher(mt, f.Key, strings.Join(f.Values, "|"))
|
|
}
|
|
}
|
|
return labels.NewMatcher(mt, f.Key, f.Value)
|
|
}
|