1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
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
}
|