-
Notifications
You must be signed in to change notification settings - Fork 1
/
timer_metrics.go
82 lines (69 loc) · 1.71 KB
/
timer_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
package timermetrics
import (
"log"
"math"
"sort"
"sync"
"time"
)
type TimerMetrics struct {
sync.Mutex
timings durations
prefix string
statusEvery int
}
// start a new TimerMetrics to print out metrics every n times
func NewTimerMetrics(statusEvery int, prefix string) *TimerMetrics {
s := &TimerMetrics{
statusEvery: statusEvery,
prefix: prefix,
}
if statusEvery > 0 {
s.timings = make(durations, 0, statusEvery)
}
return s
}
type durations []time.Duration
func (s durations) Len() int { return len(s) }
func (s durations) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s durations) Less(i, j int) bool { return s[i] < s[j] }
func percentile(perc float64, arr []time.Duration) time.Duration {
length := len(arr)
if length == 0 {
return 0
}
indexOfPerc := int(math.Ceil(((perc / 100.0) * float64(length)) + 0.5))
if indexOfPerc >= length {
indexOfPerc = length - 1
}
return arr[indexOfPerc]
}
func (m *TimerMetrics) Status(startTime time.Time) {
if m.statusEvery == 0 {
return
}
m.StatusDuration(time.Now().Sub(startTime))
}
func (m *TimerMetrics) StatusDuration(duration time.Duration) {
if m.statusEvery == 0 {
return
}
m.Lock()
m.timings = append(m.timings, duration)
if len(m.timings) < cap(m.timings) {
m.Unlock()
return
}
var total time.Duration
for _, v := range m.timings {
total += v
}
avgMs := (total.Seconds() * 1000) / float64(len(m.timings))
sort.Sort(m.timings)
p95Ms := percentile(95.0, m.timings).Seconds() * 1000
p99Ms := percentile(99.0, m.timings).Seconds() * 1000
log.Printf("%s finished %d - 99th: %.02fms - 95th: %.02fms - avg: %.02fms",
m.prefix, len(m.timings), p99Ms, p95Ms, avgMs)
m.timings = m.timings[:0]
m.Unlock()
}