-
Notifications
You must be signed in to change notification settings - Fork 723
/
Copy pathtrace.go
149 lines (130 loc) · 4.38 KB
/
trace.go
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Copyright (c) 2015-present Jeevanandam M ([email protected]), All rights reserved.
// resty source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
// SPDX-License-Identifier: MIT
package resty
import (
"context"
"crypto/tls"
"fmt"
"net/http/httptrace"
"time"
)
// TraceInfo struct is used to provide request trace info such as DNS lookup
// duration, Connection obtain duration, Server processing duration, etc.
type TraceInfo struct {
// DNSLookup is the duration that transport took to perform
// DNS lookup.
DNSLookup time.Duration `json:"dns_lookup_time"`
// ConnTime is the duration it took to obtain a successful connection.
ConnTime time.Duration `json:"connection_time"`
// TCPConnTime is the duration it took to obtain the TCP connection.
TCPConnTime time.Duration `json:"tcp_connection_time"`
// TLSHandshake is the duration of the TLS handshake.
TLSHandshake time.Duration `json:"tls_handshake_time"`
// ServerTime is the server's duration for responding to the first byte.
ServerTime time.Duration `json:"server_time"`
// ResponseTime is the duration since the first response byte from the server to
// request completion.
ResponseTime time.Duration `json:"response_time"`
// TotalTime is the duration of the total time request taken end-to-end.
TotalTime time.Duration `json:"total_time"`
// IsConnReused is whether this connection has been previously
// used for another HTTP request.
IsConnReused bool `json:"is_connection_reused"`
// IsConnWasIdle is whether this connection was obtained from an
// idle pool.
IsConnWasIdle bool `json:"is_connection_was_idle"`
// ConnIdleTime is the duration how long the connection that was previously
// idle, if IsConnWasIdle is true.
ConnIdleTime time.Duration `json:"connection_idle_time"`
// RequestAttempt is to represent the request attempt made during a Resty
// request execution flow, including retry count.
RequestAttempt int `json:"request_attempt"`
// RemoteAddr returns the remote network address.
RemoteAddr string `json:"remote_address"`
}
// String method returns string representation of request trace information.
func (ti TraceInfo) String() string {
return fmt.Sprintf(`TRACE INFO:
DNSLookupTime : %v
ConnTime : %v
TCPConnTime : %v
TLSHandshake : %v
ServerTime : %v
ResponseTime : %v
TotalTime : %v
IsConnReused : %v
IsConnWasIdle : %v
ConnIdleTime : %v
RequestAttempt: %v
RemoteAddr : %v`, ti.DNSLookup, ti.ConnTime, ti.TCPConnTime,
ti.TLSHandshake, ti.ServerTime, ti.ResponseTime, ti.TotalTime,
ti.IsConnReused, ti.IsConnWasIdle, ti.ConnIdleTime, ti.RequestAttempt,
ti.RemoteAddr)
}
// JSON method returns the JSON string of request trace information
func (ti TraceInfo) JSON() string {
return toJSON(ti)
}
// Clone method returns the clone copy of [TraceInfo]
func (ti TraceInfo) Clone() *TraceInfo {
ti2 := new(TraceInfo)
*ti2 = ti
return ti2
}
// clientTrace struct maps the [httptrace.ClientTrace] hooks into Fields
// with the same naming for easy understanding. Plus additional insights
// [Request].
type clientTrace struct {
getConn time.Time
dnsStart time.Time
dnsDone time.Time
connectDone time.Time
tlsHandshakeStart time.Time
tlsHandshakeDone time.Time
gotConn time.Time
gotFirstResponseByte time.Time
endTime time.Time
gotConnInfo httptrace.GotConnInfo
}
func (t *clientTrace) createContext(ctx context.Context) context.Context {
return httptrace.WithClientTrace(
ctx,
&httptrace.ClientTrace{
DNSStart: func(_ httptrace.DNSStartInfo) {
t.dnsStart = time.Now()
},
DNSDone: func(_ httptrace.DNSDoneInfo) {
t.dnsDone = time.Now()
},
ConnectStart: func(_, _ string) {
if t.dnsDone.IsZero() {
t.dnsDone = time.Now()
}
if t.dnsStart.IsZero() {
t.dnsStart = t.dnsDone
}
},
ConnectDone: func(net, addr string, err error) {
t.connectDone = time.Now()
},
GetConn: func(_ string) {
t.getConn = time.Now()
},
GotConn: func(ci httptrace.GotConnInfo) {
t.gotConn = time.Now()
t.gotConnInfo = ci
},
GotFirstResponseByte: func() {
t.gotFirstResponseByte = time.Now()
},
TLSHandshakeStart: func() {
t.tlsHandshakeStart = time.Now()
},
TLSHandshakeDone: func(_ tls.ConnectionState, _ error) {
t.tlsHandshakeDone = time.Now()
},
},
)
}