diff --git a/config.go b/config.go index a4e0e43a5d9ba..adff385af75a2 100644 --- a/config.go +++ b/config.go @@ -43,6 +43,10 @@ type Config struct { func (c *Config) Plugins() map[string]*ast.Table { return c.plugins } +type TagFilter struct { + Name string + Filter []string +} // Outputs returns the configured outputs as a map of name -> output toml func (c *Config) Outputs() map[string]*ast.Table { @@ -50,17 +54,21 @@ func (c *Config) Outputs() map[string]*ast.Table { } // ConfiguredPlugin containing a name, interval, and drop/pass prefix lists +// Also lists the tags to filter type ConfiguredPlugin struct { Name string Drop []string Pass []string + TagDrop []TagFilter + + TagPass []TagFilter Interval time.Duration } // ShouldPass returns true if the metric should pass, false if should drop -func (cp *ConfiguredPlugin) ShouldPass(measurement string) bool { +func (cp *ConfiguredPlugin) ShouldPass(measurement string, tags map[string]string) bool { if cp.Pass != nil { for _, pat := range cp.Pass { if strings.HasPrefix(measurement, pat) { @@ -81,16 +89,41 @@ func (cp *ConfiguredPlugin) ShouldPass(measurement string) bool { return true } - return true + if cp.TagPass != nil { + for _, pat := range cp.TagPass { + if tagval, ok := tags[pat.Name]; ok { + for _, filter := range pat.Filter { + if filter == tagval { + return true + } + } + } + } + return false + } + + + if cp.TagDrop != nil { + for _, pat := range cp.TagDrop { + if tagval, ok := tags[pat.Name]; ok { + for _, filter := range pat.Filter { + if filter == tagval { + return false + } + } + } + } + return true + } + + return nil } // ApplyOutput loads the toml config into the given interface func (c *Config) ApplyOutput(name string, v interface{}) error { if c.outputs[name] != nil { return toml.UnmarshalTable(c.outputs[name], v) - } - - return nil + } } // ApplyAgent loads the toml config into the given interface @@ -147,9 +180,47 @@ func (c *Config) ApplyPlugin(name string, v interface{}) (*ConfiguredPlugin, err } } + if node, ok := tbl.Fields["tagpass"]; ok { + if subtbl, ok := node.(*ast.Table); ok { + for name, val := range subtbl.Fields { + if kv, ok := val.(*ast.KeyValue); ok { + tagfilter := &TagFilter{Name: name} + if ary, ok := kv.Value.(*ast.Array); ok { + for _, elem := range ary.Value { + if str, ok := elem.(*ast.String); ok { + tagfilter.Filter = append(tagfilter.Filter, str.Value) + } + } + } + cp.TagPass = append(cp.TagPass, *tagfilter) + } + } + } + } + + if node, ok := tbl.Fields["tagdrop"]; ok { + if subtbl, ok := node.(*ast.Table); ok { + for name, val := range subtbl.Fields { + if kv, ok := val.(*ast.KeyValue); ok { + tagfilter := &TagFilter{Name: name} + if ary, ok := kv.Value.(*ast.Array); ok { + for _, elem := range ary.Value { + if str, ok := elem.(*ast.String); ok { + tagfilter.Filter = append(tagfilter.Filter, str.Value) + } + } + } + cp.TagDrop = append(cp.TagDrop, *tagfilter) + } + } + } + } + delete(tbl.Fields, "drop") delete(tbl.Fields, "pass") delete(tbl.Fields, "interval") + delete(tbl.Fields, "tagdrop") + delete(tbl.Fields, "tagpass") return cp, toml.UnmarshalTable(tbl, v) } @@ -227,6 +298,20 @@ func LoadConfig(path string) (*Config, error) { return c, nil } +// ListTags returns a string of tags specified in the config, +// line-protocol style +func (c *Config) ListTags() string { + var tags []string + + for k, v := range c.Tags { + tags = append(tags, fmt.Sprintf("%s=%s", k, v)) + } + + sort.Strings(tags) + + return strings.Join(tags, " ") +} + type hasConfig interface { BasicConfig() string } @@ -281,6 +366,9 @@ database = "telegraf" # required. # Set the user agent for the POSTs (can be useful for log differentiation) # user_agent = "telegraf" +# Tags can also be specified via a normal map, but only one form at a time: + +# [influxdb.tags] # tags = { "dc" = "us-east-1" } # Configuration for telegraf itself