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
|
# File 'lib/profiler/instrumentation/net_http_instrumentation.rb', line 13
def request(req, body = nil, &block)
collector = Thread.current[:profiler_http_collector]
return super unless collector
return super if Thread.current[:profiler_http_recording]
host = address.to_s
return super if NetHttpInstrumentation.skip_host?(host)
url = build_url(host, port, req.path, use_ssl?)
req_body = req.body.to_s
req_body = body.to_s if req_body.empty? && body
= req.to_hash.transform_values { |v| v.join(", ") }
request_id = SecureRandom.hex(8)
started_at = Time.now.iso8601(3)
t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
Thread.current[:profiler_http_recording] = true
response = super
duration = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0) * 1000).round(2)
resp_body_raw = response.body.to_s
resp_content_encoding = response["content-encoding"].to_s.strip.downcase
resp_body = NetHttpInstrumentation.decompress_body(resp_body_raw, resp_content_encoding)
resp_content_type = response["content-type"].to_s
req_content_type = req["content-type"].to_s
processed_req = req_body.empty? ? { body: nil, encoding: "text" } : NetHttpInstrumentation.process_body(req_body, req_content_type)
processed_resp = NetHttpInstrumentation.process_body(resp_body, resp_content_type)
t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
collector.record_request(
id: request_id,
started_at: started_at,
url: url,
method: req.method,
status: response.code.to_i,
duration: duration,
request_headers: ,
request_body: processed_req[:body],
request_body_encoding: processed_req[:encoding],
request_size: req_body.bytesize,
response_headers: response.to_hash.transform_values { |v| v.join(", ") },
response_body: processed_resp[:body],
response_body_encoding: processed_resp[:encoding],
response_size: resp_body_raw.bytesize,
backtrace: NetHttpInstrumentation.
)
fg = Thread.current[:profiler_flamegraph_collector]
fg&.record_http_event(started_at: t0, finished_at: t1, url: url, method: req.method, status: response.code.to_i)
response
rescue => e
if defined?(t0) && t0
duration = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0) * 1000).round(2)
collector&.record_request(
id: defined?(request_id) ? request_id : SecureRandom.hex(8),
started_at: defined?(started_at) ? started_at : Time.now.iso8601(3),
url: url,
method: req.method,
status: 0,
duration: duration,
request_headers: defined?() ? : {},
request_body: nil,
request_body_encoding: "text",
request_size: 0,
response_headers: {},
response_body: nil,
response_body_encoding: "text",
response_size: 0,
backtrace: NetHttpInstrumentation.,
error: e.message
)
end
raise
ensure
Thread.current[:profiler_http_recording] = false
end
|