-
Notifications
You must be signed in to change notification settings - Fork 20
/
handler_metrics.go
135 lines (110 loc) · 3.46 KB
/
handler_metrics.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
package metrics
import (
"fmt"
"sync"
"github.com/prometheus/client_golang/prometheus"
io_prometheus_client "github.com/prometheus/client_model/go"
"github.com/sirupsen/logrus"
)
var (
handlerMetricsByHandlerName = &sync.Map{}
)
const (
failure = "failure"
success = "success"
handlerResult = "result"
handlers = "handlers"
grabbitPrefix = "grabbit"
)
type handlerMetrics struct {
result *prometheus.CounterVec
latency prometheus.Summary
}
//AddHandlerMetrics adds a handlere to be tracked with metrics
func AddHandlerMetrics(handlerName string) {
handlerMetrics := newHandlerMetrics(handlerName)
_, exists := handlerMetricsByHandlerName.LoadOrStore(handlerName, handlerMetrics)
if !exists {
prometheus.MustRegister(handlerMetrics.latency, handlerMetrics.result)
}
}
//RunHandlerWithMetric runs a specific handler with metrics being collected and reported to prometheus
func RunHandlerWithMetric(handleMessage func() error, handlerName string, logger logrus.FieldLogger) error {
handlerMetrics := GetHandlerMetrics(handlerName)
defer func() {
if p := recover(); p != nil {
if handlerMetrics != nil {
handlerMetrics.result.WithLabelValues(failure).Inc()
}
panic(p)
}
}()
if handlerMetrics == nil {
logger.WithField("handler", handlerName).Warn("Running with metrics - couldn't find metrics for the given handler")
return handleMessage()
}
err := trackTime(handleMessage, handlerMetrics.latency)
if err != nil {
handlerMetrics.result.WithLabelValues(failure).Inc()
} else {
handlerMetrics.result.WithLabelValues(success).Inc()
}
return err
}
//GetHandlerMetrics gets the metrics handler associated with the handlerName
func GetHandlerMetrics(handlerName string) *handlerMetrics {
entry, ok := handlerMetricsByHandlerName.Load(handlerName)
if ok {
return entry.(*handlerMetrics)
}
return nil
}
func newHandlerMetrics(handlerName string) *handlerMetrics {
return &handlerMetrics{
result: prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: grabbitPrefix,
Subsystem: handlers,
Name: fmt.Sprintf("%s_result", handlerName),
Help: fmt.Sprintf("The %s's result", handlerName),
},
[]string{handlerResult}),
latency: prometheus.NewSummary(
prometheus.SummaryOpts{
Namespace: grabbitPrefix,
Subsystem: handlers,
Name: fmt.Sprintf("%s_latency", handlerName),
Help: fmt.Sprintf("The %s's latency", handlerName),
}),
}
}
func trackTime(functionToTrack func() error, observer prometheus.Observer) error {
timer := prometheus.NewTimer(observer)
defer timer.ObserveDuration()
return functionToTrack()
}
//GetSuccessCount gets the value of the handlers success value
func (hm *handlerMetrics) GetSuccessCount() (float64, error) {
return hm.getLabeledCounterValue(success)
}
//GetFailureCount gets the value of the handlers failure value
func (hm *handlerMetrics) GetFailureCount() (float64, error) {
return hm.getLabeledCounterValue(failure)
}
//GetLatencySampleCount gets the value of the handlers latency value
func (hm *handlerMetrics) GetLatencySampleCount() (*uint64, error) {
m := &io_prometheus_client.Metric{}
err := hm.latency.Write(m)
if err != nil {
return nil, err
}
return m.GetSummary().SampleCount, nil
}
func (hm *handlerMetrics) getLabeledCounterValue(label string) (float64, error) {
m := &io_prometheus_client.Metric{}
err := hm.result.WithLabelValues(label).Write(m)
if err != nil {
return 0, err
}
return m.GetCounter().GetValue(), nil
}