github.com/aavshr/aws-sdk-go@v1.41.3/awstesting/integration/performance/s3UploadManager/metric.go (about) 1 //go:build integration && perftest 2 // +build integration,perftest 3 4 package main 5 6 import ( 7 "context" 8 "crypto/tls" 9 "fmt" 10 "net/http/httptrace" 11 "strconv" 12 "strings" 13 "time" 14 15 "github.com/aavshr/aws-sdk-go/aws/request" 16 ) 17 18 type RequestTrace struct { 19 Operation string 20 ID string 21 22 context.Context 23 24 start, finish time.Time 25 26 errs Errors 27 attempts []RequestAttempt 28 curAttempt RequestAttempt 29 } 30 31 func NewRequestTrace(ctx context.Context, op, id string) *RequestTrace { 32 rt := &RequestTrace{ 33 Operation: op, 34 ID: id, 35 start: time.Now(), 36 attempts: []RequestAttempt{}, 37 curAttempt: RequestAttempt{ 38 ID: id, 39 }, 40 } 41 42 trace := &httptrace.ClientTrace{ 43 GetConn: rt.getConn, 44 GotConn: rt.gotConn, 45 PutIdleConn: rt.putIdleConn, 46 GotFirstResponseByte: rt.gotFirstResponseByte, 47 Got100Continue: rt.got100Continue, 48 DNSStart: rt.dnsStart, 49 DNSDone: rt.dnsDone, 50 ConnectStart: rt.connectStart, 51 ConnectDone: rt.connectDone, 52 TLSHandshakeStart: rt.tlsHandshakeStart, 53 TLSHandshakeDone: rt.tlsHandshakeDone, 54 WroteHeaders: rt.wroteHeaders, 55 Wait100Continue: rt.wait100Continue, 56 WroteRequest: rt.wroteRequest, 57 } 58 59 rt.Context = httptrace.WithClientTrace(ctx, trace) 60 61 return rt 62 } 63 64 func (rt *RequestTrace) AppendError(err error) { 65 rt.errs = append(rt.errs, err) 66 } 67 func (rt *RequestTrace) OnSendAttempt(r *request.Request) { 68 rt.curAttempt.SendStart = time.Now() 69 } 70 func (rt *RequestTrace) OnCompleteAttempt(r *request.Request) { 71 rt.curAttempt.Start = r.AttemptTime 72 rt.curAttempt.Finish = time.Now() 73 rt.curAttempt.Err = r.Error 74 75 if r.Error != nil { 76 rt.AppendError(r.Error) 77 } 78 79 rt.attempts = append(rt.attempts, rt.curAttempt) 80 rt.curAttempt = RequestAttempt{ 81 ID: rt.curAttempt.ID, 82 AttemptNum: rt.curAttempt.AttemptNum + 1, 83 } 84 } 85 func (rt *RequestTrace) OnComplete(r *request.Request) { 86 rt.finish = time.Now() 87 // Last attempt includes reading the response body 88 if len(rt.attempts) > 0 { 89 rt.attempts[len(rt.attempts)-1].Finish = rt.finish 90 } 91 } 92 93 func (rt *RequestTrace) Err() error { 94 if len(rt.errs) != 0 { 95 return rt.errs 96 } 97 return nil 98 } 99 func (rt *RequestTrace) TotalLatency() time.Duration { 100 return rt.finish.Sub(rt.start) 101 } 102 func (rt *RequestTrace) Attempts() []RequestAttempt { 103 return rt.attempts 104 } 105 func (rt *RequestTrace) Retries() int { 106 return len(rt.attempts) - 1 107 } 108 109 func (rt *RequestTrace) getConn(hostPort string) {} 110 func (rt *RequestTrace) gotConn(info httptrace.GotConnInfo) { 111 rt.curAttempt.Reused = info.Reused 112 } 113 func (rt *RequestTrace) putIdleConn(err error) {} 114 func (rt *RequestTrace) gotFirstResponseByte() { 115 rt.curAttempt.FirstResponseByte = time.Now() 116 } 117 func (rt *RequestTrace) got100Continue() {} 118 func (rt *RequestTrace) dnsStart(info httptrace.DNSStartInfo) { 119 rt.curAttempt.DNSStart = time.Now() 120 } 121 func (rt *RequestTrace) dnsDone(info httptrace.DNSDoneInfo) { 122 rt.curAttempt.DNSDone = time.Now() 123 } 124 func (rt *RequestTrace) connectStart(network, addr string) { 125 rt.curAttempt.ConnectStart = time.Now() 126 } 127 func (rt *RequestTrace) connectDone(network, addr string, err error) { 128 rt.curAttempt.ConnectDone = time.Now() 129 } 130 func (rt *RequestTrace) tlsHandshakeStart() { 131 rt.curAttempt.TLSHandshakeStart = time.Now() 132 } 133 func (rt *RequestTrace) tlsHandshakeDone(state tls.ConnectionState, err error) { 134 rt.curAttempt.TLSHandshakeDone = time.Now() 135 } 136 func (rt *RequestTrace) wroteHeaders() { 137 rt.curAttempt.WroteHeaders = time.Now() 138 } 139 func (rt *RequestTrace) wait100Continue() { 140 rt.curAttempt.Read100Continue = time.Now() 141 } 142 func (rt *RequestTrace) wroteRequest(info httptrace.WroteRequestInfo) { 143 rt.curAttempt.RequestWritten = time.Now() 144 } 145 146 type RequestAttempt struct { 147 Start, Finish time.Time 148 SendStart time.Time 149 Err error 150 151 Reused bool 152 ID string 153 AttemptNum int 154 155 DNSStart, DNSDone time.Time 156 ConnectStart, ConnectDone time.Time 157 TLSHandshakeStart, TLSHandshakeDone time.Time 158 WroteHeaders time.Time 159 RequestWritten time.Time 160 Read100Continue time.Time 161 FirstResponseByte time.Time 162 } 163 164 func (a RequestAttempt) String() string { 165 const sep = ", " 166 167 var w strings.Builder 168 w.WriteString(a.ID + "-" + strconv.Itoa(a.AttemptNum) + sep) 169 w.WriteString("Latency:" + durToMSString(a.Finish.Sub(a.Start)) + sep) 170 w.WriteString("SDKPreSend:" + durToMSString(a.SendStart.Sub(a.Start)) + sep) 171 172 writeStart := a.SendStart 173 fmt.Fprintf(&w, "ConnReused:%t"+sep, a.Reused) 174 if !a.Reused { 175 w.WriteString("DNS:" + durToMSString(a.DNSDone.Sub(a.DNSStart)) + sep) 176 w.WriteString("Connect:" + durToMSString(a.ConnectDone.Sub(a.ConnectStart)) + sep) 177 w.WriteString("TLS:" + durToMSString(a.TLSHandshakeDone.Sub(a.TLSHandshakeStart)) + sep) 178 writeStart = a.TLSHandshakeDone 179 } 180 181 writeHeader := a.WroteHeaders.Sub(writeStart) 182 w.WriteString("WriteHeader:" + durToMSString(writeHeader) + sep) 183 if !a.Read100Continue.IsZero() { 184 // With 100-continue 185 w.WriteString("Read100Cont:" + durToMSString(a.Read100Continue.Sub(a.WroteHeaders)) + sep) 186 w.WriteString("WritePayload:" + durToMSString(a.FirstResponseByte.Sub(a.RequestWritten)) + sep) 187 188 w.WriteString("RespRead:" + durToMSString(a.Finish.Sub(a.RequestWritten)) + sep) 189 } else { 190 // No 100-continue 191 w.WriteString("WritePayload:" + durToMSString(a.RequestWritten.Sub(a.WroteHeaders)) + sep) 192 193 if !a.FirstResponseByte.IsZero() { 194 w.WriteString("RespFirstByte:" + durToMSString(a.FirstResponseByte.Sub(a.RequestWritten)) + sep) 195 w.WriteString("RespRead:" + durToMSString(a.Finish.Sub(a.FirstResponseByte)) + sep) 196 } 197 } 198 199 return w.String() 200 } 201 202 func durToMSString(v time.Duration) string { 203 ms := float64(v) / float64(time.Millisecond) 204 return fmt.Sprintf("%0.6f", ms) 205 }