Use WriteLoop approach to reduce api overhead.
Cameron Stitt
6 years ago
2 | 2 | import ( |
3 | 3 | "sync" |
4 | 4 | |
5 | "time" | |
6 | ||
7 | "github.com/aws/aws-sdk-go/aws" | |
5 | 8 | "github.com/aws/aws-sdk-go/service/cloudwatch" |
6 | 9 | "github.com/go-kit/kit/log" |
7 | 10 | "github.com/go-kit/kit/metrics" |
14 | 17 | prefix string |
15 | 18 | svc *cloudwatch.CloudWatch |
16 | 19 | counters map[string]*Counter |
17 | //gauges map[string]*Gauge | |
18 | //histograms map[string]*Histogram | |
19 | logger log.Logger | |
20 | logger log.Logger | |
20 | 21 | } |
21 | 22 | |
23 | // New ... | |
22 | 24 | func New(prefix string, logger log.Logger, svc *cloudwatch.CloudWatch) *CloudWatch { |
23 | 25 | return &CloudWatch{ |
24 | 26 | prefix: prefix, |
29 | 31 | } |
30 | 32 | |
31 | 33 | func (cw *CloudWatch) NewCounter(name string) *Counter { |
32 | c := NewCounter(cw.prefix, name) | |
34 | c := NewCounter(name) | |
33 | 35 | cw.mtx.Lock() |
34 | 36 | cw.counters[cw.prefix+name] = c |
35 | 37 | cw.mtx.Unlock() |
36 | 38 | return c |
37 | 39 | } |
38 | 40 | |
39 | // Counter is a Graphite counter metric. | |
41 | // WriteLoop is a helper method that invokes WriteTo to the passed writer every | |
42 | // time the passed channel fires. This method blocks until the channel is | |
43 | // closed, so clients probably want to run it in its own goroutine. For typical | |
44 | // usage, create a time.Ticker and pass its C channel to this method. | |
45 | func (cw *CloudWatch) WriteLoop(c <-chan time.Time) { | |
46 | for range c { | |
47 | cw.mtx.RLock() | |
48 | defer cw.mtx.RUnlock() | |
49 | now := time.Now() | |
50 | ||
51 | for name, c := range cw.counters { | |
52 | _, err := cw.svc.PutMetricData(&cloudwatch.PutMetricDataInput{ | |
53 | Namespace: aws.String(cw.prefix), | |
54 | MetricData: []*cloudwatch.MetricDatum{ | |
55 | { | |
56 | MetricName: aws.String(name), | |
57 | Dimensions: makeDimensions(c.c.LabelValues()...), | |
58 | Value: aws.Float64(c.c.Value()), | |
59 | Timestamp: aws.Time(now), | |
60 | }, | |
61 | }, | |
62 | }) | |
63 | if err != nil { | |
64 | cw.logger.Log("during", "WriteLoop", "err", err) | |
65 | } | |
66 | } | |
67 | } | |
68 | } | |
69 | ||
70 | // Counter is a CloudWatch counter metric. | |
40 | 71 | type Counter struct { |
41 | namespace string | |
42 | c *generic.Counter | |
72 | c *generic.Counter | |
43 | 73 | } |
44 | 74 | |
45 | 75 | // NewCounter returns a new usable counter metric. |
46 | func NewCounter(namespace, name string) *Counter { | |
76 | func NewCounter(name string) *Counter { | |
47 | 77 | return &Counter{ |
48 | namespace: namespace, | |
49 | c: generic.NewCounter(name), | |
78 | c: generic.NewCounter(name), | |
50 | 79 | } |
51 | 80 | } |
52 | 81 | |
59 | 88 | func (c *Counter) Add(delta float64) { |
60 | 89 | c.c.Add(delta) |
61 | 90 | } |
91 | ||
92 | func makeDimensions(labelValues ...string) []*cloudwatch.Dimension { | |
93 | dimensions := make([]*cloudwatch.Dimension, len(labelValues)/2) | |
94 | for i, j := 0, 0; i < len(labelValues); i, j := i+2, j+1 { | |
95 | dimensions[j] = &cloudwatch.Dimension{ | |
96 | Name: aws.String(labelValues[i]), | |
97 | Value: aws.String(labelValues[i+1]), | |
98 | } | |
99 | } | |
100 | return dimensions | |
101 | } |