Use Cloudwatch options in the struct itself, which is cleaner
Eric Feliksik
6 years ago
30 | 30 | // |
31 | 31 | // To regularly report metrics to CloudWatch, use the WriteLoop helper method. |
32 | 32 | type CloudWatch struct { |
33 | mtx sync.RWMutex | |
34 | sem chan struct{} | |
35 | namespace string | |
36 | svc cloudwatchiface.CloudWatchAPI | |
37 | counters *lv.Space | |
38 | gauges *lv.Space | |
39 | histograms *lv.Space | |
40 | *cwoptions | |
41 | } | |
42 | ||
43 | type cwoptions struct { | |
33 | mtx sync.RWMutex | |
34 | sem chan struct{} | |
35 | namespace string | |
36 | svc cloudwatchiface.CloudWatchAPI | |
37 | counters *lv.Space | |
38 | gauges *lv.Space | |
39 | histograms *lv.Space | |
44 | 40 | percentiles Percentiles |
45 | 41 | logger log.Logger |
46 | 42 | numConcurrentRequests int |
47 | 43 | } |
48 | 44 | |
49 | type option func(*cwoptions) | |
50 | ||
51 | func (s *cwoptions) apply(opt option) { | |
45 | type option func(*CloudWatch) | |
46 | ||
47 | func (s *CloudWatch) apply(opt option) { | |
52 | 48 | if opt != nil { |
53 | 49 | opt(s) |
54 | 50 | } |
55 | 51 | } |
56 | 52 | |
57 | 53 | func WithLogger(logger log.Logger) option { |
58 | return func(o *cwoptions) { | |
59 | o.logger = logger | |
54 | return func(c *CloudWatch) { | |
55 | c.logger = logger | |
60 | 56 | } |
61 | 57 | } |
62 | 58 | |
63 | 59 | func WithPercentiles(p Percentiles) option { |
64 | return func(o *cwoptions) { | |
60 | return func(c *CloudWatch) { | |
65 | 61 | validated := Percentiles{} |
66 | 62 | for _, entry := range p { |
67 | 63 | if entry.f < 0 || entry.f > 1 { |
69 | 65 | } |
70 | 66 | validated = append(validated, entry) |
71 | 67 | } |
72 | o.percentiles = validated | |
68 | c.percentiles = validated | |
73 | 69 | } |
74 | 70 | } |
75 | 71 | |
76 | 72 | func WithConcurrentRequests(n int) option { |
77 | return func(o *cwoptions) { | |
73 | return func(c *CloudWatch) { | |
78 | 74 | if n > maxConcurrentRequests { |
79 | 75 | n = maxConcurrentRequests |
80 | 76 | } |
81 | o.numConcurrentRequests = n | |
77 | c.numConcurrentRequests = n | |
82 | 78 | } |
83 | 79 | } |
84 | 80 | |
87 | 83 | // Callers must ensure that regular calls to Send are performed, either |
88 | 84 | // manually or with one of the helper methods. |
89 | 85 | func New(namespace string, svc cloudwatchiface.CloudWatchAPI, options ...option) *CloudWatch { |
90 | useOptions := &cwoptions{ | |
86 | cw := &CloudWatch{ | |
87 | sem: nil, // set below | |
88 | namespace: namespace, | |
89 | svc: svc, | |
90 | counters: lv.NewSpace(), | |
91 | gauges: lv.NewSpace(), | |
92 | histograms: lv.NewSpace(), | |
91 | 93 | numConcurrentRequests: 10, |
92 | 94 | logger: log.NewLogfmtLogger(os.Stderr), |
93 | 95 | percentiles: Percentiles{ |
98 | 100 | }, |
99 | 101 | } |
100 | 102 | |
101 | for _, opt := range options { | |
102 | useOptions.apply(opt) | |
103 | } | |
104 | ||
105 | return &CloudWatch{ | |
106 | sem: make(chan struct{}, useOptions.numConcurrentRequests), | |
107 | namespace: namespace, | |
108 | svc: svc, | |
109 | counters: lv.NewSpace(), | |
110 | gauges: lv.NewSpace(), | |
111 | histograms: lv.NewSpace(), | |
112 | cwoptions: useOptions, | |
113 | } | |
103 | for _, optFunc := range options { | |
104 | optFunc(cw) | |
105 | } | |
106 | ||
107 | cw.sem = make(chan struct{}, cw.numConcurrentRequests) | |
108 | ||
109 | return cw | |
114 | 110 | } |
115 | 111 | |
116 | 112 | // NewCounter returns a counter. Observations are aggregated and emitted once |