github.com/influxdata/telegraf@v1.30.3/filter/filter.go (about)

     1  package filter
     2  
     3  import (
     4  	"strings"
     5  
     6  	"github.com/gobwas/glob"
     7  )
     8  
     9  type Filter interface {
    10  	Match(string) bool
    11  }
    12  
    13  // Compile takes a list of string filters and returns a Filter interface
    14  // for matching a given string against the filter list. The filter list
    15  // supports glob matching with separators too, ie:
    16  //
    17  //	f, _ := Compile([]string{"cpu", "mem", "net*"})
    18  //	f.Match("cpu")     // true
    19  //	f.Match("network") // true
    20  //	f.Match("memory")  // false
    21  //
    22  // separators are only to be used for globbing filters, ie:
    23  //
    24  //	f, _ := Compile([]string{"cpu.*.count"}, '.')
    25  //	f.Match("cpu.count")     // false
    26  //	f.Match("cpu.measurement.count") // true
    27  //	f.Match("cpu.field.measurement.count")  // false
    28  //
    29  // Compile will return nil if the filter list is empty.
    30  func Compile(filters []string, separators ...rune) (Filter, error) {
    31  	// return if there is nothing to compile
    32  	if len(filters) == 0 {
    33  		return nil, nil
    34  	}
    35  
    36  	// check if we can compile a non-glob filter
    37  	noGlob := len(separators) == 0
    38  	for _, filter := range filters {
    39  		if hasMeta(filter) {
    40  			noGlob = false
    41  			break
    42  		}
    43  	}
    44  
    45  	switch {
    46  	case noGlob:
    47  		// return non-globbing filter if not needed.
    48  		return compileFilterNoGlob(filters), nil
    49  	case len(filters) == 1:
    50  		return glob.Compile(filters[0], separators...)
    51  	default:
    52  		return glob.Compile("{"+strings.Join(filters, ",")+"}", separators...)
    53  	}
    54  }
    55  
    56  func MustCompile(filters []string, separators ...rune) Filter {
    57  	f, err := Compile(filters, separators...)
    58  	if err != nil {
    59  		panic(err)
    60  	}
    61  	return f
    62  }
    63  
    64  // hasMeta reports whether path contains any magic glob characters.
    65  func hasMeta(s string) bool {
    66  	return strings.ContainsAny(s, "*?[")
    67  }
    68  
    69  type filter struct {
    70  	m map[string]struct{}
    71  }
    72  
    73  func (f *filter) Match(s string) bool {
    74  	_, ok := f.m[s]
    75  	return ok
    76  }
    77  
    78  type filtersingle struct {
    79  	s string
    80  }
    81  
    82  func (f *filtersingle) Match(s string) bool {
    83  	return f.s == s
    84  }
    85  
    86  func compileFilterNoGlob(filters []string) Filter {
    87  	if len(filters) == 1 {
    88  		return &filtersingle{s: filters[0]}
    89  	}
    90  	out := filter{m: make(map[string]struct{})}
    91  	for _, filter := range filters {
    92  		out.m[filter] = struct{}{}
    93  	}
    94  	return &out
    95  }
    96  
    97  type IncludeExcludeFilter struct {
    98  	include        Filter
    99  	exclude        Filter
   100  	includeDefault bool
   101  	excludeDefault bool
   102  }
   103  
   104  func NewIncludeExcludeFilter(
   105  	include []string,
   106  	exclude []string,
   107  ) (Filter, error) {
   108  	return NewIncludeExcludeFilterDefaults(include, exclude, true, false)
   109  }
   110  
   111  func NewIncludeExcludeFilterDefaults(
   112  	include []string,
   113  	exclude []string,
   114  	includeDefault bool,
   115  	excludeDefault bool,
   116  ) (Filter, error) {
   117  	in, err := Compile(include)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  
   122  	ex, err := Compile(exclude)
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  
   127  	return &IncludeExcludeFilter{in, ex, includeDefault, excludeDefault}, nil
   128  }
   129  
   130  func (f *IncludeExcludeFilter) Match(s string) bool {
   131  	if f.include != nil {
   132  		if !f.include.Match(s) {
   133  			return false
   134  		}
   135  	} else if !f.includeDefault {
   136  		return false
   137  	}
   138  
   139  	if f.exclude != nil {
   140  		if f.exclude.Match(s) {
   141  			return false
   142  		}
   143  	} else if f.excludeDefault {
   144  		return false
   145  	}
   146  
   147  	return true
   148  }