This repository has been archived by the owner on May 18, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
response_stats.go
130 lines (118 loc) · 3.14 KB
/
response_stats.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
package main
import (
"strings"
"sync"
"time"
"github.com/Sirupsen/logrus"
"github.com/honeycombio/libhoney-go"
)
// responseStats is a container for collecting statistics about events sent
// via libhoney. It counts interesting aspects of the events it gets and
// presents them for printing whenever it's called.
//
// the intent is to periodically print and flush the counters, eg once/minute
type responseStats struct {
lock *sync.Mutex
count int
statusCodes map[int]int
bodies map[string]int
errors map[string]int
maxDuration time.Duration
sumDuration time.Duration
minDuration time.Duration
event *evWithMeta
totalCount int
totalStatusCodes map[int]int
}
// newResponseStats initializes the struct's complex data types
func newResponseStats() *responseStats {
r := &responseStats{}
r.totalStatusCodes = make(map[int]int)
r.lock = &sync.Mutex{}
r.reset()
return r
}
// update adds a response into the stats container
func (r *responseStats) update(rsp libhoney.Response) {
r.lock.Lock()
defer r.lock.Unlock()
r.count += 1
r.statusCodes[rsp.StatusCode] += 1
r.bodies[strings.TrimSpace(string(rsp.Body))] += 1
if rsp.Err != nil {
r.errors[rsp.Err.Error()] += 1
}
if r.minDuration == 0 {
r.minDuration = rsp.Duration
}
if rsp.Duration < r.minDuration {
r.minDuration = rsp.Duration
} else if rsp.Duration > r.maxDuration {
r.maxDuration = rsp.Duration
}
r.sumDuration += rsp.Duration
ev := rsp.Metadata.(evWithMeta)
r.event = &ev
}
// log the current stats and reset them all to zero.
// thread safe.
func (r *responseStats) logAndReset() {
r.lock.Lock()
defer r.lock.Unlock()
r.log()
r.reset()
}
// log the current statistics to logrus.
// NOT thread safe.
func (r *responseStats) log() {
var avg time.Duration
if r.count != 0 {
avg = r.sumDuration / time.Duration(r.count)
} else {
avg = 0
}
logrus.WithFields(logrus.Fields{
"count": r.count,
"lifetime_count": r.totalCount + r.count,
"slowest": r.maxDuration,
"fastest": r.minDuration,
"avg_duration": avg,
"count_per_status": r.statusCodes,
"response_bodies": r.bodies,
"errors": r.errors,
}).Info("Summary of sent events")
if r.event != nil {
fields := make(map[string]interface{})
fields["event"] = r.event.Data
fields["event_timestamp"] = r.event.meta.timestamp
logrus.WithFields(fields).Info("Last parsed event")
}
}
// log the total count on its own
func (r *responseStats) logFinal() {
r.lock.Lock()
defer r.lock.Unlock()
r.totalCount += r.count
for code, count := range r.statusCodes {
r.totalStatusCodes[code] += count
}
logrus.WithFields(logrus.Fields{
"total attempted sends": r.totalCount,
"number sent by response status code": r.totalStatusCodes,
}).Info("Total number of events sent")
}
// reset the counters to zero.
// NOT thread safe
func (r *responseStats) reset() {
r.totalCount += r.count
for code, count := range r.statusCodes {
r.totalStatusCodes[code] += count
}
r.count = 0
r.statusCodes = make(map[int]int)
r.bodies = make(map[string]int)
r.errors = make(map[string]int)
r.maxDuration = 0
r.sumDuration = 0
r.minDuration = 0
}