diff --git a/requests/response.go b/requests/response.go index 7955bfe..68df76a 100644 --- a/requests/response.go +++ b/requests/response.go @@ -5,7 +5,7 @@ import ( "os" "time" - "github.com/aykhans/dodo/utils" + . "github.com/aykhans/dodo/types" "github.com/jedib0t/go-pretty/v6/table" ) @@ -18,24 +18,32 @@ type Response struct { type Responses []*Response // Print prints the responses in a tabular format, including information such as -// response count, minimum time, maximum time, and average time. +// response count, minimum time, maximum time, average time, and latency percentiles. func (respones Responses) Print() { - var ( - totalMinDuration time.Duration = respones[0].Time - totalMaxDuration time.Duration = respones[0].Time - totalDuration time.Duration - totalCount int = len(respones) - ) - mergedResponses := make(map[string][]time.Duration) + total := struct { + Count int + Min time.Duration + Max time.Duration + Sum time.Duration + P90 time.Duration + P95 time.Duration + P99 time.Duration + }{ + Count: len(respones), + Min: respones[0].Time, + Max: respones[0].Time, + } + mergedResponses := make(map[string]Durations) + var allDurations Durations for _, response := range respones { - if response.Time < totalMinDuration { - totalMinDuration = response.Time + if response.Time < total.Min { + total.Min = response.Time } - if response.Time > totalMaxDuration { - totalMaxDuration = response.Time + if response.Time > total.Max { + total.Max = response.Time } - totalDuration += response.Time + total.Sum += response.Time if response.Error != nil { mergedResponses[response.Error.Error()] = append( @@ -48,38 +56,60 @@ func (respones Responses) Print() { response.Time, ) } + allDurations = append(allDurations, response.Time) } + allDurations.Sort() + allDurationsLenAsFloat := float64(len(allDurations) - 1) + total.P90 = allDurations[int(0.90*allDurationsLenAsFloat)] + total.P95 = allDurations[int(0.95*allDurationsLenAsFloat)] + total.P99 = allDurations[int(0.99*allDurationsLenAsFloat)] t := table.NewWriter() t.SetOutputMirror(os.Stdout) t.SetStyle(table.StyleLight) t.SetColumnConfigs([]table.ColumnConfig{ - {Number: 1, WidthMax: 80}, + {Number: 1, WidthMax: 40}, }) - t.AppendHeader(table.Row{ "Response", "Count", "Min Time", "Max Time", "Average Time", + "P90", + "P95", + "P99", }) + for key, durations := range mergedResponses { + durations.Sort() + durationsLen := len(durations) + durationsLenAsFloat := float64(durationsLen - 1) + t.AppendRow(table.Row{ key, - len(durations), - utils.MinDuration(durations...), - utils.MaxDuration(durations...), - utils.AvgDuration(durations...), + durationsLen, + durations.First(), + durations.Last(), + durations.Avg(), + durations[int(0.90*durationsLenAsFloat)], + durations[int(0.95*durationsLenAsFloat)], + durations[int(0.99*durationsLenAsFloat)], }) t.AppendSeparator() } - t.AppendRow(table.Row{ - "Total", - totalCount, - totalMinDuration, - totalMaxDuration, - totalDuration / time.Duration(totalCount), - }) + + if len(mergedResponses) > 1 { + t.AppendRow(table.Row{ + "Total", + total.Count, + total.Min, + total.Max, + total.Sum / time.Duration(total.Count), // Average + total.P90, + total.P95, + total.P99, + }) + } t.Render() } diff --git a/utils/time.go b/utils/time.go deleted file mode 100644 index a502833..0000000 --- a/utils/time.go +++ /dev/null @@ -1,31 +0,0 @@ -package utils - -import "time" - -func MinDuration(durations ...time.Duration) time.Duration { - min := durations[0] - for _, d := range durations { - if d < min { - min = d - } - } - return min -} - -func MaxDuration(durations ...time.Duration) time.Duration { - max := durations[0] - for _, d := range durations { - if d > max { - max = d - } - } - return max -} - -func AvgDuration(durations ...time.Duration) time.Duration { - total := time.Duration(0) - for _, d := range durations { - total += d - } - return total / time.Duration(len(durations)) -}