Adjust logic in functions responsible for passing metrics in order to be able to process them correctly in case where pass and drop are defined together.
264 lines
5.6 KiB
Go
264 lines
5.6 KiB
Go
package models
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/influxdata/telegraf/filter"
|
|
)
|
|
|
|
// TagFilter is the name of a tag, and the values on which to filter
|
|
type TagFilter struct {
|
|
Name string
|
|
Filter []string
|
|
filter filter.Filter
|
|
}
|
|
|
|
// Filter containing drop/pass and tagdrop/tagpass rules
|
|
type Filter struct {
|
|
NameDrop []string
|
|
nameDrop filter.Filter
|
|
NamePass []string
|
|
namePass filter.Filter
|
|
|
|
FieldDrop []string
|
|
fieldDrop filter.Filter
|
|
FieldPass []string
|
|
fieldPass filter.Filter
|
|
|
|
TagDrop []TagFilter
|
|
TagPass []TagFilter
|
|
|
|
TagExclude []string
|
|
tagExclude filter.Filter
|
|
TagInclude []string
|
|
tagInclude filter.Filter
|
|
|
|
isActive bool
|
|
}
|
|
|
|
// Compile all Filter lists into filter.Filter objects.
|
|
func (f *Filter) Compile() error {
|
|
if len(f.NameDrop) == 0 &&
|
|
len(f.NamePass) == 0 &&
|
|
len(f.FieldDrop) == 0 &&
|
|
len(f.FieldPass) == 0 &&
|
|
len(f.TagInclude) == 0 &&
|
|
len(f.TagExclude) == 0 &&
|
|
len(f.TagPass) == 0 &&
|
|
len(f.TagDrop) == 0 {
|
|
return nil
|
|
}
|
|
|
|
f.isActive = true
|
|
var err error
|
|
f.nameDrop, err = filter.Compile(f.NameDrop)
|
|
if err != nil {
|
|
return fmt.Errorf("Error compiling 'namedrop', %s", err)
|
|
}
|
|
f.namePass, err = filter.Compile(f.NamePass)
|
|
if err != nil {
|
|
return fmt.Errorf("Error compiling 'namepass', %s", err)
|
|
}
|
|
|
|
f.fieldDrop, err = filter.Compile(f.FieldDrop)
|
|
if err != nil {
|
|
return fmt.Errorf("Error compiling 'fielddrop', %s", err)
|
|
}
|
|
f.fieldPass, err = filter.Compile(f.FieldPass)
|
|
if err != nil {
|
|
return fmt.Errorf("Error compiling 'fieldpass', %s", err)
|
|
}
|
|
|
|
f.tagExclude, err = filter.Compile(f.TagExclude)
|
|
if err != nil {
|
|
return fmt.Errorf("Error compiling 'tagexclude', %s", err)
|
|
}
|
|
f.tagInclude, err = filter.Compile(f.TagInclude)
|
|
if err != nil {
|
|
return fmt.Errorf("Error compiling 'taginclude', %s", err)
|
|
}
|
|
|
|
for i, _ := range f.TagDrop {
|
|
f.TagDrop[i].filter, err = filter.Compile(f.TagDrop[i].Filter)
|
|
if err != nil {
|
|
return fmt.Errorf("Error compiling 'tagdrop', %s", err)
|
|
}
|
|
}
|
|
for i, _ := range f.TagPass {
|
|
f.TagPass[i].filter, err = filter.Compile(f.TagPass[i].Filter)
|
|
if err != nil {
|
|
return fmt.Errorf("Error compiling 'tagpass', %s", err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Apply applies the filter to the given measurement name, fields map, and
|
|
// tags map. It will return false if the metric should be "filtered out", and
|
|
// true if the metric should "pass".
|
|
// It will modify tags & fields in-place if they need to be deleted.
|
|
func (f *Filter) Apply(
|
|
measurement string,
|
|
fields map[string]interface{},
|
|
tags map[string]string,
|
|
) bool {
|
|
if !f.isActive {
|
|
return true
|
|
}
|
|
|
|
// check if the measurement name should pass
|
|
if !f.shouldNamePass(measurement) {
|
|
return false
|
|
}
|
|
|
|
// check if the tags should pass
|
|
if !f.shouldTagsPass(tags) {
|
|
return false
|
|
}
|
|
|
|
// filter fields
|
|
for fieldkey, _ := range fields {
|
|
if !f.shouldFieldPass(fieldkey) {
|
|
delete(fields, fieldkey)
|
|
}
|
|
}
|
|
if len(fields) == 0 {
|
|
return false
|
|
}
|
|
|
|
// filter tags
|
|
f.filterTags(tags)
|
|
|
|
return true
|
|
}
|
|
|
|
// IsActive checking if filter is active
|
|
func (f *Filter) IsActive() bool {
|
|
return f.isActive
|
|
}
|
|
|
|
// shouldNamePass returns true if the metric should pass, false if should drop
|
|
// based on the drop/pass filter parameters
|
|
func (f *Filter) shouldNamePass(key string) bool {
|
|
|
|
pass := func(f *Filter) bool {
|
|
if f.namePass.Match(key) {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
drop := func(f *Filter) bool {
|
|
if f.nameDrop.Match(key) {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
if f.namePass != nil && f.nameDrop != nil {
|
|
return pass(f) && drop(f)
|
|
} else if f.namePass != nil {
|
|
return pass(f)
|
|
} else if f.nameDrop != nil {
|
|
return drop(f)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// shouldFieldPass returns true if the metric should pass, false if should drop
|
|
// based on the drop/pass filter parameters
|
|
func (f *Filter) shouldFieldPass(key string) bool {
|
|
|
|
pass := func(f *Filter) bool {
|
|
if f.fieldPass.Match(key) {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
drop := func(f *Filter) bool {
|
|
if f.fieldDrop.Match(key) {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
if f.fieldPass != nil && f.fieldDrop != nil {
|
|
return pass(f) && drop(f)
|
|
} else if f.fieldPass != nil {
|
|
return pass(f)
|
|
} else if f.fieldDrop != nil {
|
|
return drop(f)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// shouldTagsPass returns true if the metric should pass, false if should drop
|
|
// based on the tagdrop/tagpass filter parameters
|
|
func (f *Filter) shouldTagsPass(tags map[string]string) bool {
|
|
|
|
pass := func(f *Filter) bool {
|
|
for _, pat := range f.TagPass {
|
|
if pat.filter == nil {
|
|
continue
|
|
}
|
|
if tagval, ok := tags[pat.Name]; ok {
|
|
if pat.filter.Match(tagval) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
drop := func(f *Filter) bool {
|
|
for _, pat := range f.TagDrop {
|
|
if pat.filter == nil {
|
|
continue
|
|
}
|
|
if tagval, ok := tags[pat.Name]; ok {
|
|
if pat.filter.Match(tagval) {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Add additional logic in case where both parameters are set.
|
|
// see: https://github.com/influxdata/telegraf/issues/2860
|
|
if f.TagPass != nil && f.TagDrop != nil {
|
|
// return true only in case when tag pass and won't be dropped (true, true).
|
|
// in case when the same tag should be passed and dropped it will be dropped (true, false).
|
|
return pass(f) && drop(f)
|
|
} else if f.TagPass != nil {
|
|
return pass(f)
|
|
} else if f.TagDrop != nil {
|
|
return drop(f)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// Apply TagInclude and TagExclude filters.
|
|
// modifies the tags map in-place.
|
|
func (f *Filter) filterTags(tags map[string]string) {
|
|
if f.tagInclude != nil {
|
|
for k, _ := range tags {
|
|
if !f.tagInclude.Match(k) {
|
|
delete(tags, k)
|
|
}
|
|
}
|
|
}
|
|
|
|
if f.tagExclude != nil {
|
|
for k, _ := range tags {
|
|
if f.tagExclude.Match(k) {
|
|
delete(tags, k)
|
|
}
|
|
}
|
|
}
|
|
}
|