forked from myzhan/boomer
-
Notifications
You must be signed in to change notification settings - Fork 3
/
output.go
146 lines (119 loc) · 4.28 KB
/
output.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package boomer
import (
"fmt"
"os"
"sort"
"strconv"
"time"
"github.com/olekukonko/tablewriter"
)
// Output is primarily responsible for printing test results to different destinations
// such as consoles, files. You can write you own output and add to boomer.
// When running in standalone mode, the default output is ConsoleOutput, you can add more.
// When running in distribute mode, test results will be reported to master with or without
// an output.
// All the OnXXX function will be call in a separated goroutine, just in case some output will block.
// But it will wait for all outputs return to avoid data lost.
type Output interface {
// OnStart will be call before the test starts.
OnStart()
// By default, each output receive stats data from runner every three seconds.
// OnEvent is responsible for dealing with the data.
OnEvent(data map[string]interface{})
// OnStop will be called before the test ends.
OnStop()
}
// ConsoleOutput is the default output for standalone mode.
type ConsoleOutput struct {
}
// NewConsoleOutput returns a ConsoleOutput.
func NewConsoleOutput() *ConsoleOutput {
return &ConsoleOutput{}
}
func getMedianResponseTime(numRequests int64, responseTimes map[int64]int64) int64 {
medianResponseTime := int64(0)
if len(responseTimes) != 0 {
pos := (numRequests - 1) / 2
var sortedKeys []int64
for k := range responseTimes {
sortedKeys = append(sortedKeys, k)
}
sort.Slice(sortedKeys, func(i, j int) bool {
return sortedKeys[i] < sortedKeys[j]
})
for _, k := range sortedKeys {
if pos < responseTimes[k] {
medianResponseTime = k
break
}
pos -= responseTimes[k]
}
}
return medianResponseTime
}
func getAvgResponseTime(numRequests int64, totalResponseTime int64) (avgResponseTime float64) {
avgResponseTime = float64(0)
if numRequests != 0 {
avgResponseTime = float64(totalResponseTime) / float64(numRequests)
}
return avgResponseTime
}
func getAvgContentLength(numRequests int64, totalContentLength int64) (avgContentLength int64) {
avgContentLength = int64(0)
if numRequests != 0 {
avgContentLength = totalContentLength / numRequests
}
return avgContentLength
}
func getCurrentRps(numRequests int64, numReqsPerSecond map[int64]int64) (currentRps int64) {
currentRps = int64(0)
numReqsPerSecondLength := int64(len(numReqsPerSecond))
if numReqsPerSecondLength != 0 {
currentRps = numRequests / numReqsPerSecondLength
}
return currentRps
}
// OnStart of ConsoleOutput has nothing to do.
func (o *ConsoleOutput) OnStart() {
}
// OnStop of ConsoleOutput has nothing to do.
func (o *ConsoleOutput) OnStop() {
}
// OnEvent will print to the console.
func (o *ConsoleOutput) OnEvent(data map[string]interface{}) {
stats, ok := data["stats"].([]interface{})
if !ok {
return
}
currentTime := time.Now()
println(fmt.Sprintf("Current time: %s", currentTime.Format("2006/01/02 15:04:05")))
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Type", "Name", "# requests", "# fails", "Median", "Average", "Min", "Max", "Content Size", "# reqs/sec"})
for _, stat := range stats {
s := stat.(map[string]interface{})
row := make([]string, 10)
row[0], row[1] = s["name"].(string), s["method"].(string)
numRequests := s["num_requests"].(int64)
row[2] = strconv.FormatInt(numRequests, 10)
numFailures := s["num_failures"].(int64)
row[3] = strconv.FormatInt(numFailures, 10)
medianResponseTime := getMedianResponseTime(numRequests, s["response_times"].(map[int64]int64))
row[4] = strconv.FormatInt(medianResponseTime, 10)
totalResponseTime := s["total_response_time"].(int64)
avgResponseTime := getAvgResponseTime(numRequests, totalResponseTime)
row[5] = strconv.FormatFloat(avgResponseTime, 'f', 2, 64)
minResponseTime := s["min_response_time"].(int64)
row[6] = strconv.FormatInt(minResponseTime, 10)
maxResponseTime := s["max_response_time"].(int64)
row[7] = strconv.FormatInt(maxResponseTime, 10)
totalContentLength := s["total_content_length"].(int64)
avgContentLength := getAvgContentLength(numRequests, totalContentLength)
row[8] = strconv.FormatInt(avgContentLength, 10)
numReqsPerSecond := s["num_reqs_per_sec"].(map[int64]int64)
currentRps := getCurrentRps(numRequests, numReqsPerSecond)
row[9] = strconv.FormatInt(currentRps, 10)
table.Append(row)
}
table.Render()
println()
}