forked from technologize/otel-go-contrib
/
transport.go
103 lines (83 loc) · 2.12 KB
/
transport.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
package otelhttpmetrics
import (
"net/http"
"time"
semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
)
type transport struct {
rt http.RoundTripper
cfg *config
}
func NewTransport(base http.RoundTripper, options ...Option) *transport {
if base == nil {
base = http.DefaultTransport
}
cfg := defaultConfig()
for _, option := range options {
option.apply(cfg)
}
if cfg.recorder == nil {
cfg.recorder = GetRecorder("")
}
t := transport{
rt: base,
cfg: cfg,
}
return &t
}
func (t *transport) RoundTrip(r *http.Request) (*http.Response, error) {
start := time.Now()
cfg := t.cfg
recorder := cfg.recorder
if !cfg.shouldRecord(r) {
return t.RoundTrip(r)
}
reqAttributes := cfg.attributes(r)
if cfg.recordInFlight {
recorder.AddInflightRequests(r.Context(), 1, reqAttributes)
defer recorder.AddInflightRequests(r.Context(), -1, reqAttributes)
}
res, err := t.rt.RoundTrip(r)
defer func() {
if err != nil {
return
}
resAttributes := append(reqAttributes[0:0], reqAttributes...)
if cfg.groupedStatus {
code := int(res.StatusCode/100) * 100
resAttributes = append(resAttributes, semconv.HTTPStatusCodeKey.Int(code))
} else {
resAttributes = append(resAttributes, semconv.HTTPAttributesFromHTTPStatusCode(res.StatusCode)...)
}
recorder.AddRequests(r.Context(), 1, resAttributes)
if cfg.recordSize {
requestSize := computeApproximateRequestSize(r)
recorder.ObserveHTTPRequestSize(r.Context(), requestSize, resAttributes)
recorder.ObserveHTTPResponseSize(r.Context(), int64(res.ContentLength), resAttributes)
}
if cfg.recordDuration {
recorder.ObserveHTTPRequestDuration(r.Context(), time.Since(start), resAttributes)
}
}()
return res, err
}
func computeApproximateRequestSize(r *http.Request) int64 {
s := 0
if r.URL != nil {
s = len(r.URL.Path)
}
s += len(r.Method)
s += len(r.Proto)
for name, values := range r.Header {
s += len(name)
for _, value := range values {
s += len(value)
}
}
s += len(r.Host)
// N.B. r.Form and r.MultipartForm are assumed to be included in r.URL.
if r.ContentLength != -1 {
s += int(r.ContentLength)
}
return int64(s)
}