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
# ## must be specified in order to retrieve the metric statistics.
# ## 'value' has wildcard / 'glob' matching support such as `p-*`.
# [[inputs.cloudwatch.metrics.dimensions]]
# name = "LoadBalancerName"
# value = "p-example"

View File

@ -66,8 +66,9 @@ type Metric struct {
// Dimension defines a simplified Cloudwatch dimension (provides metric filtering).
type Dimension struct {
Name string `toml:"name"`
Value string `toml:"value"`
Name string `toml:"name"`
Value string `toml:"value"`
valueMatcher filter.Filter
}
// 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
# ## must be specified in order to retrieve the metric statistics.
# ## 'value' has wildcard / 'glob' matching support. such as 'p-*'.
# [[inputs.cloudwatch.metrics.dimensions]]
# name = "LoadBalancerName"
# value = "p-example"
@ -294,6 +296,18 @@ func (c *CloudWatch) initializeCloudWatch() error {
loglevel := aws.LogOff
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
}
@ -633,7 +647,7 @@ func (f *metricCache) isValid() bool {
func hasWildcard(dimensions []*Dimension) bool {
for _, d := range dimensions {
if d.Value == "" || d.Value == "*" {
if d.Value == "" || strings.ContainsAny(d.Value, "*?[") {
return true
}
}
@ -651,7 +665,7 @@ func isSelected(name string, metric *cloudwatch.Metric, dimensions []*Dimension)
selected := false
for _, d2 := range metric.Dimensions {
if d.Name == *d2.Name {
if d.Value == "" || d.Value == "*" || d.Value == *d2.Value {
if d.Value == "" || d.valueMatcher.Match(*d2.Value) {
selected = true
}
}

View File

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