...
1
2
3
4
5
6
7
8
9
10
11
12
13
14 package labels
15
16 import (
17 "bytes"
18 "encoding/json"
19 "fmt"
20 "regexp"
21 "strings"
22
23 "github.com/prometheus/common/model"
24 )
25
26
27 type MatchType int
28
29
30 const (
31 MatchEqual MatchType = iota
32 MatchNotEqual
33 MatchRegexp
34 MatchNotRegexp
35 )
36
37 func (m MatchType) String() string {
38 typeToStr := map[MatchType]string{
39 MatchEqual: "=",
40 MatchNotEqual: "!=",
41 MatchRegexp: "=~",
42 MatchNotRegexp: "!~",
43 }
44 if str, ok := typeToStr[m]; ok {
45 return str
46 }
47 panic("unknown match type")
48 }
49
50
51 type Matcher struct {
52 Type MatchType
53 Name string
54 Value string
55
56 re *regexp.Regexp
57 }
58
59
60 func NewMatcher(t MatchType, n, v string) (*Matcher, error) {
61 m := &Matcher{
62 Type: t,
63 Name: n,
64 Value: v,
65 }
66 if t == MatchRegexp || t == MatchNotRegexp {
67 re, err := regexp.Compile("^(?:" + v + ")$")
68 if err != nil {
69 return nil, err
70 }
71 m.re = re
72 }
73 return m, nil
74 }
75
76 func (m *Matcher) String() string {
77 return fmt.Sprintf(`%s%s"%s"`, m.Name, m.Type, openMetricsEscape(m.Value))
78 }
79
80
81 func (m *Matcher) Matches(s string) bool {
82 switch m.Type {
83 case MatchEqual:
84 return s == m.Value
85 case MatchNotEqual:
86 return s != m.Value
87 case MatchRegexp:
88 return m.re.MatchString(s)
89 case MatchNotRegexp:
90 return !m.re.MatchString(s)
91 }
92 panic("labels.Matcher.Matches: invalid match type")
93 }
94
95 type apiV1Matcher struct {
96 Name string `json:"name"`
97 Value string `json:"value"`
98 IsRegex bool `json:"isRegex"`
99 IsEqual bool `json:"isEqual"`
100 }
101
102
103 func (m Matcher) MarshalJSON() ([]byte, error) {
104 return json.Marshal(apiV1Matcher{
105 Name: m.Name,
106 Value: m.Value,
107 IsRegex: m.Type == MatchRegexp || m.Type == MatchNotRegexp,
108 IsEqual: m.Type == MatchRegexp || m.Type == MatchEqual,
109 })
110 }
111
112 func (m *Matcher) UnmarshalJSON(data []byte) error {
113 v1m := apiV1Matcher{
114 IsEqual: true,
115 }
116
117 if err := json.Unmarshal(data, &v1m); err != nil {
118 return err
119 }
120
121 var t MatchType
122 switch {
123 case v1m.IsEqual && !v1m.IsRegex:
124 t = MatchEqual
125 case !v1m.IsEqual && !v1m.IsRegex:
126 t = MatchNotEqual
127 case v1m.IsEqual && v1m.IsRegex:
128 t = MatchRegexp
129 case !v1m.IsEqual && v1m.IsRegex:
130 t = MatchNotRegexp
131 }
132
133 matcher, err := NewMatcher(t, v1m.Name, v1m.Value)
134 if err != nil {
135 return err
136 }
137 *m = *matcher
138 return nil
139 }
140
141
142
143
144
145 func openMetricsEscape(s string) string {
146 r := strings.NewReplacer(
147 `\`, `\\`,
148 "\n", `\n`,
149 `"`, `\"`,
150 )
151 return r.Replace(s)
152 }
153
154
155
156
157 type Matchers []*Matcher
158
159 func (ms Matchers) Len() int { return len(ms) }
160 func (ms Matchers) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] }
161
162 func (ms Matchers) Less(i, j int) bool {
163 if ms[i].Name > ms[j].Name {
164 return false
165 }
166 if ms[i].Name < ms[j].Name {
167 return true
168 }
169 if ms[i].Value > ms[j].Value {
170 return false
171 }
172 if ms[i].Value < ms[j].Value {
173 return true
174 }
175 return ms[i].Type < ms[j].Type
176 }
177
178
179 func (ms Matchers) Matches(lset model.LabelSet) bool {
180 for _, m := range ms {
181 if !m.Matches(string(lset[model.LabelName(m.Name)])) {
182 return false
183 }
184 }
185 return true
186 }
187
188 func (ms Matchers) String() string {
189 var buf bytes.Buffer
190
191 buf.WriteByte('{')
192 for i, m := range ms {
193 if i > 0 {
194 buf.WriteByte(',')
195 }
196 buf.WriteString(m.String())
197 }
198 buf.WriteByte('}')
199
200 return buf.String()
201 }
202
View as plain text