-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinstrument.go
150 lines (117 loc) · 2.92 KB
/
instrument.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
package stats
import "fmt"
type InstrumentVector interface {
WithLabels(...string) Instrument
}
type instrumentVector struct {
entityVector
scope Scope
name string
opts instrumentOptions
}
func NewInstrumentVector(scope Scope, name string, labels []string, opts ...InstrumentOption) InstrumentVector {
var iv = instrumentVector{
entityVector: entityVector{
marshaler: newDefaultMarshaler(),
labels: labels,
},
scope: scope,
name: name,
opts: defaultInstrumentOptions,
}
for _, opt := range opts {
opt(&iv.opts)
}
iv.newFunc = iv.newInstrument
return &iv
}
func (iv *instrumentVector) newInstrument(vs map[string]string) interface{} {
return newInstrument(iv.scope.Scope("", vs), iv.name, iv.opts)
}
func (iv *instrumentVector) WithLabels(ls ...string) Instrument {
return iv.entity(ls).(*instrument)
}
type Instrument interface {
Exec(func() error) error
}
type InstrumentOption func(*instrumentOptions)
var defaultInstrumentOptions = instrumentOptions{
formatter: defaultFormatter,
trackStarted: true,
counterLabel: "status",
}
func DisableStartedCounter() InstrumentOption {
return func(opts *instrumentOptions) {
opts.trackStarted = false
}
}
func WithFormatter(f ErrorFormatter) InstrumentOption {
return func(opts *instrumentOptions) {
opts.formatter = f
}
}
func WithCounterLabel(s string) InstrumentOption {
return func(opts *instrumentOptions) {
opts.counterLabel = s
}
}
func WithTimerOptions(tOpts ...TimerOption) InstrumentOption {
return func(opts *instrumentOptions) {
opts.tOpts = tOpts
}
}
type instrumentOptions struct {
formatter ErrorFormatter
tOpts []TimerOption
trackStarted bool
counterLabel string
}
func NewInstrument(scope Scope, name string, iOpts ...InstrumentOption) Instrument {
var opts = defaultInstrumentOptions
for _, opt := range iOpts {
opt(&opts)
}
return newInstrument(scope, name, opts)
}
func newInstrument(scope Scope, name string, opts instrumentOptions) *instrument {
var startedCounter Counter = noopCounter{}
if opts.trackStarted {
startedCounter = scope.Counter(fmt.Sprintf("%s_started_total", name))
}
return &instrument{
instrumentOptions: opts,
timer: NewTimer(
scope,
fmt.Sprintf("%s_duration", name),
opts.tOpts...,
),
started: startedCounter,
finished: scope.CounterVector(
fmt.Sprintf("%s_total", name),
[]string{opts.counterLabel},
),
}
}
type ErrorFormatter func(error) string
type instrument struct {
instrumentOptions
finished CounterVector
started Counter
timer Timer
}
func (i *instrument) Exec(fn func() error) error {
i.started.Inc()
sw := i.timer.Start()
err := fn()
sw.Stop()
i.finished.WithLabels(i.formatter(err)).Inc()
return err
}
// defaultFormatter , look into https://github.com/upfluence/errors/blob/master/stats/statuser.go#L36
// for more advanced reporting
func defaultFormatter(err error) string {
if err == nil {
return "success"
}
return "failed"
}