-
Notifications
You must be signed in to change notification settings - Fork 89
/
request_queue_time_converter.rb
71 lines (53 loc) · 2.09 KB
/
request_queue_time_converter.rb
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
module ScoutApm
module LayerConverters
class RequestQueueTimeConverter < ConverterBase
HEADERS = %w(X-Queue-Start X-Request-Start X-QUEUE-START X-REQUEST-START x-queue-start x-request-start)
WEBSOCKET_HEADERS = %w(SEC_WEBSOCKET_VERSION Sec-WebSocket-Version SEC_WEBSOCKET_PROTOCOL Sec-WebSocket-Protocol SEC_WEBSOCKET_KEY Sec-WebSocket-Key)
def headers
request.headers
end
def record!
return unless request.web?
return unless context.config.value('record_queue_time')
return unless headers
@context.logger.debug headers.inspect
@context.logger.debug "Request over websocket? #{request_over_websocket?}"
raw_start = locate_timestamp
return unless raw_start
parsed_start = parse(raw_start)
return unless parsed_start
request_start = root_layer.start_time
queue_time = (request_start - parsed_start).to_f
# If we end up with a negative value, just bail out and don't report anything
return if queue_time < 0
meta = MetricMeta.new("QueueTime/Request", {:scope => scope_layer.legacy_metric_name})
stat = MetricStats.new(true)
stat.update!(queue_time)
metrics = { meta => stat }
@store.track!(metrics)
metrics # this result must be returned so it can be accessed by transaction callback extensions
end
private
def request_over_websocket?
WEBSOCKET_HEADERS.any? { |header| headers[header] }
end
# Looks through the possible headers with this data, and extracts the raw
# value of the header
# Returns nil if not found
def locate_timestamp
return nil unless headers
header = HEADERS.find { |candidate| headers[candidate] }
if header
data = headers[header]
data.to_s.gsub(/(t=|\.)/, '')
else
nil
end
end
# Returns a timestamp in fractional seconds since epoch
def parse(time_string)
Time.at("#{time_string[0,10]}.#{time_string[10,13]}".to_f)
end
end
end
end