forked from stripe/veneur
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sink_routing.go
170 lines (148 loc) · 3.55 KB
/
sink_routing.go
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package veneur
import (
"fmt"
"regexp"
"strings"
)
type SinkRoutingConfig struct {
Name string `yaml:"name"`
MatchConfigs []MatcherConfig `yaml:"match"`
Sinks SinkRoutingSinks `yaml:"sinks"`
}
type MatcherConfig struct {
Name NameMatcher `yaml:"name"`
Tags []TagMatcher `yaml:"tags"`
}
type NameMatcherConfig struct {
Kind string `yaml:"kind"`
Value string `yaml:"value"`
}
type NameMatcher struct {
Kind string `yaml:"kind"`
match func(string) bool
regex *regexp.Regexp
Value string `yaml:"value"`
}
type TagMatcherConfig struct {
Kind string `yaml:"kind"`
Unset bool `yaml:"unset"`
Value string `yaml:"value"`
}
type TagMatcher struct {
Kind string `yaml:"kind"`
match func(string) bool
regex *regexp.Regexp
Unset bool `yaml:"unset"`
Value string `yaml:"value"`
}
type SinkRoutingSinks struct {
Matched []string `yaml:"matched"`
NotMatched []string `yaml:"not_matched"`
}
// UnmarshalYAML unmarshals and validates the yaml config for matching the name
// of a metric.
func (matcher *NameMatcher) UnmarshalYAML(
unmarshal func(interface{}) error,
) error {
config := NameMatcherConfig{}
err := unmarshal(&config)
if err != nil {
return err
}
matcher.Kind = config.Kind
switch config.Kind {
case "any":
matcher.match = matcher.matchAny
case "exact":
matcher.match = matcher.matchExact
case "prefix":
matcher.match = matcher.matchPrefix
case "regex":
matcher.regex, err = regexp.Compile(config.Value)
if err != nil {
return err
}
matcher.match = matcher.matchRegex
default:
return fmt.Errorf("unknown matcher kind \"%s\"", config.Kind)
}
matcher.Value = config.Value
return nil
}
func (matcher *NameMatcher) matchAny(value string) bool {
return true
}
func (matcher *NameMatcher) matchExact(value string) bool {
return value == matcher.Value
}
func (matcher *NameMatcher) matchPrefix(value string) bool {
return strings.HasPrefix(value, matcher.Value)
}
func (matcher *NameMatcher) matchRegex(value string) bool {
return matcher.regex.MatchString(value)
}
// UnmarshalYAML unmarshals and validates the yaml config for matching tags
// within a metric.
func (matcher *TagMatcher) UnmarshalYAML(
unmarshal func(interface{}) error,
) error {
config := TagMatcherConfig{}
err := unmarshal(&config)
if err != nil {
return err
}
matcher.Kind = config.Kind
switch config.Kind {
case "exact":
matcher.match = matcher.matchExact
case "prefix":
matcher.match = matcher.matchPrefix
case "regex":
matcher.regex, err = regexp.Compile(config.Value)
if err != nil {
return err
}
matcher.match = matcher.matchRegex
default:
return fmt.Errorf("unknown matcher kind \"%s\"", config.Kind)
}
matcher.Unset = config.Unset
matcher.Value = config.Value
return nil
}
func (matcher *TagMatcher) matchExact(value string) bool {
return value == matcher.Value
}
func (matcher *TagMatcher) matchPrefix(value string) bool {
return strings.HasPrefix(value, matcher.Value)
}
func (matcher *TagMatcher) matchRegex(value string) bool {
return matcher.regex.MatchString(value)
}
func (config *SinkRoutingConfig) Match(
name string, tags []string,
) bool {
configLoop:
for _, matchConfig := range config.MatchConfigs {
if !matchConfig.Name.match(name) {
continue
}
tagLoop:
for _, tagMatchConfig := range matchConfig.Tags {
for _, tag := range tags {
if tagMatchConfig.match(tag) {
if tagMatchConfig.Unset {
continue configLoop
} else {
continue tagLoop
}
}
}
if !tagMatchConfig.Unset {
continue configLoop
}
}
return true
}
return false
}