Cloudwatch input plugin

This commit is contained in:
Vebjorn Ljosa 2016-03-29 10:58:33 -04:00
parent b1cfb1afe4
commit bd4843d5f2
5 changed files with 492 additions and 0 deletions

5
Godeps
View File

@ -3,6 +3,7 @@ github.com/Shopify/sarama 8aadb476e66ca998f2f6bb3c993e9a2daa3666b9
github.com/Sirupsen/logrus 219c8cb75c258c552e999735be6df753ffc7afdc github.com/Sirupsen/logrus 219c8cb75c258c552e999735be6df753ffc7afdc
github.com/amir/raidman 53c1b967405155bfc8758557863bf2e14f814687 github.com/amir/raidman 53c1b967405155bfc8758557863bf2e14f814687
github.com/aws/aws-sdk-go 13a12060f716145019378a10e2806c174356b857 github.com/aws/aws-sdk-go 13a12060f716145019378a10e2806c174356b857
github.com/azer/snakecase 7a41237eda4ca971bdcbba00d459901be8221a19
github.com/beorn7/perks 3ac7bf7a47d159a033b107610db8a1b6575507a4 github.com/beorn7/perks 3ac7bf7a47d159a033b107610db8a1b6575507a4
github.com/cenkalti/backoff 4dc77674aceaabba2c7e3da25d4c823edfb73f99 github.com/cenkalti/backoff 4dc77674aceaabba2c7e3da25d4c823edfb73f99
github.com/couchbase/go-couchbase cb664315a324d87d19c879d9cc67fda6be8c2ac1 github.com/couchbase/go-couchbase cb664315a324d87d19c879d9cc67fda6be8c2ac1
@ -13,6 +14,7 @@ github.com/davecgh/go-spew 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d
github.com/eapache/go-resiliency b86b1ec0dd4209a588dc1285cdd471e73525c0b3 github.com/eapache/go-resiliency b86b1ec0dd4209a588dc1285cdd471e73525c0b3
github.com/eapache/queue ded5959c0d4e360646dc9e9908cff48666781367 github.com/eapache/queue ded5959c0d4e360646dc9e9908cff48666781367
github.com/fsouza/go-dockerclient a49c8269a6899cae30da1f8a4b82e0ce945f9967 github.com/fsouza/go-dockerclient a49c8269a6899cae30da1f8a4b82e0ce945f9967
github.com/go-ini/ini 776aa739ce9373377cd16f526cdf06cb4c89b40f
github.com/go-sql-driver/mysql 1fca743146605a172a266e1654e01e5cd5669bee github.com/go-sql-driver/mysql 1fca743146605a172a266e1654e01e5cd5669bee
github.com/golang/protobuf 552c7b9542c194800fd493123b3798ef0a832032 github.com/golang/protobuf 552c7b9542c194800fd493123b3798ef0a832032
github.com/golang/snappy 427fb6fc07997f43afa32f35e850833760e489a7 github.com/golang/snappy 427fb6fc07997f43afa32f35e850833760e489a7
@ -23,6 +25,7 @@ github.com/hailocab/go-hostpool e80d13ce29ede4452c43dea11e79b9bc8a15b478
github.com/influxdata/config b79f6829346b8d6e78ba73544b1e1038f1f1c9da github.com/influxdata/config b79f6829346b8d6e78ba73544b1e1038f1f1c9da
github.com/influxdata/influxdb e3fef5593c21644f2b43af55d6e17e70910b0e48 github.com/influxdata/influxdb e3fef5593c21644f2b43af55d6e17e70910b0e48
github.com/influxdata/toml af4df43894b16e3fd2b788d01bd27ad0776ef2d0 github.com/influxdata/toml af4df43894b16e3fd2b788d01bd27ad0776ef2d0
github.com/jmespath/go-jmespath 0b12d6b521d83fc7f755e7cfc1b1fbdd35a01a74
github.com/klauspost/crc32 19b0b332c9e4516a6370a0456e6182c3b5036720 github.com/klauspost/crc32 19b0b332c9e4516a6370a0456e6182c3b5036720
github.com/lib/pq e182dc4027e2ded4b19396d638610f2653295f36 github.com/lib/pq e182dc4027e2ded4b19396d638610f2653295f36
github.com/matttproud/golang_protobuf_extensions d0c3fe89de86839aecf2e0579c40ba3bb336a453 github.com/matttproud/golang_protobuf_extensions d0c3fe89de86839aecf2e0579c40ba3bb336a453
@ -32,6 +35,7 @@ github.com/naoina/go-stringutil 6b638e95a32d0c1131db0e7fe83775cbea4a0d0b
github.com/nats-io/nats b13fc9d12b0b123ebc374e6b808c6228ae4234a3 github.com/nats-io/nats b13fc9d12b0b123ebc374e6b808c6228ae4234a3
github.com/nats-io/nuid 4f84f5f3b2786224e336af2e13dba0a0a80b76fa github.com/nats-io/nuid 4f84f5f3b2786224e336af2e13dba0a0a80b76fa
github.com/nsqio/go-nsq 0b80d6f05e15ca1930e0c5e1d540ed627e299980 github.com/nsqio/go-nsq 0b80d6f05e15ca1930e0c5e1d540ed627e299980
github.com/pmezard/go-difflib 792786c7400a136282c1664665ae0a8db921c6c2
github.com/prometheus/client_golang 18acf9993a863f4c4b40612e19cdd243e7c86831 github.com/prometheus/client_golang 18acf9993a863f4c4b40612e19cdd243e7c86831
github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6 github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6
github.com/prometheus/common e8eabff8812b05acf522b45fdcd725a785188e37 github.com/prometheus/common e8eabff8812b05acf522b45fdcd725a785188e37
@ -40,6 +44,7 @@ github.com/samuel/go-zookeeper 218e9c81c0dd8b3b18172b2bbfad92cc7d6db55f
github.com/shirou/gopsutil 1f32ce1bb380845be7f5d174ac641a2c592c0c42 github.com/shirou/gopsutil 1f32ce1bb380845be7f5d174ac641a2c592c0c42
github.com/soniah/gosnmp b1b4f885b12c5dcbd021c5cee1c904110de6db7d github.com/soniah/gosnmp b1b4f885b12c5dcbd021c5cee1c904110de6db7d
github.com/streadway/amqp b4f3ceab0337f013208d31348b578d83c0064744 github.com/streadway/amqp b4f3ceab0337f013208d31348b578d83c0064744
github.com/stretchr/objx 1a9d0bb9f541897e62256577b352fdbc1fb4fd94
github.com/stretchr/testify 1f4a1643a57e798696635ea4c126e9127adb7d3c github.com/stretchr/testify 1f4a1643a57e798696635ea4c126e9127adb7d3c
github.com/wvanbergen/kafka 1a8639a45164fcc245d5c7b4bd3ccfbd1a0ffbf3 github.com/wvanbergen/kafka 1a8639a45164fcc245d5c7b4bd3ccfbd1a0ffbf3
github.com/wvanbergen/kazoo-go 0f768712ae6f76454f987c3356177e138df258f8 github.com/wvanbergen/kazoo-go 0f768712ae6f76454f987c3356177e138df258f8

