forked from tsenart/vegeta
-
Notifications
You must be signed in to change notification settings - Fork 0
/
reporters.go
102 lines (87 loc) · 2.72 KB
/
reporters.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
package vegeta
import (
"encoding/json"
"fmt"
"io"
"strings"
"text/tabwriter"
)
// A Report represents the state a Reporter uses to write out its reports.
type Report interface {
// Add adds a given *Result to a Report.
Add(*Result)
}
// Closer wraps the optional Report Close method.
type Closer interface {
// Close permantently closes a Report, running any necessary book keeping.
Close()
}
// A Reporter function writes out reports to the given io.Writer or returns an
// error in case of failure.
type Reporter func(io.Writer) error
// Report is a convenience method wrapping the Reporter function type.
func (rep Reporter) Report(w io.Writer) error { return rep(w) }
// NewHistogramReporter returns a Reporter that writes out a Histogram as
// aligned, formatted text.
func NewHistogramReporter(h *Histogram) Reporter {
return func(w io.Writer) (err error) {
tw := tabwriter.NewWriter(w, 0, 8, 2, ' ', tabwriter.StripEscape)
if _, err = fmt.Fprintf(tw, "Bucket\t\t#\t%%\tHistogram\n"); err != nil {
return err
}
for i, count := range h.Counts {
ratio := float64(count) / float64(h.Total)
lo, hi := h.Buckets.Nth(i)
pad := strings.Repeat("#", int(ratio*75))
_, err = fmt.Fprintf(tw, "[%s,\t%s]\t%d\t%.2f%%\t%s\n", lo, hi, count, ratio*100, pad)
if err != nil {
return nil
}
}
return tw.Flush()
}
}
// NewTextReporter returns a Reporter that writes out Metrics as aligned,
// formatted text.
func NewTextReporter(m *Metrics) Reporter {
const fmtstr = "Requests\t[total, rate]\t%d, %.2f\n" +
"Duration\t[total, attack, wait]\t%s, %s, %s\n" +
"Latencies\t[mean, 50, 95, 99, max]\t%s, %s, %s, %s, %s\n" +
"Bytes In\t[total, mean]\t%d, %.2f\n" +
"Bytes Out\t[total, mean]\t%d, %.2f\n" +
"Success\t[ratio]\t%.2f%%\n" +
"Status Codes\t[code:count]\t"
return func(w io.Writer) (err error) {
tw := tabwriter.NewWriter(w, 0, 8, 2, ' ', tabwriter.StripEscape)
if _, err = fmt.Fprintf(tw, fmtstr,
m.Requests, m.Rate,
m.Duration+m.Wait, m.Duration, m.Wait,
m.Latencies.Mean, m.Latencies.P50, m.Latencies.P95, m.Latencies.P99, m.Latencies.Max,
m.BytesIn.Total, m.BytesIn.Mean,
m.BytesOut.Total, m.BytesOut.Mean,
m.Success*100,
); err != nil {
return err
}
for code, count := range m.StatusCodes {
if _, err = fmt.Fprintf(tw, "%s:%d ", code, count); err != nil {
return err
}
}
if _, err = fmt.Fprintln(tw, "\nError Set:"); err != nil {
return err
}
for _, e := range m.Errors {
if _, err = fmt.Fprintln(tw, e); err != nil {
return err
}
}
return tw.Flush()
}
}
// NewJSONReporter returns a Reporter that writes out Metrics as JSON.
func NewJSONReporter(m *Metrics) Reporter {
return func(w io.Writer) error {
return json.NewEncoder(w).Encode(m)
}
}