From 6c6dd69b7425ac6d3585cd9a1567fd2e07b07fe6 Mon Sep 17 00:00:00 2001 From: Jeff Nickoloff Date: Mon, 28 Aug 2017 16:56:03 -0700 Subject: [PATCH] Added CloudWatch metric constraint validation (#3183) --- plugins/outputs/cloudwatch/cloudwatch.go | 19 +++++++++++++ plugins/outputs/cloudwatch/cloudwatch_test.go | 27 ++++++++++++++----- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/plugins/outputs/cloudwatch/cloudwatch.go b/plugins/outputs/cloudwatch/cloudwatch.go index 4eb2706a3..a04e86cde 100644 --- a/plugins/outputs/cloudwatch/cloudwatch.go +++ b/plugins/outputs/cloudwatch/cloudwatch.go @@ -193,6 +193,25 @@ func BuildMetricDatum(point telegraf.Metric) []*cloudwatch.MetricDatum { continue } + // Do CloudWatch boundary checking + // Constraints at: http://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_MetricDatum.html + if math.IsNaN(value) { + datums = datums[:len(datums)-1] + continue + } + if math.IsInf(value, 0) { + datums = datums[:len(datums)-1] + continue + } + if value > 0 && value < float64(8.515920e-109) { + datums = datums[:len(datums)-1] + continue + } + if value > float64(1.174271e+108) { + datums = datums[:len(datums)-1] + continue + } + datums[i] = &cloudwatch.MetricDatum{ MetricName: aws.String(strings.Join([]string{point.Name(), k}, "_")), Value: aws.Float64(value), diff --git a/plugins/outputs/cloudwatch/cloudwatch_test.go b/plugins/outputs/cloudwatch/cloudwatch_test.go index 06b41fa21..8ab60de2f 100644 --- a/plugins/outputs/cloudwatch/cloudwatch_test.go +++ b/plugins/outputs/cloudwatch/cloudwatch_test.go @@ -1,6 +1,8 @@ package cloudwatch import ( + "fmt" + "math" "sort" "testing" @@ -51,22 +53,32 @@ func TestBuildDimensions(t *testing.T) { func TestBuildMetricDatums(t *testing.T) { assert := assert.New(t) + zero := 0.0 validMetrics := []telegraf.Metric{ testutil.TestMetric(1), testutil.TestMetric(int32(1)), testutil.TestMetric(int64(1)), testutil.TestMetric(float64(1)), + testutil.TestMetric(float64(0)), + testutil.TestMetric(math.Copysign(zero, -1)), // the CW documentation does not call out -0 as rejected + testutil.TestMetric(float64(8.515920e-109)), + testutil.TestMetric(float64(1.174271e+108)), // largest should be 1.174271e+108 testutil.TestMetric(true), } - + invalidMetrics := []telegraf.Metric{ + testutil.TestMetric("Foo"), + testutil.TestMetric(math.Log(-1.0)), + testutil.TestMetric(float64(8.515919e-109)), // smallest should be 8.515920e-109 + testutil.TestMetric(float64(1.174272e+108)), // largest should be 1.174271e+108 + } for _, point := range validMetrics { datums := BuildMetricDatum(point) - assert.Equal(1, len(datums), "Valid type should create a Datum") + assert.Equal(1, len(datums), fmt.Sprintf("Valid point should create a Datum {value: %v}", point)) + } + for _, point := range invalidMetrics { + datums := BuildMetricDatum(point) + assert.Equal(0, len(datums), fmt.Sprintf("Valid point should not create a Datum {value: %v}", point)) } - - nonValidPoint := testutil.TestMetric("Foo") - - assert.Equal(0, len(BuildMetricDatum(nonValidPoint)), "Invalid type should not create a Datum") } func TestPartitionDatums(t *testing.T) { @@ -78,10 +90,13 @@ func TestPartitionDatums(t *testing.T) { Value: aws.Float64(1), } + zeroDatum := []*cloudwatch.MetricDatum{} oneDatum := []*cloudwatch.MetricDatum{&testDatum} twoDatum := []*cloudwatch.MetricDatum{&testDatum, &testDatum} threeDatum := []*cloudwatch.MetricDatum{&testDatum, &testDatum, &testDatum} + assert.Equal([][]*cloudwatch.MetricDatum{}, PartitionDatums(2, zeroDatum)) + assert.Equal([][]*cloudwatch.MetricDatum{oneDatum}, PartitionDatums(2, oneDatum)) assert.Equal([][]*cloudwatch.MetricDatum{oneDatum}, PartitionDatums(2, oneDatum)) assert.Equal([][]*cloudwatch.MetricDatum{twoDatum}, PartitionDatums(2, twoDatum)) assert.Equal([][]*cloudwatch.MetricDatum{twoDatum, oneDatum}, PartitionDatums(2, threeDatum))