The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/pkg/promlib/models/scope.go

106 lines
2.5 KiB

package models
import (
"fmt"
"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/promql/parser"
)
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
default:
return nil, fmt.Errorf("unknown operator %q", f.Operator)
}
return labels.NewMatcher(mt, f.Key, f.Value)
}