@@ -3,13 +3,15 @@ package http
33import (
44 "bytes"
55 "context"
6+ "crypto/tls"
67 "encoding/json"
78 "fmt"
89 "math"
910 "net/http"
1011 "os"
1112 "path/filepath"
1213 "sort"
14+ "strconv"
1315 "time"
1416
1517 "github.com/fatih/color"
@@ -129,27 +131,27 @@ func (c *statsCollector) toStatistics(totalTime time.Duration, totalRequests uin
129131 p95 = percentile (0.95 )
130132 }
131133
132- var errors []string
134+ errors := []string {}
133135 for errStr := range c .errSet {
134136 errors = append (errors , errStr )
135137 }
136138
137139 body := params .Body
138140 if len (body ) > 300 {
139- body = body [:300 ] + " ..."
141+ body = append ( body [:293 ], [] byte ( " ......" ) ... )
140142 }
141143
142144 return & Statistics {
143145 URL : params .URL ,
144146 Method : params .Method ,
145- Body : body ,
147+ Body : string ( body ) ,
146148
147149 TotalRequests : totalRequests ,
148150 Errors : errors ,
149151 SuccessCount : c .successCount ,
150152 ErrorCount : c .errorCount ,
151- TotalTime : totalTime .Seconds (),
152- QPS : float64 (c .successCount ) / totalTime .Seconds (),
153+ TotalDuration : math . Round ( totalTime .Seconds ()* 100 ) / 100 ,
154+ QPS : math . Round ( float64 (c .successCount )/ totalTime .Seconds ()* 10 ) / 10 ,
153155
154156 AvgLatency : convertToMilliseconds (avg ),
155157 P25Latency : convertToMilliseconds (p25 ),
@@ -158,20 +160,37 @@ func (c *statsCollector) toStatistics(totalTime time.Duration, totalRequests uin
158160 MinLatency : convertToMilliseconds (minLatency ),
159161 MaxLatency : convertToMilliseconds (maxLatency ),
160162
161- TotalSent : float64 ( c .totalReqBytes ) ,
162- TotalReceived : float64 ( c .totalRespBytes ) ,
163+ TotalSent : c .totalReqBytes ,
164+ TotalReceived : c .totalRespBytes ,
163165 StatusCodes : c .statusCodeSet ,
164166 }
165167}
166168
169+ // convert float64 to string with specified precision, automatically process the last 0
170+ func float64ToString (f float64 , precision int ) string {
171+ if precision == 0 {
172+ return strconv .FormatInt (int64 (f ), 10 )
173+ }
174+ if precision >= 1 && precision <= 6 {
175+ factor := math .Pow10 (precision )
176+ rounded := math .Round (f * factor ) / factor
177+ return strconv .FormatFloat (rounded , 'f' , precision , 64 )
178+ }
179+ return strconv .FormatFloat (f , 'f' , - 1 , 64 )
180+ }
181+
182+ func float64ToStringNoRound (f float64 ) string {
183+ return strconv .FormatFloat (f , 'f' , - 1 , 64 )
184+ }
185+
167186func (c * statsCollector ) printReport (totalDuration time.Duration , totalRequests uint64 , params * HTTPReqParams ) (* Statistics , error ) {
168187 fmt .Printf ("\n ========== %s Performance Test Report ==========\n \n " , params .version )
169188 if c .successCount == 0 {
170189 _ , _ = color .New (color .Bold ).Println ("[Requests]" )
171190 fmt .Printf (" • %-19s%d\n " , "Total Requests:" , totalRequests )
172191 fmt .Printf (" • %-19s%d%s\n " , "Successful:" , 0 , color .RedString (" (0%)" ))
173192 fmt .Printf (" • %-19s%d%s\n " , "Failed:" , c .errorCount , color .RedString (" ✗" ))
174- fmt .Printf (" • %-19s%.2fs \n \n " , "Total Duration:" , totalDuration .Seconds ())
193+ fmt .Printf (" • %-19s%s s \n \n " , "Total Duration:" , float64ToString ( totalDuration .Seconds (), 2 ))
175194
176195 if len (c .statusCodeSet ) > 0 {
177196 printStatusCodeSet (c .statusCodeSet )
@@ -196,27 +215,28 @@ func (c *statsCollector) printReport(totalDuration time.Duration, totalRequests
196215 if st .SuccessCount == 0 {
197216 successStr += color .RedString (" (0%)" )
198217 } else {
199- successStr += color .YellowString (" (%d%%)" , int (float64 (st .SuccessCount )/ float64 (st .TotalRequests )* 100 ))
218+ percentage := float64ToString (float64 (st .SuccessCount )/ float64 (st .TotalRequests )* 100 , 1 )
219+ successStr += color .YellowString (" (%s%%)" , percentage )
200220 }
201221 failureStr += color .RedString (" ✗" )
202222 }
203223 }
204224 fmt .Println (successStr )
205225 fmt .Println (failureStr )
206- fmt .Printf (" • %-19s%.2fs \n " , "Total Duration:" , st .TotalTime )
207- fmt .Printf (" • %-19s%.2f req/sec\n \n " , "Throughput (QPS):" , st .QPS )
226+ fmt .Printf (" • %-19s%s s \n " , "Total Duration:" , float64ToStringNoRound ( st .TotalDuration ) )
227+ fmt .Printf (" • %-19s%s req/sec\n \n " , "Throughput (QPS):" , float64ToStringNoRound ( st .QPS ) )
208228
209229 _ , _ = color .New (color .Bold ).Println ("[Latency]" )
210- fmt .Printf (" • %-19s%.2f ms\n " , "Average:" , st .AvgLatency )
211- fmt .Printf (" • %-19s%.2f ms\n " , "Minimum:" , st .MinLatency )
212- fmt .Printf (" • %-19s%.2f ms\n " , "Maximum:" , st .MaxLatency )
213- fmt .Printf (" • %-19s%.2f ms\n " , "P25:" , st .P25Latency )
214- fmt .Printf (" • %-19s%.2f ms\n " , "P50:" , st .P50Latency )
215- fmt .Printf (" • %-19s%.2f ms\n \n " , "P95:" , st .P95Latency )
230+ fmt .Printf (" • %-19s%s ms\n " , "Average:" , float64ToStringNoRound ( st .AvgLatency ) )
231+ fmt .Printf (" • %-19s%s ms\n " , "Minimum:" , float64ToStringNoRound ( st .MinLatency ) )
232+ fmt .Printf (" • %-19s%s ms\n " , "Maximum:" , float64ToStringNoRound ( st .MaxLatency ) )
233+ fmt .Printf (" • %-19s%s ms\n " , "P25:" , float64ToStringNoRound ( st .P25Latency ) )
234+ fmt .Printf (" • %-19s%s ms\n " , "P50:" , float64ToStringNoRound ( st .P50Latency ) )
235+ fmt .Printf (" • %-19s%s ms\n \n " , "P95:" , float64ToStringNoRound ( st .P95Latency ) )
216236
217237 _ , _ = color .New (color .Bold ).Println ("[Data Transfer]" )
218- fmt .Printf (" • %-19s%.0f Bytes\n " , "Sent:" , st .TotalSent )
219- fmt .Printf (" • %-19s%.0f Bytes\n \n " , "Received:" , st .TotalReceived )
238+ fmt .Printf (" • %-19s%d Bytes\n " , "Sent:" , st .TotalSent )
239+ fmt .Printf (" • %-19s%d Bytes\n \n " , "Received:" , st .TotalReceived )
220240
221241 if len (c .statusCodeSet ) > 0 {
222242 printStatusCodeSet (st .StatusCodes )
@@ -262,7 +282,7 @@ type Statistics struct {
262282 Body string `json:"body"` // request body (JSON)
263283
264284 TotalRequests uint64 `json:"total_requests"` // total requests
265- TotalTime float64 `json:"total_time "` // seconds
285+ TotalDuration float64 `json:"total_duration "` // total duration ( seconds)
266286 SuccessCount uint64 `json:"success_count"` // successful requests (status code 2xx)
267287 ErrorCount uint64 `json:"error_count"` // failed requests (status code not 2xx)
268288 Errors []string `json:"errors"` // error details
@@ -275,10 +295,12 @@ type Statistics struct {
275295 MinLatency float64 `json:"min_latency"` // minimum latency (ms)
276296 MaxLatency float64 `json:"max_latency"` // maximum latency (ms)
277297
278- TotalSent float64 `json:"total_sent"` // total sent (bytes)
279- TotalReceived float64 `json:"total_received"` // total received (bytes)
298+ TotalSent int64 `json:"total_sent"` // total sent (bytes)
299+ TotalReceived int64 `json:"total_received"` // total received (bytes)
280300
281301 StatusCodes map [int ]int64 `json:"status_codes"` // status code distribution (count)
302+
303+ CreatedAt time.Time `json:"created_at"` // created time
282304}
283305
284306// Save saves the statistics data to a JSON file.
@@ -485,6 +507,7 @@ func (spc *statsPrometheusCollector) PushToPrometheusAsync(ctx context.Context,
485507func (spc * statsPrometheusCollector ) PushToServer (ctx context.Context , pushURL string , elapsed time.Duration , httpReqParams * HTTPReqParams , id int64 ) error {
486508 statistics := spc .statsCollector .toStatistics (elapsed , spc .statsCollector .successCount + spc .statsCollector .errorCount , httpReqParams )
487509 statistics .PerfTestID = id
510+ statistics .CreatedAt = time .Now ()
488511
489512 _ , err := postWithContext (ctx , pushURL , statistics )
490513 return err
@@ -510,7 +533,11 @@ func postWithContext(ctx context.Context, url string, data *Statistics) (*http.R
510533
511534 req .Header .Set ("Content-Type" , "application/json" )
512535
513- client := & http.Client {}
536+ client := & http.Client {
537+ Transport : & http.Transport {
538+ TLSClientConfig : & tls.Config {InsecureSkipVerify : true }, // Skip certificate validation
539+ },
540+ }
514541 resp , err := client .Do (req )
515542 if err != nil {
516543 return nil , err
0 commit comments