diff options
Diffstat (limited to 'src/go/plugin/go.d/pkg/prometheus/selector/parse.go')
-rw-r--r-- | src/go/plugin/go.d/pkg/prometheus/selector/parse.go | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/src/go/plugin/go.d/pkg/prometheus/selector/parse.go b/src/go/plugin/go.d/pkg/prometheus/selector/parse.go new file mode 100644 index 000000000..81e970c48 --- /dev/null +++ b/src/go/plugin/go.d/pkg/prometheus/selector/parse.go @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package selector + +import ( + "fmt" + "regexp" + "strings" + + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/matcher" +) + +var ( + reLV = regexp.MustCompile(`^(?P<label_name>[a-zA-Z0-9_]+)(?P<op>=~|!~|=\*|!\*|=|!=)"(?P<pattern>.+)"$`) +) + +func Parse(expr string) (Selector, error) { + var srs []Selector + lvs := strings.Split(unsugarExpr(expr), ",") + + for _, lv := range lvs { + sr, err := parseSelector(lv) + if err != nil { + return nil, err + } + srs = append(srs, sr) + } + + switch len(srs) { + case 0: + return nil, nil + case 1: + return srs[0], nil + default: + return And(srs[0], srs[1], srs[2:]...), nil + } +} + +func parseSelector(line string) (Selector, error) { + sub := reLV.FindStringSubmatch(strings.TrimSpace(line)) + if sub == nil { + return nil, fmt.Errorf("invalid selector syntax: '%s'", line) + } + + name, op, pattern := sub[1], sub[2], strings.Trim(sub[3], "\"") + + var m matcher.Matcher + var err error + + switch op { + case OpEqual, OpNegEqual: + m, err = matcher.NewStringMatcher(pattern, true, true) + case OpRegexp, OpNegRegexp: + m, err = matcher.NewRegExpMatcher(pattern) + case OpSimplePatterns, OpNegSimplePatterns: + m, err = matcher.NewSimplePatternsMatcher(pattern) + default: + err = fmt.Errorf("unknown matching operator: %s", op) + } + if err != nil { + return nil, err + } + + sr := labelSelector{ + name: name, + m: m, + } + + if neg := strings.HasPrefix(op, "!"); neg { + return Not(sr), nil + } + return sr, nil +} + +func unsugarExpr(expr string) string { + // name => __name__=*"name" + // name{label="value"} => __name__=*"name",label="value" + // {label="value"} => label="value" + expr = strings.TrimSpace(expr) + + switch idx := strings.IndexByte(expr, '{'); true { + case idx == -1: + expr = fmt.Sprintf(`__name__%s"%s"`, + OpSimplePatterns, + strings.TrimSpace(expr), + ) + case idx == 0: + expr = strings.Trim(expr, "{}") + default: + expr = fmt.Sprintf(`__name__%s"%s",%s`, + OpSimplePatterns, + strings.TrimSpace(expr[:idx]), + strings.Trim(expr[idx:], "{}"), + ) + } + return expr +} |