Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f99615e

Browse files
Use cloudwatch interface and add tests.
1 parent 1223f9f commit f99615e

File tree

2 files changed

+157
-9
lines changed

2 files changed

+157
-9
lines changed

‎metrics/cloudwatch/cloudwatch.go‎

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/aws/aws-sdk-go/aws"
1111
"github.com/aws/aws-sdk-go/service/cloudwatch"
12+
"github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface"
1213
"github.com/go-kit/kit/log"
1314
"github.com/go-kit/kit/metrics"
1415
"github.com/go-kit/kit/metrics/generic"
@@ -22,7 +23,7 @@ import (
2223
type CloudWatch struct {
2324
mtx sync.RWMutex
2425
namespace string
25-
svc *cloudwatch.CloudWatch
26+
svc cloudwatchiface.CloudWatchAPI
2627
counters map[string]*Counter
2728
gauges map[string]*Gauge
2829
histograms map[string]*Histogram
@@ -32,7 +33,7 @@ type CloudWatch struct {
3233
// New returns a CloudWatch object that may be used to create metrics. Namespace is
3334
// applied to all created metrics and maps to the CloudWatch namespace.
3435
// Callers must ensure that regular calls to Send are performed, either manually or with one of the helper methods.
35-
func New(namespace string, logger log.Logger, svc *cloudwatch.CloudWatch) *CloudWatch {
36+
func New(namespace string, logger log.Logger, svc cloudwatchiface.CloudWatchAPI) *CloudWatch {
3637
return &CloudWatch{
3738
namespace: namespace,
3839
svc: svc,
@@ -153,7 +154,8 @@ func NewCounter(name string) *Counter {
153154

154155
// With implements counter
155156
func (c *Counter) With(labelValues ...string) metrics.Counter {
156-
return c.c.With(labelValues...)
157+
c.c = c.c.With(labelValues...).(*generic.Counter)
158+
return c
157159
}
158160

159161
// Add implements counter.
@@ -175,9 +177,8 @@ func NewGauge(name string) *Gauge {
175177

176178
// With implements gauge
177179
func (g *Gauge) With(labelValues ...string) metrics.Gauge {
178-
return &Gauge{
179-
g: g.g.With(labelValues...).(*generic.Gauge),
180-
}
180+
g.g = g.g.With(labelValues...).(*generic.Gauge)
181+
return g
181182
}
182183

183184
// Set implements gauge
@@ -204,9 +205,8 @@ func NewHistogram(name string, buckets int) *Histogram {
204205

205206
// With implements histogram
206207
func (h *Histogram) With(labelValues ...string) metrics.Histogram {
207-
return &Histogram{
208-
h: h.h.With(labelValues...).(*generic.Histogram),
209-
}
208+
h.h = h.h.With(labelValues...).(*generic.Histogram)
209+
return h
210210
}
211211

212212
// Observe implements histogram
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package cloudwatch
2+
3+
import (
4+
"errors"
5+
"testing"
6+
7+
"sync"
8+
9+
"fmt"
10+
11+
"github.com/aws/aws-sdk-go/service/cloudwatch"
12+
"github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface"
13+
"github.com/go-kit/kit/log"
14+
"github.com/go-kit/kit/metrics/teststat"
15+
)
16+
17+
type mockCloudWatch struct {
18+
cloudwatchiface.CloudWatchAPI
19+
mtx sync.RWMutex
20+
valuesReceived map[string]float64
21+
dimensionsReceived map[string][]*cloudwatch.Dimension
22+
}
23+
24+
func newMockCloudWatch() *mockCloudWatch {
25+
return &mockCloudWatch{
26+
valuesReceived: map[string]float64{},
27+
dimensionsReceived: map[string][]*cloudwatch.Dimension{},
28+
}
29+
}
30+
31+
func (mcw *mockCloudWatch) PutMetricData(input *cloudwatch.PutMetricDataInput) (*cloudwatch.PutMetricDataOutput, error) {
32+
mcw.mtx.Lock()
33+
defer mcw.mtx.Unlock()
34+
for _, datum := range input.MetricData {
35+
mcw.valuesReceived[*datum.MetricName] = *datum.Value
36+
mcw.dimensionsReceived[*datum.MetricName] = datum.Dimensions
37+
}
38+
return nil, nil
39+
}
40+
41+
func testDimensions(svc *mockCloudWatch, name string, labelValues ...string) error {
42+
dimensions, ok := svc.dimensionsReceived[name]
43+
if !ok {
44+
if len(labelValues) > 0 {
45+
return errors.New("Expected dimensions to be available, but none were")
46+
}
47+
}
48+
LabelValues:
49+
for i, j := 0, 0; i < len(labelValues); i, j = i+2, j+1 {
50+
name, value := labelValues[i], labelValues[i+1]
51+
for _, dimension := range dimensions {
52+
if *dimension.Name == name {
53+
if *dimension.Value == value {
54+
break LabelValues
55+
}
56+
}
57+
}
58+
return fmt.Errorf("Could not find dimension with name %s and value %s", name, value)
59+
}
60+
61+
return nil
62+
}
63+
64+
func TestCounter(t *testing.T) {
65+
namespace, name := "abc", "def"
66+
label, value := "label", "value"
67+
svc := newMockCloudWatch()
68+
cw := New(namespace, log.NewNopLogger(), svc)
69+
counter := cw.NewCounter(name).With(label, value)
70+
valuef := func() float64 {
71+
err := cw.Send()
72+
if err != nil {
73+
t.Fatal(err)
74+
}
75+
svc.mtx.RLock()
76+
defer svc.mtx.RUnlock()
77+
return svc.valuesReceived[name]
78+
}
79+
if err := teststat.TestCounter(counter, valuef); err != nil {
80+
t.Fatal(err)
81+
}
82+
if err := testDimensions(svc, name, label, value); err != nil {
83+
t.Fatal(err)
84+
}
85+
}
86+
87+
func TestGauge(t *testing.T) {
88+
namespace, name := "abc", "def"
89+
label, value := "label", "value"
90+
svc := newMockCloudWatch()
91+
cw := New(namespace, log.NewNopLogger(), svc)
92+
gauge := cw.NewGauge(name).With(label, value)
93+
valuef := func() float64 {
94+
err := cw.Send()
95+
if err != nil {
96+
t.Fatal(err)
97+
}
98+
svc.mtx.RLock()
99+
defer svc.mtx.RUnlock()
100+
return svc.valuesReceived[name]
101+
}
102+
if err := teststat.TestGauge(gauge, valuef); err != nil {
103+
t.Fatal(err)
104+
}
105+
if err := testDimensions(svc, name, label, value); err != nil {
106+
t.Fatal(err)
107+
}
108+
}
109+
110+
func TestHistogram(t *testing.T) {
111+
namespace, name := "abc", "def"
112+
label, value := "label", "value"
113+
svc := newMockCloudWatch()
114+
cw := New(namespace, log.NewNopLogger(), svc)
115+
histogram := cw.NewHistogram(name, 50).With(label, value)
116+
n50 := fmt.Sprintf("%s_50", name)
117+
n90 := fmt.Sprintf("%s_90", name)
118+
n95 := fmt.Sprintf("%s_95", name)
119+
n99 := fmt.Sprintf("%s_99", name)
120+
quantiles := func() (p50, p90, p95, p99 float64) {
121+
err := cw.Send()
122+
if err != nil {
123+
t.Fatal(err)
124+
}
125+
svc.mtx.RLock()
126+
defer svc.mtx.RUnlock()
127+
p50 = svc.valuesReceived[n50]
128+
p90 = svc.valuesReceived[n90]
129+
p95 = svc.valuesReceived[n95]
130+
p99 = svc.valuesReceived[n99]
131+
return
132+
}
133+
if err := teststat.TestHistogram(histogram, quantiles, 0.01); err != nil {
134+
t.Fatal(err)
135+
}
136+
if err := testDimensions(svc, n50, label, value); err != nil {
137+
t.Fatal(err)
138+
}
139+
if err := testDimensions(svc, n90, label, value); err != nil {
140+
t.Fatal(err)
141+
}
142+
if err := testDimensions(svc, n95, label, value); err != nil {
143+
t.Fatal(err)
144+
}
145+
if err := testDimensions(svc, n99, label, value); err != nil {
146+
t.Fatal(err)
147+
}
148+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /