Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

r/cloudwatch_log_metric_filter - add unit #19804

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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