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
|
//go:build integration && perftest
// +build integration,perftest
package main
import (
"context"
"crypto/tls"
"net/http/httptrace"
"time"
"github.com/aws/aws-sdk-go/aws/request"
)
type RequestTrace struct {
ID int64
context.Context
start, finish time.Time
errs Errors
attempts []RequestAttempt
curAttempt RequestAttempt
}
func NewRequestTrace(ctx context.Context, id int64) *RequestTrace {
rt := &RequestTrace{
ID: id,
start: time.Now(),
attempts: []RequestAttempt{},
}
trace := &httptrace.ClientTrace{
GetConn: rt.getConn,
GotConn: rt.gotConn,
PutIdleConn: rt.putIdleConn,
GotFirstResponseByte: rt.gotFirstResponseByte,
Got100Continue: rt.got100Continue,
DNSStart: rt.dnsStart,
DNSDone: rt.dnsDone,
ConnectStart: rt.connectStart,
ConnectDone: rt.connectDone,
TLSHandshakeStart: rt.tlsHandshakeStart,
TLSHandshakeDone: rt.tlsHandshakeDone,
WroteHeaders: rt.wroteHeaders,
Wait100Continue: rt.wait100Continue,
WroteRequest: rt.wroteRequest,
}
rt.Context = httptrace.WithClientTrace(ctx, trace)
return rt
}
func (rt *RequestTrace) AppendError(err error) {
rt.errs = append(rt.errs, err)
}
func (rt *RequestTrace) OnCompleteAttempt(r *request.Request) {
rt.curAttempt.Start = r.AttemptTime
rt.curAttempt.Finish = time.Now()
rt.curAttempt.Err = r.Error
rt.attempts = append(rt.attempts, rt.curAttempt)
rt.curAttempt = RequestAttempt{}
}
func (rt *RequestTrace) OnSendAttempt(r *request.Request) {
rt.curAttempt.SendStart = time.Now()
}
func (rt *RequestTrace) OnCompleteRequest(r *request.Request) {}
func (rt *RequestTrace) RequestDone() {
rt.finish = time.Now()
// Last attempt includes reading the response body
rt.attempts[len(rt.attempts)-1].Finish = rt.finish
}
func (rt *RequestTrace) Err() error {
return rt.errs
}
func (rt *RequestTrace) TotalLatency() time.Duration {
return rt.finish.Sub(rt.start)
}
func (rt *RequestTrace) Attempts() []RequestAttempt {
return rt.attempts
}
func (rt *RequestTrace) Retries() int {
return len(rt.attempts) - 1
}
func (rt *RequestTrace) getConn(hostPort string) {}
func (rt *RequestTrace) gotConn(info httptrace.GotConnInfo) {
rt.curAttempt.Reused = info.Reused
}
func (rt *RequestTrace) putIdleConn(err error) {}
func (rt *RequestTrace) gotFirstResponseByte() {
rt.curAttempt.FirstResponseByte = time.Now()
}
func (rt *RequestTrace) got100Continue() {}
func (rt *RequestTrace) dnsStart(info httptrace.DNSStartInfo) {
rt.curAttempt.DNSStart = time.Now()
}
func (rt *RequestTrace) dnsDone(info httptrace.DNSDoneInfo) {
rt.curAttempt.DNSDone = time.Now()
}
func (rt *RequestTrace) connectStart(network, addr string) {
rt.curAttempt.ConnectStart = time.Now()
}
func (rt *RequestTrace) connectDone(network, addr string, err error) {
rt.curAttempt.ConnectDone = time.Now()
}
func (rt *RequestTrace) tlsHandshakeStart() {
rt.curAttempt.TLSHandshakeStart = time.Now()
}
func (rt *RequestTrace) tlsHandshakeDone(state tls.ConnectionState, err error) {
rt.curAttempt.TLSHandshakeDone = time.Now()
}
func (rt *RequestTrace) wroteHeaders() {}
func (rt *RequestTrace) wait100Continue() {}
func (rt *RequestTrace) wroteRequest(info httptrace.WroteRequestInfo) {
rt.curAttempt.RequestWritten = time.Now()
}
type RequestAttempt struct {
Start, Finish time.Time
SendStart time.Time
Err error
Reused bool
DNSStart, DNSDone time.Time
ConnectStart, ConnectDone time.Time
TLSHandshakeStart, TLSHandshakeDone time.Time
RequestWritten time.Time
FirstResponseByte time.Time
}
|