diff --git a/metrics/cloudwatch/cloudwatch.go b/metrics/cloudwatch/cloudwatch.go index bf4723b..e1106a4 100644 --- a/metrics/cloudwatch/cloudwatch.go +++ b/metrics/cloudwatch/cloudwatch.go @@ -3,6 +3,9 @@ import ( "sync" + "time" + + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/cloudwatch" "github.com/go-kit/kit/log" "github.com/go-kit/kit/metrics" @@ -15,11 +18,10 @@ prefix string svc *cloudwatch.CloudWatch counters map[string]*Counter - //gauges map[string]*Gauge - //histograms map[string]*Histogram - logger log.Logger + logger log.Logger } +// New ... func New(prefix string, logger log.Logger, svc *cloudwatch.CloudWatch) *CloudWatch { return &CloudWatch{ prefix: prefix, @@ -30,24 +32,51 @@ } func (cw *CloudWatch) NewCounter(name string) *Counter { - c := NewCounter(cw.prefix, name) + c := NewCounter(name) cw.mtx.Lock() cw.counters[cw.prefix+name] = c cw.mtx.Unlock() return c } -// Counter is a Graphite counter metric. +// WriteLoop is a helper method that invokes WriteTo to the passed writer every +// time the passed channel fires. This method blocks until the channel is +// closed, so clients probably want to run it in its own goroutine. For typical +// usage, create a time.Ticker and pass its C channel to this method. +func (cw *CloudWatch) WriteLoop(c <-chan time.Time) { + for range c { + cw.mtx.RLock() + defer cw.mtx.RUnlock() + now := time.Now() + + for name, c := range cw.counters { + _, err := cw.svc.PutMetricData(&cloudwatch.PutMetricDataInput{ + Namespace: aws.String(cw.prefix), + MetricData: []*cloudwatch.MetricDatum{ + { + MetricName: aws.String(name), + Dimensions: makeDimensions(c.c.LabelValues()...), + Value: aws.Float64(c.c.Value()), + Timestamp: aws.Time(now), + }, + }, + }) + if err != nil { + cw.logger.Log("during", "WriteLoop", "err", err) + } + } + } +} + +// Counter is a CloudWatch counter metric. type Counter struct { - namespace string - c *generic.Counter + c *generic.Counter } // NewCounter returns a new usable counter metric. -func NewCounter(namespace, name string) *Counter { +func NewCounter(name string) *Counter { return &Counter{ - namespace: namespace, - c: generic.NewCounter(name), + c: generic.NewCounter(name), } } @@ -60,3 +89,14 @@ func (c *Counter) Add(delta float64) { c.c.Add(delta) } + +func makeDimensions(labelValues ...string) []*cloudwatch.Dimension { + dimensions := make([]*cloudwatch.Dimension, len(labelValues)/2) + for i, j := 0, 0; i < len(labelValues); i, j := i+2, j+1 { + dimensions[j] = &cloudwatch.Dimension{ + Name: aws.String(labelValues[i]), + Value: aws.String(labelValues[i+1]), + } + } + return dimensions +}