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/[\\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() }) }