Skip to content
Newer
Older
100644 192 lines (163 sloc) 7.28 KB
c7bf1c3 @jaggederest queue time, initial header work
jaggederest authored Dec 22, 2010
1 module NewRelic
2 module Agent
3 module Instrumentation
4 module QueueTime
b142a50 @jaggederest queue time in-flight - add middleware related methods
jaggederest authored Feb 17, 2011
5 unless defined?(MAIN_HEADER)
6 MAIN_HEADER = 'HTTP_X_REQUEST_START'
7 MIDDLEWARE_HEADER = 'HTTP_X_MIDDLEWARE_START'
aca6854 @jaggederest queue time finally actually measuring queue time, wip
jaggederest authored Feb 25, 2011
8 QUEUE_HEADER = 'HTTP_X_QUEUE_START'
9 ALT_QUEUE_HEADER = 'HTTP_X_QUEUE_TIME'
b142a50 @jaggederest queue time in-flight - add middleware related methods
jaggederest authored Feb 18, 2011
10 APP_HEADER = 'HTTP_X_APPLICATION_START'
11
12 HEADER_REGEX = /([^\s\/,(t=)]+)? ?t=([0-9]+)/
13 SERVER_METRIC = 'WebFrontend/WebServer/'
32cdce8 @jaggederest queue time now includes middleware header parsing
jaggederest authored Feb 17, 2011
14 MIDDLEWARE_METRIC = 'Middleware/'
aca6854 @jaggederest queue time finally actually measuring queue time, wip
jaggederest authored Feb 25, 2011
15 # no individual queue metric - more than one queue?!
32cdce8 @jaggederest queue time now includes middleware header parsing
jaggederest authored Feb 18, 2011
16 ALL_SERVER_METRIC = 'WebFrontend/WebServer/all'
17 ALL_MIDDLEWARE_METRIC = 'Middleware/all'
aca6854 @jaggederest queue time finally actually measuring queue time, wip
jaggederest authored Feb 25, 2011
18 ALL_QUEUE_METRIC = 'WebFrontend/QueueTime'
19 end
20
21 def current_time
22 Time.now
b142a50 @jaggederest queue time in-flight - add middleware related methods
jaggederest authored Feb 18, 2011
23 end
94e449d @jaggederest inflight queue time - add test for overlap
jaggederest authored Feb 17, 2011
24
aca6854 @jaggederest queue time finally actually measuring queue time, wip
jaggederest authored Feb 25, 2011
25 def parse_frontend_headers(env)
26 add_end_time_header(current_time, env)
b142a50 @jaggederest queue time in-flight - add middleware related methods
jaggederest authored Feb 18, 2011
27 parse_middleware_time_from(env)
94e449d @jaggederest inflight queue time - add test for overlap
jaggederest authored Feb 18, 2011
28 parse_queue_time_from(env)
aca6854 @jaggederest queue time finally actually measuring queue time, wip
jaggederest authored Feb 25, 2011
29 parse_server_time_from(env)
b142a50 @jaggederest queue time in-flight - add middleware related methods
jaggederest authored Feb 18, 2011
30 end
31
aca6854 @jaggederest queue time finally actually measuring queue time, wip
jaggederest authored Feb 25, 2011
32 private
33
34
94e449d @jaggederest inflight queue time - add test for overlap
jaggederest authored Feb 18, 2011
35 # main method to extract server time info from env hash,
c7bf1c3 @jaggederest queue time, initial header work
jaggederest authored Dec 23, 2010
36 # records individual server metrics and one roll-up for all servers
94e449d @jaggederest inflight queue time - add test for overlap
jaggederest authored Feb 18, 2011
37 def parse_server_time_from(env)
b142a50 @jaggederest queue time in-flight - add middleware related methods
jaggederest authored Feb 18, 2011
38 end_time = parse_end_time(env)
39 matches = get_matches_from_header(MAIN_HEADER, env)
32cdce8 @jaggederest queue time now includes middleware header parsing
jaggederest authored Feb 18, 2011
40
b142a50 @jaggederest queue time in-flight - add middleware related methods
jaggederest authored Feb 18, 2011
41 record_individual_server_stats(end_time, matches)
42 record_rollup_server_stat(end_time, matches)
43 end
44
45 def parse_middleware_time_from(env)
46 end_time = parse_end_time(env)
47 matches = get_matches_from_header(MIDDLEWARE_HEADER, env)
48
49 record_individual_middleware_stats(end_time, matches)
50 record_rollup_middleware_stat(end_time, matches)
aca6854 @jaggederest queue time finally actually measuring queue time, wip
jaggederest authored Feb 25, 2011
51 # notice this bit: we reset the end time to the earliest
52 # middleware tag so that other frontend metrics don't
53 # include this time.
54 add_end_time_header(find_oldest_time(matches), env)
55 end
56
57 def parse_queue_time_from(env)
58 first_time = nil
59 end_time = parse_end_time(env)
60 alternate_length = check_for_alternate_queue_length(env)
61 if alternate_length
62 # skip all that fancy-dan stuff
63 NewRelic::Agent.get_stats(ALL_QUEUE_METRIC).trace_call(alternate_length)
64 first_time = (end_time - alternate_length) # should be a time
65 else
66 matches = get_matches_from_header(QUEUE_HEADER, env)
67 record_rollup_queue_stat(end_time, matches)
68 first_time = find_oldest_time(matches)
69 end
70 # notice this bit: we reset the end time to the earliest
71 # queue tag or the start time minus the queue time so that
72 # other frontend metrics don't include this time.
73 add_end_time_header(first_time, env)
74 end
75
76 def check_for_alternate_queue_length(env)
77 header = env[ALT_QUEUE_HEADER]
78 return nil unless header
79 (header.gsub('t=', '').to_i / 1_000_000.0)
c7bf1c3 @jaggederest queue time, initial header work
jaggederest authored Dec 23, 2010
80 end
81
b142a50 @jaggederest queue time in-flight - add middleware related methods
jaggederest authored Feb 18, 2011
82 def get_matches_from_header(header, env)
83 return [] if env.nil?
84 get_matches(env[header]).map do |name, time|
85 convert_to_name_time_pair(name, time)
86 end
87 end
88
89 def get_matches(string)
90 string.to_s.scan(HEADER_REGEX)
91 end
92
93 def convert_to_name_time_pair(name, time)
94 [name, convert_from_microseconds(time.to_i)]
95 end
32cdce8 @jaggederest queue time now includes middleware header parsing
jaggederest authored Feb 18, 2011
96
97 def record_individual_stat_of_type(type, end_time, matches)
98 matches = matches.sort_by {|name, time| time }
99 matches.reverse!
100 matches.inject(end_time) {|end_time, pair|
101 name, time = pair
aca6854 @jaggederest queue time finally actually measuring queue time, wip
jaggederest authored Feb 25, 2011
102 self.send(type, name, time, end_time) if name
32cdce8 @jaggederest queue time now includes middleware header parsing
jaggederest authored Feb 18, 2011
103 time
104 }
105 end
b142a50 @jaggederest queue time in-flight - add middleware related methods
jaggederest authored Feb 18, 2011
106
c7bf1c3 @jaggederest queue time, initial header work
jaggederest authored Dec 23, 2010
107 # goes through the list of servers and records each one in
108 # reverse order, subtracting the time for each successive
109 # server from the earlier ones in the list.
110 # an example because it's complicated:
111 # start data:
112 # [['a', Time.at(1000)], ['b', Time.at(1001)]], start time: Time.at(1002)
113 # initial run: Time.at(1002), ['b', Time.at(1001)]
114 # next: Time.at(1001), ['a', Time.at(1000)]
115 # see tests for more
116 def record_individual_server_stats(end_time, matches) # (Time, [[String, Time]]) -> nil
aca6854 @jaggederest queue time finally actually measuring queue time, wip
jaggederest authored Feb 25, 2011
117 record_individual_stat_of_type(:record_server_time_for, end_time, matches)
c7bf1c3 @jaggederest queue time, initial header work
jaggederest authored Dec 23, 2010
118 end
119
32cdce8 @jaggederest queue time now includes middleware header parsing
jaggederest authored Feb 18, 2011
120 def record_individual_middleware_stats(end_time, matches)
aca6854 @jaggederest queue time finally actually measuring queue time, wip
jaggederest authored Feb 25, 2011
121 record_individual_stat_of_type(:record_middleware_time_for, end_time, matches)
32cdce8 @jaggederest queue time now includes middleware header parsing
jaggederest authored Feb 18, 2011
122 end
123
c7bf1c3 @jaggederest queue time, initial header work
jaggederest authored Dec 23, 2010
124 # records the total time for all servers in a rollup metric
b142a50 @jaggederest queue time in-flight - add middleware related methods
jaggederest authored Feb 18, 2011
125 def record_rollup_server_stat(end_time, matches) # (Time, [String, Time]) -> nil
c7bf1c3 @jaggederest queue time, initial header work
jaggederest authored Dec 23, 2010
126 # default to the start time if we have no header
b142a50 @jaggederest queue time in-flight - add middleware related methods
jaggederest authored Feb 18, 2011
127 first_time = find_oldest_time(matches) || end_time
32cdce8 @jaggederest queue time now includes middleware header parsing
jaggederest authored Feb 18, 2011
128 record_time_stat(ALL_SERVER_METRIC, first_time, end_time)
c7bf1c3 @jaggederest queue time, initial header work
jaggederest authored Dec 23, 2010
129 end
32cdce8 @jaggederest queue time now includes middleware header parsing
jaggederest authored Feb 18, 2011
130
131 def record_rollup_middleware_stat(end_time, matches)
132 first_time = find_oldest_time(matches) || end_time
133 record_time_stat(ALL_MIDDLEWARE_METRIC, first_time, end_time)
134 end
135
c7bf1c3 @jaggederest queue time, initial header work
jaggederest authored Dec 23, 2010
136 # searches for the first server to touch a request
137 def find_oldest_time(matches) # [[String, Time]] -> Time
138 matches.map do |name, time|
139 time
140 end.min
141 end
142
143 # basically just assembles the metric name
94e449d @jaggederest inflight queue time - add test for overlap
jaggederest authored Feb 18, 2011
144 def record_server_time_for(name, start_time, end_time) # (Maybe String, Time, Time) -> nil
b142a50 @jaggederest queue time in-flight - add middleware related methods
jaggederest authored Feb 18, 2011
145 record_time_stat(SERVER_METRIC + name, start_time, end_time) if name
c7bf1c3 @jaggederest queue time, initial header work
jaggederest authored Dec 23, 2010
146 end
147
32cdce8 @jaggederest queue time now includes middleware header parsing
jaggederest authored Feb 18, 2011
148 def record_middleware_time_for(name, start_time, end_time)
149 record_time_stat(MIDDLEWARE_METRIC + name, start_time, end_time)
150 end
151
c7bf1c3 @jaggederest queue time, initial header work
jaggederest authored Dec 23, 2010
152 # Checks that the time is not negative, and does the actual
153 # data recording
154 def record_time_stat(name, start_time, end_time) # (String, Time, Time) -> nil
155 total_time = end_time - start_time
156 if total_time < 0
b142a50 @jaggederest queue time in-flight - add middleware related methods
jaggederest authored Feb 18, 2011
157 raise "should not provide an end time less than start time: #{end_time} is less than #{start_time}"
c7bf1c3 @jaggederest queue time, initial header work
jaggederest authored Dec 23, 2010
158 else
159 NewRelic::Agent.get_stats(name).trace_call(total_time)
160 end
161 end
162
b142a50 @jaggederest queue time in-flight - add middleware related methods
jaggederest authored Feb 18, 2011
163 def add_end_time_header(end_time, env) # (Time, Env) -> nil
164 env[APP_HEADER] = "t=#{convert_to_microseconds(end_time)}"
165 end
166
167 def parse_end_time(env)
168 header = env[APP_HEADER]
169 return Time.now unless header
170 convert_from_microseconds(header.gsub('t=', '').to_i)
171 end
172
c7bf1c3 @jaggederest queue time, initial header work
jaggederest authored Dec 23, 2010
173 # convert a time to the value provided by the header, for convenience
174 def convert_to_microseconds(time) # Time -> Int
175 raise TypeError.new('Cannot convert a non-time into microseconds') unless time.is_a?(Time) || time.is_a?(Numeric)
176 return time if time.is_a?(Numeric)
aca6854 @jaggederest queue time finally actually measuring queue time, wip
jaggederest authored Feb 25, 2011
177 (time.to_f * 1_000_000).to_i
c7bf1c3 @jaggederest queue time, initial header work
jaggederest authored Dec 23, 2010
178 end
179
180 # convert a time from the header value (time in microseconds)
181 # into a ruby time object
182 def convert_from_microseconds(int) # Int -> Time
183 raise TypeError.new('Cannot convert a non-number into a time') unless int.is_a?(Time) || int.is_a?(Numeric)
b142a50 @jaggederest queue time in-flight - add middleware related methods
jaggederest authored Feb 18, 2011
184 return int if int.is_a?(Time)
aca6854 @jaggederest queue time finally actually measuring queue time, wip
jaggederest authored Feb 25, 2011
185 Time.at((int / 1_000_000.0))
c7bf1c3 @jaggederest queue time, initial header work
jaggederest authored Dec 23, 2010
186 end
187 end
188 end
189 end
190 end
191
Something went wrong with that request. Please try again.