package stats import ( "fmt" "sync" "sync/atomic" "time" ) type Stats struct { TotalRequests atomic.Int64 SuccessCount atomic.Int64 FailCount atomic.Int64 TotalLatencyMs atomic.Int64 MinLatencyMs atomic.Int64 MaxLatencyMs atomic.Int64 TotalSMSParts atomic.Int64 StatusCodes sync.Map } func (s *Stats) RecordLatency(latencyMs int64) { s.TotalLatencyMs.Add(latencyMs) // Update min latency for { cur := s.MinLatencyMs.Load() if cur != 0 && cur <= latencyMs { break } if s.MinLatencyMs.CompareAndSwap(cur, latencyMs) { break } } // Update max latency for { cur := s.MaxLatencyMs.Load() if cur >= latencyMs { break } if s.MaxLatencyMs.CompareAndSwap(cur, latencyMs) { break } } } func (s *Stats) RecordStatusCode(code int) { key := fmt.Sprintf("%d", code) if val, ok := s.StatusCodes.Load(key); ok { counter := val.(*atomic.Int64) counter.Add(1) } else { counter := &atomic.Int64{} counter.Add(1) s.StatusCodes.Store(key, counter) } } func (s *Stats) PrintLive(elapsed time.Duration) { total := s.TotalRequests.Load() success := s.SuccessCount.Load() fail := s.FailCount.Load() avgLatency := int64(0) if total > 0 { avgLatency = s.TotalLatencyMs.Load() / total } actualRPS := float64(total) / elapsed.Seconds() fmt.Printf("\r[%s] Reqs: %d | OK: %d | Fail: %d | Avg: %dms | Min: %dms | Max: %dms | RPS: %.1f ", elapsed.Round(time.Second), total, success, fail, avgLatency, s.MinLatencyMs.Load(), s.MaxLatencyMs.Load(), actualRPS, ) } func (s *Stats) PrintFinalReport(duration time.Duration) { total := s.TotalRequests.Load() success := s.SuccessCount.Load() fail := s.FailCount.Load() avgLatency := int64(0) if total > 0 { avgLatency = s.TotalLatencyMs.Load() / total } fmt.Println("\n") fmt.Println("========================================") fmt.Println(" LOAD TEST FINAL REPORT ") fmt.Println("========================================") fmt.Printf("Duration: %s\n", duration.Round(time.Millisecond)) fmt.Printf("Total Requests: %d\n", total) fmt.Printf("Successful: %d (%.1f%%)\n", success, pct(success, total)) fmt.Printf("Failed: %d (%.1f%%)\n", fail, pct(fail, total)) fmt.Printf("Avg Latency: %d ms\n", avgLatency) fmt.Printf("Min Latency: %d ms\n", s.MinLatencyMs.Load()) fmt.Printf("Max Latency: %d ms\n", s.MaxLatencyMs.Load()) fmt.Printf("Actual RPS: %.1f\n", float64(total)/duration.Seconds()) fmt.Printf("Total SMS Parts: %d\n", s.TotalSMSParts.Load()) fmt.Println("----------------------------------------") fmt.Println("Status Code Breakdown:") s.StatusCodes.Range(func(key, value any) bool { counter := value.(*atomic.Int64) fmt.Printf(" HTTP %s: %d\n", key.(string), counter.Load()) return true }) fmt.Println("========================================") } func pct(part, total int64) float64 { if total == 0 { return 0 } return float64(part) / float64(total) * 100 }