forked from kubernetes-retired/contrib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
results.go
111 lines (95 loc) · 3.16 KB
/
results.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
package vegeta
import (
"encoding/gob"
"encoding/json"
"fmt"
"io"
"sort"
"time"
)
func init() {
gob.Register(&Result{})
}
// Result represents the metrics defined out of an http.Response
// generated by each target hit
type Result struct {
Code uint16 `json:"code"`
Timestamp time.Time `json:"timestamp"`
Latency time.Duration `json:"latency"`
BytesOut uint64 `json:"bytes_out"`
BytesIn uint64 `json:"bytes_in"`
Error string `json:"error"`
}
// End returns the time at which a Result ended.
func (r *Result) End() time.Time { return r.Timestamp.Add(r.Latency) }
// Results is a slice of Results.
type Results []Result
// Add implements the Add method of the Report interface by appending the given
// Result to the slice.
func (rs *Results) Add(r *Result) { *rs = append(*rs, *r) }
// Close implements the Close method of the Report interface by sorting the
// Results.
func (rs *Results) Close() { sort.Sort(rs) }
// The following methods implement sort.Interface
func (rs Results) Len() int { return len(rs) }
func (rs Results) Less(i, j int) bool { return rs[i].Timestamp.Before(rs[j].Timestamp) }
func (rs Results) Swap(i, j int) { rs[i], rs[j] = rs[j], rs[i] }
// A Decoder decodes a Result and returns an error in case of failure.
type Decoder func(*Result) error
// NewDecoder returns a new Result decoder closure for the given io.Readers.
// It round robins across the io.Readers on every invocation and decoding error.
func NewDecoder(readers ...io.Reader) Decoder {
dec := make([]*gob.Decoder, len(readers))
for i := range readers {
dec[i] = gob.NewDecoder(readers[i])
}
var seq uint64
return func(r *Result) (err error) {
for range dec {
robin := seq % uint64(len(dec))
seq++
if err = dec[robin].Decode(r); err != nil {
continue
}
return nil
}
return err
}
}
// Decode is an an adapter method calling the Decoder function itself with the
// given parameters.
func (dec Decoder) Decode(r *Result) error { return dec(r) }
// An Encoder encodes a Result and returns an error in case of failure.
type Encoder func(*Result) error
// NewEncoder returns a new Result encoder closure for the given io.Writer
func NewEncoder(r io.Writer) Encoder {
enc := gob.NewEncoder(r)
return func(r *Result) error {
return enc.Encode(r)
}
}
// Encode is an an adapter method calling the Encoder function itself with the
// given parameters.
func (enc Encoder) Encode(r *Result) error { return enc(r) }
// NewCSVEncoder returns an Encoder that dumps the given *Result as a CSV
// record with six columns. The columns are: UNIX timestamp in ns since epoch,
// HTTP status code, request latency in ns, bytes out, bytes in, and lastly the error.
func NewCSVEncoder(w io.Writer) Encoder {
return func(r *Result) error {
_, err := fmt.Fprintf(w, "%d,%d,%d,%d,%d,\"%s\"\n",
r.Timestamp.UnixNano(),
r.Code,
r.Latency.Nanoseconds(),
r.BytesOut,
r.BytesIn,
r.Error,
)
return err
}
}
// NewJSONEncoder returns an Encoder that dumps the given *Results as a JSON
// object.
func NewJSONEncoder(w io.Writer) Encoder {
enc := json.NewEncoder(w)
return func(r *Result) error { return enc.Encode(r) }
}