Skip to content

Commit

Permalink
Merge pull request #19804 from DrFaust92/r/cloudwatchlogs_metric_filt…
Browse files Browse the repository at this point in the history
…er_unit

r/cloudwatch_log_metric_filter - add `unit`
  • Loading branch information
ewbankkit committed Jun 16, 2021
2 parents 244e325 + f90bfec commit cb078b6
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 66 deletions.
3 changes: 3 additions & 0 deletions .changelog/19804.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_cloudwatch_log_metric_filter: Add support for `unit` in the `metric_transformation` block.
```
73 changes: 66 additions & 7 deletions aws/resource_aws_cloudwatch_log_metric_filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package aws
import (
"fmt"
"log"
"strconv"
"strings"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand Down Expand Up @@ -83,6 +83,12 @@ func resourceAwsCloudWatchLogMetricFilter() *schema.Resource {
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"unit": {
Type: schema.TypeString,
Optional: true,
Default: cloudwatchlogs.StandardUnitNone,
ValidateFunc: validation.StringInSlice(cloudwatchlogs.StandardUnit_Values(), false),
},
},
},
},
Expand Down Expand Up @@ -115,7 +121,7 @@ func resourceAwsCloudWatchLogMetricFilterUpdate(d *schema.ResourceData, meta int
log.Printf("[DEBUG] Creating/Updating CloudWatch Log Metric Filter: %s", input)
_, err := conn.PutMetricFilter(&input)
if err != nil {
return fmt.Errorf("Creating/Updating CloudWatch Log Metric Filter failed: %s", err)
return fmt.Errorf("Creating/Updating CloudWatch Log Metric Filter failed: %w", err)
}

d.SetId(d.Get("name").(string))
Expand All @@ -137,15 +143,15 @@ func resourceAwsCloudWatchLogMetricFilterRead(d *schema.ResourceData, meta inter
return nil
}

return fmt.Errorf("Failed reading CloudWatch Log Metric Filter: %s", err)
return fmt.Errorf("Failed reading CloudWatch Log Metric Filter: %w", err)
}

log.Printf("[DEBUG] Found CloudWatch Log Metric Filter: %s", mf)

d.Set("name", mf.FilterName)
d.Set("pattern", mf.FilterPattern)
if err := d.Set("metric_transformation", flattenCloudWatchLogMetricTransformations(mf.MetricTransformations)); err != nil {
return fmt.Errorf("error setting metric_transformation: %s", err)
return fmt.Errorf("error setting metric_transformation: %w", err)
}

return nil
Expand All @@ -162,7 +168,7 @@ func lookupCloudWatchLogMetricFilter(conn *cloudwatchlogs.CloudWatchLogs,
log.Printf("[DEBUG] Reading CloudWatch Log Metric Filter: %s", input)
resp, err := conn.DescribeMetricFilters(&input)
if err != nil {
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ResourceNotFoundException" {
if isAWSErr(err, cloudwatchlogs.ErrCodeResourceNotFoundException, "") {
return nil, &resource.NotFoundError{
Message: fmt.Sprintf("CloudWatch Log Metric Filter %q / %q not found via"+
" initial DescribeMetricFilters call", name, logGroupName),
Expand All @@ -171,7 +177,7 @@ func lookupCloudWatchLogMetricFilter(conn *cloudwatchlogs.CloudWatchLogs,
}
}

return nil, fmt.Errorf("Failed describing CloudWatch Log Metric Filter: %s", err)
return nil, fmt.Errorf("Failed describing CloudWatch Log Metric Filter: %w", err)
}

for _, mf := range resp.MetricFilters {
Expand Down Expand Up @@ -208,7 +214,7 @@ func resourceAwsCloudWatchLogMetricFilterDelete(d *schema.ResourceData, meta int
log.Printf("[INFO] Deleting CloudWatch Log Metric Filter: %s", d.Id())
_, err := conn.DeleteMetricFilter(&input)
if err != nil {
return fmt.Errorf("Error deleting CloudWatch Log Metric Filter: %s", err)
return fmt.Errorf("Error deleting CloudWatch Log Metric Filter: %w", err)
}
log.Println("[INFO] CloudWatch Log Metric Filter deleted")

Expand All @@ -227,3 +233,56 @@ func resourceAwsCloudWatchLogMetricFilterImport(d *schema.ResourceData, meta int
d.SetId(name)
return []*schema.ResourceData{d}, nil
}

func expandCloudWatchLogMetricTransformations(m map[string]interface{}) []*cloudwatchlogs.MetricTransformation {
transformation := cloudwatchlogs.MetricTransformation{
MetricName: aws.String(m["name"].(string)),
MetricNamespace: aws.String(m["namespace"].(string)),
MetricValue: aws.String(m["value"].(string)),
}

if m["default_value"].(string) != "" {
value, _ := strconv.ParseFloat(m["default_value"].(string), 64)
transformation.DefaultValue = aws.Float64(value)
}

if dims := m["dimensions"].(map[string]interface{}); len(dims) > 0 {
transformation.Dimensions = expandStringMap(dims)
}

if v, ok := m["unit"].(string); ok && v != "" {
transformation.Unit = aws.String(v)
}

return []*cloudwatchlogs.MetricTransformation{&transformation}
}

func flattenCloudWatchLogMetricTransformations(ts []*cloudwatchlogs.MetricTransformation) []interface{} {
mts := make([]interface{}, 0)
m := make(map[string]interface{})

transform := ts[0]
m["name"] = aws.StringValue(transform.MetricName)
m["namespace"] = aws.StringValue(transform.MetricNamespace)
m["value"] = aws.StringValue(transform.MetricValue)

if transform.DefaultValue == nil {
m["default_value"] = ""
} else {
m["default_value"] = strconv.FormatFloat(aws.Float64Value(transform.DefaultValue), 'f', -1, 64)
}

if dims := transform.Dimensions; len(dims) > 0 {
m["dimensions"] = pointersMapToStringList(dims)
} else {
m["dimensions"] = nil
}

if transform.Unit != nil {
m["unit"] = aws.StringValue(transform.Unit)
}

mts = append(mts, m)

return mts
}
74 changes: 60 additions & 14 deletions aws/resource_aws_cloudwatch_log_metric_filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
func TestAccAWSCloudWatchLogMetricFilter_basic(t *testing.T) {
var mf cloudwatchlogs.MetricFilter
rInt := acctest.RandInt()
resourceName := "aws_cloudwatch_log_metric_filter.foobar"
resourceName := "aws_cloudwatch_log_metric_filter.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Expand Down Expand Up @@ -98,7 +98,53 @@ func TestAccAWSCloudWatchLogMetricFilter_basic(t *testing.T) {
},
{
Config: testAccAWSCloudwatchLogMetricFilterConfigMany(rInt),
Check: testAccCheckCloudwatchLogMetricFilterManyExist("aws_cloudwatch_log_metric_filter.count_dracula", &mf),
Check: testAccCheckCloudwatchLogMetricFilterManyExist("aws_cloudwatch_log_metric_filter.test", &mf),
},
},
})
}

func TestAccAWSCloudWatchLogMetricFilter_disappears(t *testing.T) {
var mf cloudwatchlogs.MetricFilter
rInt := acctest.RandInt()
resourceName := "aws_cloudwatch_log_metric_filter.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, cloudwatchlogs.EndpointsID),
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCloudWatchLogMetricFilterDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSCloudWatchLogMetricFilterConfig(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudWatchLogMetricFilterExists(resourceName, &mf),
testAccCheckResourceDisappears(testAccProvider, resourceAwsCloudWatchLogMetricFilter(), resourceName),
),
ExpectNonEmptyPlan: true,
},
},
})
}

func TestAccAWSCloudWatchLogMetricFilter_disappears_logGroup(t *testing.T) {
var mf cloudwatchlogs.MetricFilter
rInt := acctest.RandInt()
resourceName := "aws_cloudwatch_log_metric_filter.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, cloudwatchlogs.EndpointsID),
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCloudWatchLogMetricFilterDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSCloudWatchLogMetricFilterConfig(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudWatchLogMetricFilterExists(resourceName, &mf),
testAccCheckResourceDisappears(testAccProvider, resourceAwsCloudWatchLogGroup(), "aws_cloudwatch_log_group.test"),
),
ExpectNonEmptyPlan: true,
},
},
})
Expand Down Expand Up @@ -233,10 +279,10 @@ func testAccCheckCloudwatchLogMetricFilterManyExist(basename string, mf *cloudwa

func testAccAWSCloudWatchLogMetricFilterConfig(rInt int) string {
return fmt.Sprintf(`
resource "aws_cloudwatch_log_metric_filter" "foobar" {
resource "aws_cloudwatch_log_metric_filter" "test" {
name = "MyAppAccessCount-%d"
pattern = ""
log_group_name = aws_cloudwatch_log_group.dada.name
log_group_name = aws_cloudwatch_log_group.test.name
metric_transformation {
name = "EventCount"
Expand All @@ -245,23 +291,23 @@ resource "aws_cloudwatch_log_metric_filter" "foobar" {
}
}
resource "aws_cloudwatch_log_group" "dada" {
resource "aws_cloudwatch_log_group" "test" {
name = "MyApp/access-%d.log"
}
`, rInt, rInt)
}

func testAccAWSCloudWatchLogMetricFilterConfigModified(rInt int) string {
return fmt.Sprintf(`
resource "aws_cloudwatch_log_metric_filter" "foobar" {
resource "aws_cloudwatch_log_metric_filter" "test" {
name = "MyAppAccessCount-%d"
pattern = <<PATTERN
{ $.errorCode = "AccessDenied" }
PATTERN
log_group_name = aws_cloudwatch_log_group.dada.name
log_group_name = aws_cloudwatch_log_group.test.name
metric_transformation {
name = "AccessDeniedCount"
Expand All @@ -271,23 +317,23 @@ PATTERN
}
}
resource "aws_cloudwatch_log_group" "dada" {
resource "aws_cloudwatch_log_group" "test" {
name = "MyApp/access-%d.log"
}
`, rInt, rInt)
}

func testAccAWSCloudWatchLogMetricFilterConfigModifiedWithDimensions(rInt int) string {
return fmt.Sprintf(`
resource "aws_cloudwatch_log_metric_filter" "foobar" {
resource "aws_cloudwatch_log_metric_filter" "test" {
name = "MyAppAccessCount-%d"
pattern = <<PATTERN
{ $.errorCode = "AccessDenied" }
PATTERN
log_group_name = aws_cloudwatch_log_group.dada.name
log_group_name = aws_cloudwatch_log_group.test.name
metric_transformation {
name = "AccessDeniedCount"
Expand All @@ -300,19 +346,19 @@ PATTERN
}
}
resource "aws_cloudwatch_log_group" "dada" {
resource "aws_cloudwatch_log_group" "test" {
name = "MyApp/access-%d.log"
}
`, rInt, rInt)
}

func testAccAWSCloudwatchLogMetricFilterConfigMany(rInt int) string {
return fmt.Sprintf(`
resource "aws_cloudwatch_log_metric_filter" "count_dracula" {
resource "aws_cloudwatch_log_metric_filter" "test" {
count = 15
name = "MyAppCountLog-${count.index}-%d"
pattern = "count ${count.index}"
log_group_name = aws_cloudwatch_log_group.mama.name
log_group_name = aws_cloudwatch_log_group.test.name
metric_transformation {
name = "CountDracula-${count.index}"
Expand All @@ -321,7 +367,7 @@ resource "aws_cloudwatch_log_metric_filter" "count_dracula" {
}
}
resource "aws_cloudwatch_log_group" "mama" {
resource "aws_cloudwatch_log_group" "test" {
name = "MyApp/count-log-%d.log"
}
`, rInt, rInt)
Expand Down
45 changes: 0 additions & 45 deletions aws/structure.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"github.com/aws/aws-sdk-go/service/appmesh"
"github.com/aws/aws-sdk-go/service/autoscaling"
"github.com/aws/aws-sdk-go/service/cloudformation"
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
"github.com/aws/aws-sdk-go/service/cognitoidentity"
"github.com/aws/aws-sdk-go/service/cognitoidentityprovider"
"github.com/aws/aws-sdk-go/service/configservice"
Expand Down Expand Up @@ -1656,50 +1655,6 @@ func expandApiGatewayMethodParametersOperations(d *schema.ResourceData, key stri
return operations
}

func expandCloudWatchLogMetricTransformations(m map[string]interface{}) []*cloudwatchlogs.MetricTransformation {
transformation := cloudwatchlogs.MetricTransformation{
MetricName: aws.String(m["name"].(string)),
MetricNamespace: aws.String(m["namespace"].(string)),
MetricValue: aws.String(m["value"].(string)),
}

if m["default_value"].(string) != "" {
value, _ := strconv.ParseFloat(m["default_value"].(string), 64)
transformation.DefaultValue = aws.Float64(value)
}

if dims := m["dimensions"].(map[string]interface{}); len(dims) > 0 {
transformation.Dimensions = expandStringMap(dims)
}

return []*cloudwatchlogs.MetricTransformation{&transformation}
}

func flattenCloudWatchLogMetricTransformations(ts []*cloudwatchlogs.MetricTransformation) []interface{} {
mts := make([]interface{}, 0)
m := make(map[string]interface{})

m["name"] = aws.StringValue(ts[0].MetricName)
m["namespace"] = aws.StringValue(ts[0].MetricNamespace)
m["value"] = aws.StringValue(ts[0].MetricValue)

if ts[0].DefaultValue == nil {
m["default_value"] = ""
} else {
m["default_value"] = strconv.FormatFloat(aws.Float64Value(ts[0].DefaultValue), 'f', -1, 64)
}

if dims := ts[0].Dimensions; len(dims) > 0 {
m["dimensions"] = pointersMapToStringList(dims)
} else {
m["dimensions"] = nil
}

mts = append(mts, m)

return mts
}

func flattenBeanstalkAsg(list []*elasticbeanstalk.AutoScalingGroup) []string {
strs := make([]string, 0, len(list))
for _, r := range list {
Expand Down
1 change: 1 addition & 0 deletions website/docs/r/cloudwatch_log_metric_filter.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ The `metric_transformation` block supports the following arguments:
* `value` - (Required) What to publish to the metric. For example, if you're counting the occurrences of a particular term like "Error", the value will be "1" for each occurrence. If you're counting the bytes transferred the published value will be the value in the log event.
* `default_value` - (Optional) The value to emit when a filter pattern does not match a log event. Conflicts with `dimensions`.
* `dimensions` - (Optional) Map of fields to use as dimensions for the metric. Up to 3 dimensions are allowed. Conflicts with `default_value`.
* `unit` - (Optional) The unit to assign to the metric. If you omit this, the unit is set as `None`.

## Attributes Reference

Expand Down

0 comments on commit cb078b6

Please sign in to comment.