-
Notifications
You must be signed in to change notification settings - Fork 7
/
requestmetrics.go
106 lines (89 loc) · 2.56 KB
/
requestmetrics.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
package ozone
import (
"time"
"regexp"
"strconv"
"strings"
"github.com/One-com/gone/log"
"github.com/One-com/gone/metric"
"github.com/One-com/gone/http/handlers/accesslog"
"github.com/One-com/gone/http/rrwriter"
)
type meter interface {
Measure(rrwriter.RecordingResponseWriter)
}
type status_meter struct {
test func(code int) bool
meter *metric.Counter
}
func (m *status_meter) Measure(rec rrwriter.RecordingResponseWriter) {
status := rec.Status()
if m.test(status) {
m.meter.Inc(1)
}
}
type size_meter struct {
meter metric.Histogram
}
func (m *size_meter) Measure(rec rrwriter.RecordingResponseWriter) {
size := rec.Size()
m.meter.Sample(int64(size))
}
type time_meter struct {
meter metric.Timer
}
func (m *time_meter) Measure(rec rrwriter.RecordingResponseWriter) {
t := rec.GetTimeStamp()
if !t.IsZero() {
m.meter.Sample(time.Since(t))
}
}
// make a function testing status code for exact value
func exactCodeTest(val int) func(int) bool {
return func(code int) bool {
return val == code
}
}
// make a function testing status code for being in range.
// val is 100,200,300....
func rangeCodeTest(val int) func(int) bool {
return func(code int) bool {
diff := code - val
return diff >= 0 && diff < 100
}
}
// Creates an accesslog.AuditFunction based on the provided metrics spec, which
// increments metrics counters
func metricsFunction(name, spec string) accesslog.AuditFunction {
var meters []meter
spcs := strings.Split(spec, ",")
for _, spc := range spcs {
matched_ddd, _ := regexp.MatchString("\\d\\d\\d", spc)
matched_dxx, _ := regexp.MatchString("\\d[xX]{2}", spc)
switch {
case spc == "time":
log.DEBUG("Creating time metric")
meter := metric.RegisterTimer(name + ".resp-time")
meters = append(meters, &time_meter{meter: meter})
case spc == "size":
log.DEBUG("Creating size metric")
meter := metric.RegisterHistogram(name + ".resp-size")
meters = append(meters, &size_meter{meter: meter})
case matched_ddd:
i, _ := strconv.Atoi(spc)
log.DEBUG("Creating status metric", "code", spc)
meter := metric.RegisterCounter(name + ".code." + spc)
meters = append(meters, &status_meter{test: exactCodeTest(i), meter: meter})
case matched_dxx:
i, _ := strconv.Atoi(spc[0:1])
log.DEBUG("Creating status metric", "code", spc)
meter := metric.RegisterCounter(name + ".code." + spc)
meters = append(meters, &status_meter{test: rangeCodeTest(i * 100), meter: meter})
}
}
return accesslog.AuditFunction(func(rec rrwriter.RecordingResponseWriter) {
for _, mt := range meters {
mt.Measure(rec)
}
})
}