-
Notifications
You must be signed in to change notification settings - Fork 10
/
coremetrics.go
153 lines (121 loc) · 4.89 KB
/
coremetrics.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
package slackscot
import (
"go.opentelemetry.io/otel/label"
"go.opentelemetry.io/otel/metric"
"time"
)
const (
newMsgType = "new"
updateMsgType = "edit"
deleteMsgType = "delete"
)
// instrumenter holds data for core instrumentation
type instrumenter struct {
appName string
coreMetrics coreMetrics
pluginMetrics map[string]pluginMetrics
meter metric.Meter
}
// coreMetrics holds core slackscot metrics
type coreMetrics struct {
msgsSeen metric.BoundInt64Counter
msgsProcessed map[string]metric.BoundInt64Counter
msgProcessingLatencyMillis map[string]metric.BoundInt64ValueRecorder
msgDispatchLatencyMillis metric.BoundInt64ValueRecorder
slackLatencyMillis metric.Int64ValueObserver
}
// pluginMetrics holds metrics specific to a plugin
type pluginMetrics struct {
processingTimeMillis metric.BoundInt64ValueRecorder
reactionCount metric.BoundInt64Counter
}
// newInstrumenter creates a new core instrumenter
func newInstrumenter(appName string, meter metric.Meter, latencyCallback metric.Int64ObserverFunc) (ins *instrumenter, err error) {
ins = new(instrumenter)
defaultLabels := []label.KeyValue{label.String("name", appName)}
msgSeen, err := meter.NewInt64Counter("msgSeen")
if err != nil {
return nil, err
}
slackLatency, err := meter.NewInt64ValueObserver("slackLatencyMillis", latencyCallback)
if err != nil {
return nil, err
}
dispatchLatency, err := meter.NewInt64ValueRecorder("msgDispatchLatencyMillis")
if err != nil {
return nil, err
}
msgProcessed, err := newBoundCounterByMsgType("msgProcessed", appName, meter)
if err != nil {
return nil, err
}
msgProcessingLatencyMillis, err := newBoundValueRecorderByMsgType("msgProcessingLatencyMillis", appName, meter)
if err != nil {
return nil, err
}
ins.coreMetrics = coreMetrics{msgsSeen: msgSeen.Bind(defaultLabels...),
msgsProcessed: msgProcessed,
msgProcessingLatencyMillis: msgProcessingLatencyMillis,
msgDispatchLatencyMillis: dispatchLatency.Bind(defaultLabels...),
slackLatencyMillis: slackLatency}
ins.appName = appName
ins.pluginMetrics = make(map[string]pluginMetrics)
ins.meter = meter
return ins, nil
}
// newBoundValueRecorderByMsgType creates a set of BoundInt64Counter by message type
func newBoundCounterByMsgType(counterName string, appName string, meter metric.Meter) (boundCounter map[string]metric.BoundInt64Counter, err error) {
boundCounter = make(map[string]metric.BoundInt64Counter)
c, err := meter.NewInt64Counter(counterName)
if err != nil {
return nil, err
}
boundCounter[newMsgType] = c.Bind(label.String("name", appName), label.String("msgType", newMsgType))
boundCounter[updateMsgType] = c.Bind(label.String("name", appName), label.String("msgType", updateMsgType))
boundCounter[deleteMsgType] = c.Bind(label.String("name", appName), label.String("msgType", deleteMsgType))
return boundCounter, nil
}
// newBoundValueRecorderByMsgType creates a set of BoundInt64ValueRecorder by message type
func newBoundValueRecorderByMsgType(ValueRecorderName string, appName string, meter metric.Meter) (boundValueRecorder map[string]metric.BoundInt64ValueRecorder, err error) {
boundValueRecorder = make(map[string]metric.BoundInt64ValueRecorder)
m, err := meter.NewInt64ValueRecorder(ValueRecorderName)
if err != nil {
return nil, err
}
boundValueRecorder[newMsgType] = m.Bind(label.String("name", appName), label.String("msgType", newMsgType))
boundValueRecorder[updateMsgType] = m.Bind(label.String("name", appName), label.String("msgType", updateMsgType))
boundValueRecorder[deleteMsgType] = m.Bind(label.String("name", appName), label.String("msgType", deleteMsgType))
return boundValueRecorder, nil
}
// getOrCreatePluginMetrics returns an existing pluginMetrics for a plugin or creates a new one, if necessary
func (ins *instrumenter) getOrCreatePluginMetrics(pluginName string) (pm pluginMetrics, err error) {
if _, ok := ins.pluginMetrics[pluginName]; !ok {
pm, err = newPluginMetrics(ins.appName, pluginName, ins.meter)
if err != nil {
return pm, err
}
ins.pluginMetrics[pluginName] = pm
}
return ins.pluginMetrics[pluginName], nil
}
// newPluginMetrics returns a new pluginMetrics instance for a plugin
func newPluginMetrics(appName string, pluginName string, meter metric.Meter) (pm pluginMetrics, err error) {
c, err := meter.NewInt64Counter("reactionCount")
if err != nil {
return pm, err
}
m, err := meter.NewInt64ValueRecorder("processingTimeMillis")
if err != nil {
return pm, err
}
pm.reactionCount = c.Bind(label.String("name", appName), label.String("plugin", pluginName))
pm.processingTimeMillis = m.Bind(label.String("name", appName), label.String("plugin", pluginName))
return pm, nil
}
type timed func()
// measure returns the execution duration of a timed function
func measure(operation timed) (d time.Duration) {
before := time.Now()
operation()
return time.Now().Sub(before)
}