Codebase list golang-github-go-kit-kit / f99615e
Use cloudwatch interface and add tests. Cameron Stitt 7 years ago
2 changed file(s) with 157 addition(s) and 9 deletion(s). Raw diff Collapse all Expand all
88
99 "github.com/aws/aws-sdk-go/aws"
1010 "github.com/aws/aws-sdk-go/service/cloudwatch"
11 "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface"
1112 "github.com/go-kit/kit/log"
1213 "github.com/go-kit/kit/metrics"
1314 "github.com/go-kit/kit/metrics/generic"
2122 type CloudWatch struct {
2223 mtx sync.RWMutex
2324 namespace string
24 svc *cloudwatch.CloudWatch
25 svc cloudwatchiface.CloudWatchAPI
2526 counters map[string]*Counter
2627 gauges map[string]*Gauge
2728 histograms map[string]*Histogram
3132 // New returns a CloudWatch object that may be used to create metrics. Namespace is
3233 // applied to all created metrics and maps to the CloudWatch namespace.
3334 // Callers must ensure that regular calls to Send are performed, either manually or with one of the helper methods.
34 func New(namespace string, logger log.Logger, svc *cloudwatch.CloudWatch) *CloudWatch {
35 func New(namespace string, logger log.Logger, svc cloudwatchiface.CloudWatchAPI) *CloudWatch {
3536 return &CloudWatch{
3637 namespace: namespace,
3738 svc: svc,
152153
153154 // With implements counter
154155 func (c *Counter) With(labelValues ...string) metrics.Counter {
155 return c.c.With(labelValues...)
156 c.c = c.c.With(labelValues...).(*generic.Counter)
157 return c
156158 }
157159
158160 // Add implements counter.
174176
175177 // With implements gauge
176178 func (g *Gauge) With(labelValues ...string) metrics.Gauge {
177 return &Gauge{
178 g: g.g.With(labelValues...).(*generic.Gauge),
179 }
179 g.g = g.g.With(labelValues...).(*generic.Gauge)
180 return g
180181 }
181182
182183 // Set implements gauge
203204
204205 // With implements histogram
205206 func (h *Histogram) With(labelValues ...string) metrics.Histogram {
206 return &Histogram{
207 h: h.h.With(labelValues...).(*generic.Histogram),
208 }
207 h.h = h.h.With(labelValues...).(*generic.Histogram)
208 return h
209209 }
210210
211211 // Observe implements histogram
0 package cloudwatch
1
2 import (
3 "errors"
4 "testing"
5
6 "sync"
7
8 "fmt"
9
10 "github.com/aws/aws-sdk-go/service/cloudwatch"
11 "github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface"
12 "github.com/go-kit/kit/log"
13 "github.com/go-kit/kit/metrics/teststat"
14 )
15
16 type mockCloudWatch struct {
17 cloudwatchiface.CloudWatchAPI
18 mtx sync.RWMutex
19 valuesReceived map[string]float64
20 dimensionsReceived map[string][]*cloudwatch.Dimension
21 }
22
23 func newMockCloudWatch() *mockCloudWatch {
24 return &mockCloudWatch{
25 valuesReceived: map[string]float64{},
26 dimensionsReceived: map[string][]*cloudwatch.Dimension{},
27 }
28 }
29
30 func (mcw *mockCloudWatch) PutMetricData(input *cloudwatch.PutMetricDataInput) (*cloudwatch.PutMetricDataOutput, error) {
31 mcw.mtx.Lock()
32 defer mcw.mtx.Unlock()
33 for _, datum := range input.MetricData {
34 mcw.valuesReceived[*datum.MetricName] = *datum.Value
35 mcw.dimensionsReceived[*datum.MetricName] = datum.Dimensions
36 }
37 return nil, nil
38 }
39
40 func testDimensions(svc *mockCloudWatch, name string, labelValues ...string) error {
41 dimensions, ok := svc.dimensionsReceived[name]
42 if !ok {
43 if len(labelValues) > 0 {
44 return errors.New("Expected dimensions to be available, but none were")
45 }
46 }
47 LabelValues:
48 for i, j := 0, 0; i < len(labelValues); i, j = i+2, j+1 {
49 name, value := labelValues[i], labelValues[i+1]
50 for _, dimension := range dimensions {
51 if *dimension.Name == name {
52 if *dimension.Value == value {
53 break LabelValues
54 }
55 }
56 }
57 return fmt.Errorf("Could not find dimension with name %s and value %s", name, value)
58 }
59
60 return nil
61 }
62
63 func TestCounter(t *testing.T) {
64 namespace, name := "abc", "def"
65 label, value := "label", "value"
66 svc := newMockCloudWatch()
67 cw := New(namespace, log.NewNopLogger(), svc)
68 counter := cw.NewCounter(name).With(label, value)
69 valuef := func() float64 {
70 err := cw.Send()
71 if err != nil {
72 t.Fatal(err)
73 }
74 svc.mtx.RLock()
75 defer svc.mtx.RUnlock()
76 return svc.valuesReceived[name]
77 }
78 if err := teststat.TestCounter(counter, valuef); err != nil {
79 t.Fatal(err)
80 }
81 if err := testDimensions(svc, name, label, value); err != nil {
82 t.Fatal(err)
83 }
84 }
85
86 func TestGauge(t *testing.T) {
87 namespace, name := "abc", "def"
88 label, value := "label", "value"
89 svc := newMockCloudWatch()
90 cw := New(namespace, log.NewNopLogger(), svc)
91 gauge := cw.NewGauge(name).With(label, value)
92 valuef := func() float64 {
93 err := cw.Send()
94 if err != nil {
95 t.Fatal(err)
96 }
97 svc.mtx.RLock()
98 defer svc.mtx.RUnlock()
99 return svc.valuesReceived[name]
100 }
101 if err := teststat.TestGauge(gauge, valuef); err != nil {
102 t.Fatal(err)
103 }
104 if err := testDimensions(svc, name, label, value); err != nil {
105 t.Fatal(err)
106 }
107 }
108
109 func TestHistogram(t *testing.T) {
110 namespace, name := "abc", "def"
111 label, value := "label", "value"
112 svc := newMockCloudWatch()
113 cw := New(namespace, log.NewNopLogger(), svc)
114 histogram := cw.NewHistogram(name, 50).With(label, value)
115 n50 := fmt.Sprintf("%s_50", name)
116 n90 := fmt.Sprintf("%s_90", name)
117 n95 := fmt.Sprintf("%s_95", name)
118 n99 := fmt.Sprintf("%s_99", name)
119 quantiles := func() (p50, p90, p95, p99 float64) {
120 err := cw.Send()
121 if err != nil {
122 t.Fatal(err)
123 }
124 svc.mtx.RLock()
125 defer svc.mtx.RUnlock()
126 p50 = svc.valuesReceived[n50]
127 p90 = svc.valuesReceived[n90]
128 p95 = svc.valuesReceived[n95]
129 p99 = svc.valuesReceived[n99]
130 return
131 }
132 if err := teststat.TestHistogram(histogram, quantiles, 0.01); err != nil {
133 t.Fatal(err)
134 }
135 if err := testDimensions(svc, n50, label, value); err != nil {
136 t.Fatal(err)
137 }
138 if err := testDimensions(svc, n90, label, value); err != nil {
139 t.Fatal(err)
140 }
141 if err := testDimensions(svc, n95, label, value); err != nil {
142 t.Fatal(err)
143 }
144 if err := testDimensions(svc, n99, label, value); err != nil {
145 t.Fatal(err)
146 }
147 }