-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
430 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Regex Processor Plugin | ||
|
||
The `regex` plugin transforms tag and field values with regex pattern. If `result_key` parameter is present, it can produce new tags and fields from existing ones. | ||
|
||
### Configuration: | ||
|
||
```toml | ||
[[processors.regex]] | ||
namepass = ["nginx_requests"] | ||
|
||
# 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$" | ||
## Pattern for constructing a new value (${1} represents first subgroup) | ||
replacement = "${1}xx" | ||
|
||
[[processors.regex.fields]] | ||
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" | ||
``` | ||
|
||
### Tags: | ||
|
||
No tags are applied by this processor. | ||
|
||
### Example Output: | ||
``` | ||
nginx_requests,verb=GET,resp_code=2xx request="/api/search/?category=plugins&q=regex&sort=asc",method="/search/",search_category="plugins",referrer="-",ident="-",http_version=1.1,agent="UserAgent",client_ip="127.0.0.1",auth="-",resp_bytes=270i 1519652321000000000 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
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 | ||
} | ||
|
||
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$" | ||
# ## Pattern for constructing a new value (${1} represents first subgroup) | ||
# replacement = "${1}xx" | ||
# [[processors.regex.fields]] | ||
# 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 { | ||
metric.AddTag(r.convert(converter, value)) | ||
} | ||
} | ||
|
||
for _, converter := range r.Fields { | ||
if value, ok := metric.GetField(converter.Key); ok { | ||
switch value := value.(type) { | ||
case string: | ||
metric.AddField(r.convert(converter, value)) | ||
} | ||
} | ||
} | ||
} | ||
|
||
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() | ||
}) | ||
} |
Oops, something went wrong.