forked from influxdata/telegraf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
regex.go
122 lines (104 loc) · 2.84 KB
/
regex.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
package regex
import (
"regexp"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/processors"
)
type Regex struct {
Tags []converter
Fields []converter
regexCache map[string]*regexp.Regexp
}
type converter struct {
Key string
Pattern string
Replacement string
ResultKey string
Append bool
}
const sampleConfig = `
## Tag and field conversions defined in a separate sub-tables
# [[processors.regex.tags]]
# ## Tag to change
# key = "resp_code"
# ## Regular expression to match on a tag value
# pattern = "^(\\d)\\d\\d$"
# ## Matches of the pattern will be replaced with this string. Use ${1}
# ## notation to use the text of the first submatch.
# replacement = "${1}xx"
# [[processors.regex.fields]]
# ## Field to change
# key = "request"
# ## All the power of the Go regular expressions available here
# ## For example, named subgroups
# pattern = "^/api(?P<method>/[\\w/]+)\\S*"
# replacement = "${method}"
# ## If result_key is present, a new field will be created
# ## instead of changing existing field
# result_key = "method"
## Multiple conversions may be applied for one field sequentially
## Let's extract one more value
# [[processors.regex.fields]]
# key = "request"
# pattern = ".*category=(\\w+).*"
# replacement = "${1}"
# result_key = "search_category"
`
func NewRegex() *Regex {
return &Regex{
regexCache: make(map[string]*regexp.Regexp),
}
}
func (r *Regex) SampleConfig() string {
return sampleConfig
}
func (r *Regex) Description() string {
return "Transforms tag and field values with regex pattern"
}
func (r *Regex) Apply(in ...telegraf.Metric) []telegraf.Metric {
for _, metric := range in {
for _, converter := range r.Tags {
if value, ok := metric.GetTag(converter.Key); ok {
if key, newValue := r.convert(converter, value); newValue != "" {
if converter.Append {
if v, ok := metric.GetTag(key); ok {
newValue = v + newValue
}
}
metric.AddTag(key, newValue)
}
}
}
for _, converter := range r.Fields {
if value, ok := metric.GetField(converter.Key); ok {
switch value := value.(type) {
case string:
if key, newValue := r.convert(converter, value); newValue != "" {
metric.AddField(key, newValue)
}
}
}
}
}
return in
}
func (r *Regex) convert(c converter, src string) (string, string) {
regex, compiled := r.regexCache[c.Pattern]
if !compiled {
regex = regexp.MustCompile(c.Pattern)
r.regexCache[c.Pattern] = regex
}
value := ""
if c.ResultKey == "" || regex.MatchString(src) {
value = regex.ReplaceAllString(src, c.Replacement)
}
if c.ResultKey != "" {
return c.ResultKey, value
}
return c.Key, value
}
func init() {
processors.Add("regex", func() telegraf.Processor {
return NewRegex()
})
}