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 } 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 { if f.namePass != nil { if f.namePass.Match(key) { return true } return false } if f.nameDrop != nil { if f.nameDrop.Match(key) { return false } } 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 { if f.fieldPass != nil { if f.fieldPass.Match(key) { return true } return false } if f.fieldDrop != nil { if f.fieldDrop.Match(key) { return false } } 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 { tagPass := 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 } tagDrop := 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 tagPass(f) && tagDrop(f) } else if f.TagPass != nil { return tagPass(f) } else if f.TagDrop != nil { return tagDrop(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) } } } }