View File

@ -4,6 +4,7 @@ import (
_ "github.com/influxdata/telegraf/plugins/inputs/aerospike" _ "github.com/influxdata/telegraf/plugins/inputs/aerospike"
_ "github.com/influxdata/telegraf/plugins/inputs/apache" _ "github.com/influxdata/telegraf/plugins/inputs/apache"
_ "github.com/influxdata/telegraf/plugins/inputs/bcache" _ "github.com/influxdata/telegraf/plugins/inputs/bcache"
_ "github.com/influxdata/telegraf/plugins/inputs/cloudwatch"
_ "github.com/influxdata/telegraf/plugins/inputs/couchbase" _ "github.com/influxdata/telegraf/plugins/inputs/couchbase"
_ "github.com/influxdata/telegraf/plugins/inputs/couchdb" _ "github.com/influxdata/telegraf/plugins/inputs/couchdb"
_ "github.com/influxdata/telegraf/plugins/inputs/disque" _ "github.com/influxdata/telegraf/plugins/inputs/disque"

View File

@ -0,0 +1,85 @@
# Telegraf Plugin: Cloudwatch
## Configuration:
```
# Read metrics from Cloudwatch
[[inputs.cloudwatch]]
## AWS region
region = "us-east-1"
## specify namespaces as strings
namespaces = ["AWS/EC2", "AWS/DynamoDB"]
```
In each iteration, the cloudwatch input plugin queries Cloudwatch for
datapoints that are timestamped since the last iteration. (The first
iteration does not retrieve any data.)
Some AWS services post timepoints late, in the sense that new
timepoints are timestamped 23 minutes in the past. These points will
be missed by the cloudwatch input plugin if you run telegraf with a
short `interval`. Running telegraf with a longer interval, such as
`5m`, is recommended.
## Measurements:
Each namespace becomes a measurement, converted to snake_case and
prefixed with `cloudwatch`. For instance, the namespace `AWS/EC2`
becomes the measurement `cloudwatch_aws_ec2`, and the namespace
`AWS/DynamoDB` becomes the measurement `cloudwatch_aws_dynamo_db`.
### Fields
The cloudwatch input plugin retrieves all statistics from all
measurements in the specified namespaces. Each combination of metric
and statistic becomes a field. Metric names are converted to
snake_case. As an example, the metric `DiskWriteBytes` leads to the fields
* `disk_write_bytes_average`,
* `disk_write_bytes_maximum`,
* `disk_write_bytes_minimum`,
* `disk_write_bytes_sample_count`, and
* `disk_write_bytes_sum`.
To learn about the metrics for a particular Cloudwatch namespace, and
to see units and example data, see the AWS documentation for the
service in question, or explore using the AWS Console or AWS CLI.
### Tags
The cloudwatch input plugin tags the metrics it collects with the AWS
region (key: `region`) and the cloudwatch dimensions of the metric in
question. The dimensions names are converted to snake_keys, but the
values are left as is. As an example, the `AWS/DynamoDB` namespace has
a metric called `ThrottledRequest` with the dimensions `Operation` and
`TableName`. An example set of tags for this metric could be:
* `region`: `us-east-1`
* `operation`: `GetItem`
* `table_name`: `foo`
## Example output
```
$ ~/src/go/bin/telegraf -config ~/tmp/kapacitor/telegraf.conf -input-filter cloudwatch -debug
2016/03/29 10:47:15 Attempting connection to output: influxdb
2016/03/29 10:47:16 Successfully connected to output: influxdb
2016/03/29 10:47:16 Starting Telegraf (version 0.11.1-54-ge07c792)
2016/03/29 10:47:16 Loaded outputs: influxdb
2016/03/29 10:47:16 Loaded inputs: cloudwatch
2016/03/29 10:47:16 Tags enabled: host=vljosa-yieldbot.local
2016/03/29 10:47:16 Agent Config: Interval:5m0s, Debug:true, Quiet:false, Hostname:"vljosa-yieldbot.local", Flush Interval:11.228634593s
2016/03/29 10:50:00 Found 26 cloudwatch metrics
2016/03/29 10:50:00 Gathered metrics, (5m0s interval), from 1 inputs in 709.03259ms
> cloudwatch_aws_dynamo_db,host=vljosa-yieldbot.local,table_name=prd-platform-datomic-config consumed_write_capacity_units_average=1,consumed_write_capacity_units_maximum=1,consumed_write_capacity_units_minimum=1,consumed_write_capacity_units_sample_count=65,consumed_write_capacity_units_sum=65 1459263300548895733
> cloudwatch_aws_dynamo_db,host=vljosa-yieldbot.local,table_name=dev-platform-datomic-config consumed_read_capacity_units_average=1,consumed_read_capacity_units_maximum=1,consumed_read_capacity_units_minimum=1,consumed_read_capacity_units_sample_count=48,consumed_read_capacity_units_sum=48 1459263300642785107
> cloudwatch_aws_dynamo_db,host=vljosa-yieldbot.local,operation=PutItem,table_name=dev-platform-datomic-config successful_request_latency_average=8.910156727272726,successful_request_latency_maximum=26.477,successful_request_latency_minimum=4.243,successful_request_latency_sample_count=44,successful_request_latency_sum=392.04689599999995 1459263300688946255
> cloudwatch_aws_dynamo_db,host=vljosa-yieldbot.local,operation=GetItem,table_name=dev-platform-datomic-config successful_request_latency_average=6.982394130434781,successful_request_latency_maximum=38.125,successful_request_latency_minimum=2.156,successful_request_latency_sample_count=46,successful_request_latency_sum=321.19012999999995 1459263300727174463
> cloudwatch_aws_dynamo_db,host=vljosa-yieldbot.local,table_name=dev-platform-datomic-config consumed_write_capacity_units_average=1,consumed_write_capacity_units_maximum=1,consumed_write_capacity_units_minimum=1,consumed_write_capacity_units_sample_count=48,consumed_write_capacity_units_sum=48 1459263300760742003
> cloudwatch_aws_dynamo_db,host=vljosa-yieldbot.local,table_name=prd-platform-datomic-config consumed_read_capacity_units_average=1.8539288112827401,consumed_read_capacity_units_maximum=8,consumed_read_capacity_units_minimum=0.5,consumed_read_capacity_units_sample_count=1489,consumed_read_capacity_units_sum=2760.5 1459263300832984286
> cloudwatch_aws_dynamo_db,host=vljosa-yieldbot.local,operation=GetItem,table_name=prd-platform-datomic-config successful_request_latency_average=5.014870193569996,successful_request_latency_maximum=56.839959,successful_request_latency_minimum=2.030115,successful_request_latency_sample_count=1493,successful_request_latency_sum=7487.201199000004 1459263300868485699
> cloudwatch_aws_dynamo_db,host=vljosa-yieldbot.local,operation=PutItem,table_name=prd-platform-datomic-config successful_request_latency_average=9.664095158730158,successful_request_latency_maximum=25.262,successful_request_latency_minimum=3.533,successful_request_latency_sample_count=63,successful_request_latency_sum=608.837995 1459263300990375223
2016/03/29 10:55:01 Gathered metrics, (5m0s interval), from 1 inputs in 1.048629086s
2016/03/29 10:55:03 Wrote 8 metrics to output influxdb in 90.0269ms
```

View File

@ -0,0 +1,164 @@
package cloudwatch
import (
"errors"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/azer/snakecase"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/inputs"
"log"
"strings"
"time"
)
type Cloudwatch struct {
Region string
Namespaces []string
// List of metrics to gather statistics for. Computed the first time Gather() is called.
metrics []*cloudwatch.Metric
// Get metrics statistics since last time Gather() was called.
lastTime *time.Time
}
var sampleConfig = `
## AWS region
region = "us-east-1"
## specify namespaces as strings
namespaces = ["AWS/EC2", "AWS/DynamoDB"]
`
func (r *Cloudwatch) SampleConfig() string {
return sampleConfig
}
func (r *Cloudwatch) Description() string {
return "Read metrics from AWS CloudWatch"
}
// Reads stats from AWS CloudWatch. Accumulates stats.
// Returns one of the errors encountered while gathering stats (if any).
func (r *Cloudwatch) Gather(acc telegraf.Accumulator) error {
svc := cloudwatch.New(session.New(), &aws.Config{Region: aws.String(r.Region)})
var outerr error
now := time.Now()
if r.lastTime == nil {
r.metrics, outerr = listMetrics(svc, r.Namespaces)
log.Printf("Found %d cloudwatch metrics", len(r.metrics))
} else {
for i := 0; i < len(r.metrics); i++ {
metric := r.metrics[i]
minutes := int64(now.Sub(*r.lastTime) / time.Minute)
if minutes == 0 {
minutes = 1
}
period := minutes * 60
outerr = gatherMetric(svc, r.Region, acc, metric, *r.lastTime, now, period)
}
}
r.lastTime = &now
return outerr
}
type listMetricsAPI interface {
ListMetrics(*cloudwatch.ListMetricsInput) (*cloudwatch.ListMetricsOutput, error)
}
func listMetrics(svc listMetricsAPI, namespaces []string) ([]*cloudwatch.Metric, error) {
metrics := []*cloudwatch.Metric{}
for i := 0; i < len(namespaces); i++ {
namespace := namespaces[i]
params := &cloudwatch.ListMetricsInput{
Dimensions: []*cloudwatch.DimensionFilter{},
MetricName: nil,
Namespace: aws.String(namespace),
NextToken: nil,
}
resp, err := svc.ListMetrics(params)
if err != nil {
return []*cloudwatch.Metric{}, err
}
metrics = append(metrics, resp.Metrics...)
}
return metrics, nil
}
type getMetricStatisticsAPI interface {
GetMetricStatistics(*cloudwatch.GetMetricStatisticsInput) (*cloudwatch.GetMetricStatisticsOutput, error)
}
func gatherMetric(svc getMetricStatisticsAPI, region string, acc telegraf.Accumulator, metric *cloudwatch.Metric, startTime time.Time, endTime time.Time, period int64) error {
r, err := svc.GetMetricStatistics(&cloudwatch.GetMetricStatisticsInput{
Namespace: metric.Namespace,
MetricName: metric.MetricName,
Dimensions: metric.Dimensions,
Statistics: []*string{
aws.String("Average"),
aws.String("Maximum"),
aws.String("Minimum"),
aws.String("Sum"),
aws.String("SampleCount")},
StartTime: &startTime,
EndTime: &endTime,
Period: &period,
})
if err != nil {
return err
}
if len(r.Datapoints) == 0 {
return nil
}
if len(r.Datapoints) != 1 {
return errors.New(fmt.Sprintf("Expected one datapoint, received %d", len(r.Datapoints)))
}
dp := r.Datapoints[0]
fields := make(map[string]interface{})
if dp.Average != nil {
fields[formatField(*metric.MetricName, "average")] = *dp.Average
}
if dp.Maximum != nil {
fields[formatField(*metric.MetricName, "maximum")] = *dp.Maximum
}
if dp.Minimum != nil {
fields[formatField(*metric.MetricName, "minimum")] = *dp.Minimum
}
if dp.Sum != nil {
fields[formatField(*metric.MetricName, "sum")] = *dp.Sum
}
if dp.SampleCount != nil {
fields[formatField(*metric.MetricName, "sample_count")] = *dp.SampleCount
}
tags := getTags(region, metric.Dimensions)
acc.AddFields(formatMeasurement(*metric.Namespace), fields, tags)
return nil
}
func getTags(region string, dimensions []*cloudwatch.Dimension) map[string]string {
tags := make(map[string]string)
tags["region"] = region
for _, d := range dimensions {
tags[snakecase.SnakeCase(*d.Name)] = *d.Value
}
return tags
}
func formatField(metricName string, statistic string) string {
return fmt.Sprintf("%s_%s", snakecase.SnakeCase(metricName), statistic)
}
func formatMeasurement(namespace string) string {
ns := snakecase.SnakeCase(namespace)
ns = strings.Replace(ns, "/", "_", -1)
ns = strings.Replace(ns, "__", "_", -1)
return fmt.Sprintf("cloudwatch_%s", ns)
}
func init() {
inputs.Add("cloudwatch", func() telegraf.Input {
return &Cloudwatch{}
})
}

View File

@ -0,0 +1,237 @@
package cloudwatch
import (
"errors"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/influxdata/telegraf/testutil"
"testing"
"time"
)
type ListMetricsMock struct{}
func (lmm *ListMetricsMock) ListMetrics(params *cloudwatch.ListMetricsInput) (*cloudwatch.ListMetricsOutput, error) {
switch *params.Namespace {
case "AWS/EC2":
return &cloudwatch.ListMetricsOutput{
Metrics: []*cloudwatch.Metric{
&cloudwatch.Metric{
Dimensions: []*cloudwatch.Dimension{
&cloudwatch.Dimension{
Name: aws.String("InstanceId"),
Value: aws.String("i-a6c5c510"),
},
},
MetricName: aws.String("DiskReadBytes"),
Namespace: aws.String("AWS/EC2"),
},
&cloudwatch.Metric{
Dimensions: []*cloudwatch.Dimension{
&cloudwatch.Dimension{
Name: aws.String("InstanceId"),
Value: aws.String("i-10a2c094"),
},
},
MetricName: aws.String("DiskWriteBytes"),
Namespace: aws.String("AWS/EC2"),
},
},
}, nil
case "AWS/DynamoDB":
return &cloudwatch.ListMetricsOutput{
Metrics: []*cloudwatch.Metric{
&cloudwatch.Metric{
Dimensions: []*cloudwatch.Dimension{
&cloudwatch.Dimension{
Name: aws.String("Operation"),
Value: aws.String("GetItem"),
},
&cloudwatch.Dimension{
Name: aws.String("TableName"),
Value: aws.String("foo"),
},
},
MetricName: aws.String("ThrottledRequests"),
Namespace: aws.String("AWS/DynamoDB"),
},
&cloudwatch.Metric{
Dimensions: []*cloudwatch.Dimension{
&cloudwatch.Dimension{
Name: aws.String("Operation"),
Value: aws.String("PutItem"),
},
&cloudwatch.Dimension{
Name: aws.String("TableName"),
Value: aws.String("foo"),
},
},
MetricName: aws.String("ThrottledRequests"),
Namespace: aws.String("AWS/DynamoDB"),
},
},
}, nil
default:
return nil, errors.New("No such namespace")
}
}
func TestListMetrics(t *testing.T) {
var lmm ListMetricsMock
metrics, err := listMetrics(&lmm, []string{"AWS/EC2"})
if err != nil {
t.Fatal(err)
}
if len(metrics) != 2 {
t.Fatal("Expected 2 AWS/EC2 metrics, found ", len(metrics))
}
allMetrics, err := listMetrics(&lmm, []string{"AWS/EC2", "AWS/DynamoDB"})
if err != nil {
t.Fatal(err)
}
if len(allMetrics) != 4 {
t.Fatal("Expected 4 AWS/EC2 and AWS/DynamoDB metrics, found ", len(allMetrics))
}
}
type GetMetricStatisticsMock struct{}
func (gmsm *GetMetricStatisticsMock) GetMetricStatistics(input *cloudwatch.GetMetricStatisticsInput) (*cloudwatch.GetMetricStatisticsOutput, error) {
timestamp := time.Unix(1459201201, 0)
avg := float64(1.6295248026217786)
maximum := float64(8.0)
minimum := float64(0.5)
sum := float64(10939.0)
sampleCount := float64(6713.0)
return &cloudwatch.GetMetricStatisticsOutput{
Datapoints: []*cloudwatch.Datapoint{
&cloudwatch.Datapoint{
Timestamp: &timestamp,
Average: &avg,
Maximum: &maximum,
Minimum: &minimum,
Sum: &sum,
SampleCount: &sampleCount,
Unit: aws.String("Count"),
},
},
Label: aws.String("ConsumedReadCapacityUnits"),
}, nil
}
type GetMetricStatisticsMockPartial struct{}
func (gmsm *GetMetricStatisticsMockPartial) GetMetricStatistics(input *cloudwatch.GetMetricStatisticsInput) (*cloudwatch.GetMetricStatisticsOutput, error) {
timestamp := time.Unix(1459201201, 0)
avg := float64(1.6295248026217786)
return &cloudwatch.GetMetricStatisticsOutput{
Datapoints: []*cloudwatch.Datapoint{
&cloudwatch.Datapoint{
Timestamp: &timestamp,
Average: &avg,
Unit: aws.String("Count"),
},
},
Label: aws.String("ConsumedReadCapacityUnits"),
}, nil
}
func TestGatherMetric(t *testing.T) {
var svc GetMetricStatisticsMock
var acc testutil.Accumulator
metric := &cloudwatch.Metric{
Dimensions: []*cloudwatch.Dimension{
&cloudwatch.Dimension{
Name: aws.String("TableName"),
Value: aws.String("foo"),
},
},
MetricName: aws.String("ConsumedReadCapacityUnits"),
Namespace: aws.String("AWS/DynamoDB"),
}
bogusTime := time.Now()
err := gatherMetric(&svc, "us-east-1", &acc, metric, bogusTime, bogusTime, 300)
if err != nil {
t.Fatal(err)
}
acc.AssertContainsTaggedFields(t, "cloudwatch_aws_dynamo_db",
map[string]interface{}{"consumed_read_capacity_units_average": 1.6295248026217786,
"consumed_read_capacity_units_maximum": 8.0,
"consumed_read_capacity_units_minimum": 0.5,
"consumed_read_capacity_units_sum": 10939.0,
"consumed_read_capacity_units_sample_count": 6713.0,
},
map[string]string{
"region": "us-east-1",
"table_name": "foo",
})
}
// Test that it still works with only some statistics
func TestGatherMetricPartial(t *testing.T) {
var svc GetMetricStatisticsMockPartial
var acc testutil.Accumulator
metric := &cloudwatch.Metric{
Dimensions: []*cloudwatch.Dimension{
&cloudwatch.Dimension{
Name: aws.String("TableName"),
Value: aws.String("foo"),
},
},
MetricName: aws.String("ConsumedReadCapacityUnits"),
Namespace: aws.String("AWS/DynamoDB"),
}
bogusTime := time.Now()
err := gatherMetric(&svc, "us-east-1", &acc, metric, bogusTime, bogusTime, 300)
if err != nil {
t.Fatal(err)
}
acc.AssertContainsTaggedFields(t, "cloudwatch_aws_dynamo_db",
map[string]interface{}{"consumed_read_capacity_units_average": 1.6295248026217786},
map[string]string{
"region": "us-east-1",
"table_name": "foo",
})
}
func TestGetTags(t *testing.T) {
tags := getTags("us-east-1", []*cloudwatch.Dimension{
&cloudwatch.Dimension{
Name: aws.String("Operation"),
Value: aws.String("GetItem"),
},
&cloudwatch.Dimension{
Name: aws.String("TableName"),
Value: aws.String("foo"),
},
})
if len(tags) != 3 {
t.Fatal("Expected 3 tags, not ", len(tags))
}
if tags["region"] != "us-east-1" {
t.Fatal("Expected the tag `region` with value `us-east-1`")
}
if tags["operation"] != "GetItem" {
t.Fatal("Expected the tag `operation` with value `GetItem`")
}
if tags["table_name"] != "foo" {
t.Fatal("Expected the tag `table_name` with value `foo`")
}
}
func TestFormatField(t *testing.T) {
if s := formatField("DiskWriteBytes", "average"); s != "disk_write_bytes_average" {
t.Fatal("Field should not be ", s)
}
}
func TestFormatMeasurement(t *testing.T) {
if s := formatMeasurement("AWS/EC2"); s != "cloudwatch_aws_ec2" {
t.Fatal("Measurement should not be ", s)
}
if s := formatMeasurement("AWS/DynamoDB"); s != "cloudwatch_aws_dynamo_db" {
t.Fatal("Measurement should not be ", s)
}
}