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
|
package httprange
import (
"crypto/tls"
"net/http"
"net/http/httptrace"
"time"
"gitlab.com/gitlab-org/labkit/log"
"gitlab.com/gitlab-org/gitlab-pages/metrics"
)
type tracedTransport struct {
next http.RoundTripper
}
// withRoundTripper takes an original RoundTripper, reports metrics based on the
// gauge and counter collectors passed
func (tr *tracedTransport) RoundTrip(r *http.Request) (*http.Response, error) {
r = r.WithContext(httptrace.WithClientTrace(r.Context(), newTracer(time.Now())))
return tr.next.RoundTrip(r)
}
func newTracer(start time.Time) *httptrace.ClientTrace {
trace := &httptrace.ClientTrace{
GetConn: func(host string) {
httpTraceObserve("httptrace.ClientTrace.GetConn", start)
log.WithFields(log.Fields{
"host": host,
}).Traceln("httptrace.ClientTrace.GetConn")
},
GotConn: func(connInfo httptrace.GotConnInfo) {
httpTraceObserve("httptrace.ClientTrace.GotConn", start)
log.WithFields(log.Fields{
"reused": connInfo.Reused,
"was_idle": connInfo.WasIdle,
"idle_time_ms": connInfo.IdleTime.Milliseconds(),
}).Traceln("httptrace.ClientTrace.GotConn")
},
GotFirstResponseByte: func() {
httpTraceObserve("httptrace.ClientTrace.GotFirstResponseByte", start)
},
DNSStart: func(d httptrace.DNSStartInfo) {
httpTraceObserve("httptrace.ClientTrace.DNSStart", start)
},
DNSDone: func(d httptrace.DNSDoneInfo) {
httpTraceObserve("httptrace.ClientTrace.DNSDone", start)
log.WithFields(log.Fields{}).WithError(d.Err).
Traceln("httptrace.ClientTrace.DNSDone")
},
ConnectStart: func(net, addr string) {
httpTraceObserve("httptrace.ClientTrace.ConnectStart", start)
log.WithFields(log.Fields{
"network": net,
"address": addr,
}).Traceln("httptrace.ClientTrace.ConnectStart")
},
ConnectDone: func(net string, addr string, err error) {
httpTraceObserve("httptrace.ClientTrace.ConnectDone", start)
log.WithFields(log.Fields{
"network": net,
"address": addr,
}).WithError(err).Traceln("httptrace.ClientTrace.ConnectDone")
},
TLSHandshakeStart: func() {
httpTraceObserve("httptrace.ClientTrace.TLSHandshakeStart", start)
},
TLSHandshakeDone: func(connState tls.ConnectionState, err error) {
httpTraceObserve("httptrace.ClientTrace.TLSHandshakeDone", start)
log.WithFields(log.Fields{
"version": connState.Version,
"connection_resumed": connState.DidResume,
}).WithError(err).Traceln("httptrace.ClientTrace.TLSHandshakeDone")
},
}
return trace
}
func httpTraceObserve(label string, start time.Time) {
metrics.HTTPRangeTraceDuration.WithLabelValues(label).
Observe(time.Since(start).Seconds())
}
|