Add Glob / Wildcard support to Cloudwatch input for 'Dimensions' configuration (#9136)

I believe this will resolve #4046
This commit is contained in:
David Bennett 2021-04-20 17:29:58 -04:00 committed by GitHub
parent 243488c266
commit e29bca7419
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 23 additions and 6 deletions

View File

@ -101,6 +101,7 @@ API endpoint. In the following order the plugin will attempt to authenticate.
# #
# ## Dimension filters for Metric. All dimensions defined for the metric names # ## Dimension filters for Metric. All dimensions defined for the metric names
# ## must be specified in order to retrieve the metric statistics. # ## must be specified in order to retrieve the metric statistics.
# ## 'value' has wildcard / 'glob' matching support such as `p-*`.
# [[inputs.cloudwatch.metrics.dimensions]] # [[inputs.cloudwatch.metrics.dimensions]]
# name = "LoadBalancerName" # name = "LoadBalancerName"
# value = "p-example" # value = "p-example"

View File

@ -66,8 +66,9 @@ type Metric struct {
// Dimension defines a simplified Cloudwatch dimension (provides metric filtering). // Dimension defines a simplified Cloudwatch dimension (provides metric filtering).
type Dimension struct { type Dimension struct {
Name string `toml:"name"` Name string `toml:"name"`
Value string `toml:"value"` Value string `toml:"value"`
valueMatcher filter.Filter
} }
// metricCache caches metrics, their filters, and generated queries. // metricCache caches metrics, their filters, and generated queries.
@ -170,6 +171,7 @@ func (c *CloudWatch) SampleConfig() string {
# #
# ## Dimension filters for Metric. All dimensions defined for the metric names # ## Dimension filters for Metric. All dimensions defined for the metric names
# ## must be specified in order to retrieve the metric statistics. # ## must be specified in order to retrieve the metric statistics.
# ## 'value' has wildcard / 'glob' matching support. such as 'p-*'.
# [[inputs.cloudwatch.metrics.dimensions]] # [[inputs.cloudwatch.metrics.dimensions]]
# name = "LoadBalancerName" # name = "LoadBalancerName"
# value = "p-example" # value = "p-example"
@ -294,6 +296,18 @@ func (c *CloudWatch) initializeCloudWatch() error {
loglevel := aws.LogOff loglevel := aws.LogOff
c.client = cloudwatch.New(configProvider, cfg.WithLogLevel(loglevel)) c.client = cloudwatch.New(configProvider, cfg.WithLogLevel(loglevel))
// Initialize regex matchers for each Dimension value.
for _, m := range c.Metrics {
for _, dimension := range m.Dimensions {
matcher, err := filter.NewIncludeExcludeFilter([]string{dimension.Value}, nil)
if err != nil {
return err
}
dimension.valueMatcher = matcher
}
}
return nil return nil
} }
@ -633,7 +647,7 @@ func (f *metricCache) isValid() bool {
func hasWildcard(dimensions []*Dimension) bool { func hasWildcard(dimensions []*Dimension) bool {
for _, d := range dimensions { for _, d := range dimensions {
if d.Value == "" || d.Value == "*" { if d.Value == "" || strings.ContainsAny(d.Value, "*?[") {
return true return true
} }
} }
@ -651,7 +665,7 @@ func isSelected(name string, metric *cloudwatch.Metric, dimensions []*Dimension)
selected := false selected := false
for _, d2 := range metric.Dimensions { for _, d2 := range metric.Dimensions {
if d.Name == *d2.Name { if d.Name == *d2.Name {
if d.Value == "" || d.Value == "*" || d.Value == *d2.Value { if d.Value == "" || d.valueMatcher.Match(*d2.Value) {
selected = true selected = true
} }
} }

View File

@ -201,16 +201,18 @@ func TestSelectMetrics(t *testing.T) {
Dimensions: []*Dimension{ Dimensions: []*Dimension{
{ {
Name: "LoadBalancerName", Name: "LoadBalancerName",
Value: "*", Value: "lb*",
}, },
{ {
Name: "AvailabilityZone", Name: "AvailabilityZone",
Value: "*", Value: "us-east*",
}, },
}, },
}, },
}, },
} }
err := c.initializeCloudWatch()
assert.NoError(t, err)
c.client = &mockSelectMetricsCloudWatchClient{} c.client = &mockSelectMetricsCloudWatchClient{}
filtered, err := getFilteredMetrics(c) filtered, err := getFilteredMetrics(c)
// We've asked for 2 (out of 4) metrics, over all 3 load balancers in all 2 // We've asked for 2 (out of 4) metrics, over all 3 load balancers in all 2