-
Notifications
You must be signed in to change notification settings - Fork 0
/
measurement.go
214 lines (182 loc) · 5.76 KB
/
measurement.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
//go:generate mockgen -destination=mock_measurement.go -package stats -source=measurement.go Stats,Measurement
package stats
import (
"fmt"
"time"
"gopkg.in/alexcesaro/statsd.v2"
)
// Counter represents a counter metric
type Counter interface {
Count(n int)
Increment()
}
// Gauge represents a gauge metric
type Gauge interface {
Gauge(value interface{})
}
// Histogram represents a histogram metric
type Histogram interface {
Observe(value float64)
}
// Timer represents a timer metric
type Timer interface {
SendTiming(duration time.Duration)
Since(start time.Time)
RecordDuration() func()
}
// Measurement provides all stat measurement functions
// TODO: the API should not return a union of measurement methods, but rather a distinct type for each measurement type
type Measurement interface {
Counter
Gauge
Histogram
Timer
}
// statsdMeasurement is the statsd-specific implementation of Measurement
type statsdMeasurement struct {
conf *statsdConfig
name string
statType string
client *statsdClient
}
// skip returns true if the stat should be skipped (stats disabled or client not ready)
func (m *statsdMeasurement) skip() bool {
return !m.conf.enabled || !m.client.ready()
}
// Count default behavior is to panic as not supported operation
func (m *statsdMeasurement) Count(_ int) {
panic(fmt.Errorf("operation Count not supported for measurement type:%s", m.statType))
}
// Increment default behavior is to panic as not supported operation
func (m *statsdMeasurement) Increment() {
panic(fmt.Errorf("operation Increment not supported for measurement type:%s", m.statType))
}
// Gauge default behavior is to panic as not supported operation
func (m *statsdMeasurement) Gauge(_ interface{}) {
panic(fmt.Errorf("operation Gauge not supported for measurement type:%s", m.statType))
}
// Observe default behavior is to panic as not supported operation
func (m *statsdMeasurement) Observe(_ float64) {
panic(fmt.Errorf("operation Observe not supported for measurement type:%s", m.statType))
}
// Start default behavior is to panic as not supported operation
func (m *statsdMeasurement) Start() {
panic(fmt.Errorf("operation Start not supported for measurement type:%s", m.statType))
}
func (m *statsdMeasurement) End() {
panic(fmt.Errorf("operation End not supported for measurement type:%s", m.statType))
}
// SendTiming default behavior is to panic as not supported operation
func (m *statsdMeasurement) SendTiming(_ time.Duration) {
panic(fmt.Errorf("operation SendTiming not supported for measurement type:%s", m.statType))
}
// Since default behavior is to panic as not supported operation
func (m *statsdMeasurement) Since(_ time.Time) {
panic(fmt.Errorf("operation Since not supported for measurement type:%s", m.statType))
}
// RecordDuration default behavior is to panic as not supported operation
func (m *statsdMeasurement) RecordDuration() func() {
panic(fmt.Errorf("operation RecordDuration not supported for measurement type:%s", m.statType))
}
// statsdCounter represents a counter stat
type statsdCounter struct {
*statsdMeasurement
}
func (c *statsdCounter) Count(n int) {
if c.skip() {
return
}
c.client.statsd.Count(c.name, n)
}
// Increment increases the stat by 1. Is the Equivalent of Count(1). Only applies to CountType stats
func (c *statsdCounter) Increment() {
if c.skip() {
return
}
c.client.statsd.Increment(c.name)
}
// statsdGauge represents a gauge stat
type statsdGauge struct {
*statsdMeasurement
}
// Gauge records an absolute value for this stat. Only applies to GaugeType stats
func (g *statsdGauge) Gauge(value interface{}) {
if g.skip() {
return
}
g.client.statsd.Gauge(g.name, value)
}
// statsdTimer represents a timer stat
type statsdTimer struct {
*statsdMeasurement
timing *statsd.Timing
}
// Start starts a new timing for this stat. Only applies to TimerType stats
// Deprecated: Use concurrent safe SendTiming() instead
func (t *statsdTimer) Start() {
if t.skip() {
return
}
timing := t.client.statsd.NewTiming()
t.timing = &timing
}
// End send the time elapsed since the Start() call of this stat. Only applies to TimerType stats
// Deprecated: Use concurrent safe SendTiming() instead
func (t *statsdTimer) End() {
if t.skip() || t.timing == nil {
return
}
t.timing.Send(t.name)
}
// Since sends the time elapsed since duration start. Only applies to TimerType stats
func (t *statsdTimer) Since(start time.Time) {
t.SendTiming(time.Since(start))
}
// SendTiming sends a timing for this stat. Only applies to TimerType stats
func (t *statsdTimer) SendTiming(duration time.Duration) {
if t.skip() {
return
}
t.client.statsd.Timing(t.name, int(duration/time.Millisecond))
}
// RecordDuration records the duration of time between
// the call to this function and the execution of the function it returns.
// Only applies to TimerType stats
func (t *statsdTimer) RecordDuration() func() {
start := time.Now()
return func() {
t.Since(start)
}
}
// statsdHistogram represents a histogram stat
type statsdHistogram struct {
*statsdMeasurement
}
// Observe sends an observation
func (h *statsdHistogram) Observe(value float64) {
if h.skip() {
return
}
h.client.statsd.Histogram(h.name, value)
}
// newStatsdMeasurement creates a new measurement of the specific type
func newStatsdMeasurement(conf *statsdConfig, name, statType string, client *statsdClient) Measurement {
baseMeasurement := &statsdMeasurement{
conf: conf,
name: name,
statType: statType,
client: client,
}
switch statType {
case CountType:
return &statsdCounter{baseMeasurement}
case GaugeType:
return &statsdGauge{baseMeasurement}
case TimerType:
return &statsdTimer{statsdMeasurement: baseMeasurement}
case HistogramType:
return &statsdHistogram{baseMeasurement}
default:
panic(fmt.Errorf("unsupported measurement type %s", statType))
}
}