rack-mini-profiler 3.1.1 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +1 -1
- data/lib/html/includes.js +3 -2
- data/lib/html/speedscope/{import.cf0fa83f.js → import.8ae8aa3d.js} +26 -18
- data/lib/html/speedscope/index.html +1 -1
- data/lib/html/speedscope/release.txt +3 -3
- data/lib/html/speedscope/{speedscope.44364064.js → speedscope.f27db165.js} +99 -106
- data/lib/mini_profiler/actions.rb +152 -0
- data/lib/mini_profiler/asset_version.rb +1 -1
- data/lib/mini_profiler/profiling_methods.rb +4 -0
- data/lib/mini_profiler/storage/memcache_store.rb +9 -0
- data/lib/mini_profiler/timer_struct/request.rb +6 -0
- data/lib/mini_profiler/timer_struct/sql.rb +3 -1
- data/lib/mini_profiler/version.rb +1 -1
- data/lib/mini_profiler/views.rb +192 -0
- data/lib/mini_profiler.rb +54 -352
- data/lib/mini_profiler_rails/railtie.rb +10 -0
- data/lib/mini_profiler_rails/railtie_methods.rb +1 -1
- data/lib/patches/sql_patches.rb +2 -2
- data/rack-mini-profiler.gemspec +1 -1
- metadata +8 -6
data/lib/mini_profiler.rb
CHANGED
@@ -12,11 +12,15 @@ require 'mini_profiler/context'
|
|
12
12
|
require 'mini_profiler/client_settings'
|
13
13
|
require 'mini_profiler/gc_profiler'
|
14
14
|
require 'mini_profiler/snapshots_transporter'
|
15
|
+
require 'mini_profiler/views'
|
16
|
+
require 'mini_profiler/actions'
|
15
17
|
|
16
18
|
module Rack
|
17
19
|
class MiniProfiler
|
18
|
-
|
20
|
+
include Actions
|
21
|
+
include Views
|
19
22
|
|
23
|
+
class << self
|
20
24
|
include Rack::MiniProfiler::ProfilingMethods
|
21
25
|
attr_accessor :subscribe_sql_active_record
|
22
26
|
|
@@ -37,14 +41,6 @@ module Rack
|
|
37
41
|
@config ||= Config.default
|
38
42
|
end
|
39
43
|
|
40
|
-
def resources_root
|
41
|
-
@resources_root ||= ::File.expand_path("../html", __FILE__)
|
42
|
-
end
|
43
|
-
|
44
|
-
def share_template
|
45
|
-
@share_template ||= ERB.new(::File.read(::File.expand_path("html/share.html", ::File.dirname(__FILE__))))
|
46
|
-
end
|
47
|
-
|
48
44
|
def current
|
49
45
|
Thread.current[:mini_profiler_private]
|
50
46
|
end
|
@@ -138,70 +134,6 @@ module Rack
|
|
138
134
|
@config.user_provider.call(env)
|
139
135
|
end
|
140
136
|
|
141
|
-
def serve_results(env)
|
142
|
-
request = Rack::Request.new(env)
|
143
|
-
id = request.params['id']
|
144
|
-
group_name = request.params['group']
|
145
|
-
is_snapshot = group_name && group_name.size > 0
|
146
|
-
if is_snapshot
|
147
|
-
page_struct = @storage.load_snapshot(id, group_name)
|
148
|
-
else
|
149
|
-
page_struct = @storage.load(id)
|
150
|
-
end
|
151
|
-
if !page_struct && is_snapshot
|
152
|
-
id = ERB::Util.html_escape(id)
|
153
|
-
return [404, {}, ["Snapshot with id '#{id}' not found"]]
|
154
|
-
elsif !page_struct
|
155
|
-
@storage.set_viewed(user(env), id)
|
156
|
-
id = ERB::Util.html_escape(id)
|
157
|
-
user_info = ERB::Util.html_escape(user(env))
|
158
|
-
return [404, {}, ["Request not found: #{id} - user #{user_info}"]]
|
159
|
-
end
|
160
|
-
if !page_struct[:has_user_viewed] && !is_snapshot
|
161
|
-
page_struct[:client_timings] = TimerStruct::Client.init_from_form_data(env, page_struct)
|
162
|
-
page_struct[:has_user_viewed] = true
|
163
|
-
@storage.save(page_struct)
|
164
|
-
@storage.set_viewed(user(env), id)
|
165
|
-
end
|
166
|
-
|
167
|
-
# If we're an XMLHttpRequest, serve up the contents as JSON
|
168
|
-
if request.xhr?
|
169
|
-
result_json = page_struct.to_json
|
170
|
-
[200, { 'Content-Type' => 'application/json' }, [result_json]]
|
171
|
-
else
|
172
|
-
# Otherwise give the HTML back
|
173
|
-
html = generate_html(page_struct, env)
|
174
|
-
[200, { 'Content-Type' => 'text/html' }, [html]]
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
def generate_html(page_struct, env, result_json = page_struct.to_json)
|
179
|
-
# double-assigning to suppress "assigned but unused variable" warnings
|
180
|
-
path = path = "#{env['RACK_MINI_PROFILER_ORIGINAL_SCRIPT_NAME']}#{@config.base_url_path}"
|
181
|
-
version = version = MiniProfiler::ASSET_VERSION
|
182
|
-
json = json = result_json
|
183
|
-
includes = includes = get_profile_script(env)
|
184
|
-
name = name = page_struct[:name]
|
185
|
-
duration = duration = page_struct.duration_ms.round(1).to_s
|
186
|
-
|
187
|
-
MiniProfiler.share_template.result(binding)
|
188
|
-
end
|
189
|
-
|
190
|
-
def serve_html(env)
|
191
|
-
path = env['PATH_INFO'].sub('//', '/')
|
192
|
-
file_name = path.sub(@config.base_url_path, '')
|
193
|
-
|
194
|
-
return serve_results(env) if file_name.eql?('results')
|
195
|
-
return handle_snapshots_request(env) if file_name.eql?('snapshots')
|
196
|
-
return serve_flamegraph(env) if file_name.eql?('flamegraph')
|
197
|
-
|
198
|
-
resources_env = env.dup
|
199
|
-
resources_env['PATH_INFO'] = file_name
|
200
|
-
|
201
|
-
rack_file = Rack::File.new(MiniProfiler.resources_root, 'Cache-Control' => "max-age=#{cache_control_value}")
|
202
|
-
rack_file.call(resources_env)
|
203
|
-
end
|
204
|
-
|
205
137
|
def current
|
206
138
|
MiniProfiler.current
|
207
139
|
end
|
@@ -228,13 +160,12 @@ module Rack
|
|
228
160
|
MiniProfiler.deauthorize_request if @config.authorization_mode == :allow_authorized
|
229
161
|
|
230
162
|
status = headers = body = nil
|
231
|
-
query_string = env['QUERY_STRING']
|
232
163
|
path = env['PATH_INFO'].sub('//', '/')
|
233
164
|
|
234
165
|
# Someone (e.g. Rails engine) could change the SCRIPT_NAME so we save it
|
235
166
|
env['RACK_MINI_PROFILER_ORIGINAL_SCRIPT_NAME'] = ENV['PASSENGER_BASE_URI'] || env['SCRIPT_NAME']
|
236
167
|
|
237
|
-
skip_it =
|
168
|
+
skip_it = matches_action?('skip', env) || (
|
238
169
|
@config.skip_paths &&
|
239
170
|
@config.skip_paths.any? do |p|
|
240
171
|
if p.instance_of?(String)
|
@@ -262,15 +193,29 @@ module Rack
|
|
262
193
|
end
|
263
194
|
|
264
195
|
# handle all /mini-profiler requests here
|
265
|
-
|
196
|
+
if path.start_with? @config.base_url_path
|
197
|
+
file_name = path.sub(@config.base_url_path, '')
|
198
|
+
|
199
|
+
case file_name
|
200
|
+
when 'results'
|
201
|
+
return serve_results(env)
|
202
|
+
when 'snapshots'
|
203
|
+
self.current = nil
|
204
|
+
return serve_snapshot(env)
|
205
|
+
when 'flamegraph'
|
206
|
+
return serve_flamegraph(env)
|
207
|
+
end
|
208
|
+
|
209
|
+
return client_settings.handle_cookie(serve_file(env, file_name: file_name))
|
210
|
+
end
|
266
211
|
|
267
212
|
has_disable_cookie = client_settings.disable_profiling?
|
268
213
|
# manual session disable / enable
|
269
|
-
if
|
214
|
+
if matches_action?('disable', env) || has_disable_cookie
|
270
215
|
skip_it = true
|
271
216
|
end
|
272
217
|
|
273
|
-
if
|
218
|
+
if matches_action?('enable', env)
|
274
219
|
skip_it = false
|
275
220
|
config.enabled = true
|
276
221
|
end
|
@@ -279,54 +224,32 @@ module Rack
|
|
279
224
|
status, headers, body = @app.call(env)
|
280
225
|
client_settings.disable_profiling = true
|
281
226
|
return client_settings.handle_cookie([status, headers, body])
|
282
|
-
else
|
283
|
-
client_settings.disable_profiling = false
|
284
227
|
end
|
285
228
|
|
229
|
+
# remember that profiling is not disabled (ie enabled)
|
230
|
+
client_settings.disable_profiling = false
|
231
|
+
|
286
232
|
# profile gc
|
287
|
-
if
|
288
|
-
return tool_disabled_message(client_settings) if !advanced_debugging_enabled?
|
233
|
+
if matches_action?('profile-gc', env)
|
289
234
|
current.measure = false if current
|
290
|
-
return
|
235
|
+
return serve_profile_gc(env, client_settings)
|
291
236
|
end
|
292
237
|
|
293
238
|
# profile memory
|
294
|
-
if
|
295
|
-
return
|
296
|
-
|
297
|
-
unless defined?(MemoryProfiler) && MemoryProfiler.respond_to?(:report)
|
298
|
-
message = "Please install the memory_profiler gem and require it: add gem 'memory_profiler' to your Gemfile"
|
299
|
-
status, headers, body = @app.call(env)
|
300
|
-
body.close if body.respond_to? :close
|
301
|
-
|
302
|
-
return client_settings.handle_cookie(
|
303
|
-
text_result(message, status: 500, headers: headers)
|
304
|
-
)
|
305
|
-
end
|
306
|
-
|
307
|
-
query_params = Rack::Utils.parse_nested_query(query_string)
|
308
|
-
options = {
|
309
|
-
ignore_files: query_params['memory_profiler_ignore_files'],
|
310
|
-
allow_files: query_params['memory_profiler_allow_files'],
|
311
|
-
}
|
312
|
-
options[:top] = Integer(query_params['memory_profiler_top']) if query_params.key?('memory_profiler_top')
|
313
|
-
result = StringIO.new
|
314
|
-
report = MemoryProfiler.report(options) do
|
315
|
-
_, _, body = @app.call(env)
|
316
|
-
body.close if body.respond_to? :close
|
317
|
-
end
|
318
|
-
report.pretty_print(result)
|
319
|
-
return client_settings.handle_cookie(text_result(result.string))
|
239
|
+
if matches_action?('profile-memory', env)
|
240
|
+
return serve_profile_memory(env, client_settings)
|
320
241
|
end
|
321
242
|
|
243
|
+
# any other requests past this point are going to the app to be profiled
|
244
|
+
|
322
245
|
MiniProfiler.create_current(env, @config)
|
323
246
|
|
324
|
-
if
|
247
|
+
if matches_action?('normal-backtrace', env)
|
325
248
|
client_settings.backtrace_level = ClientSettings::BACKTRACE_DEFAULT
|
326
|
-
elsif
|
249
|
+
elsif matches_action?('no-backtrace', env)
|
327
250
|
current.skip_backtrace = true
|
328
251
|
client_settings.backtrace_level = ClientSettings::BACKTRACE_NONE
|
329
|
-
elsif
|
252
|
+
elsif matches_action?('full-backtrace', env) || client_settings.backtrace_full?
|
330
253
|
current.full_backtrace = true
|
331
254
|
client_settings.backtrace_level = ClientSettings::BACKTRACE_FULL
|
332
255
|
elsif client_settings.backtrace_none?
|
@@ -335,7 +258,7 @@ module Rack
|
|
335
258
|
|
336
259
|
flamegraph = nil
|
337
260
|
|
338
|
-
trace_exceptions =
|
261
|
+
trace_exceptions = matches_action?('trace-exceptions', env) && defined? TracePoint
|
339
262
|
status, headers, body, exceptions, trace = nil
|
340
263
|
|
341
264
|
if trace_exceptions
|
@@ -359,11 +282,11 @@ module Rack
|
|
359
282
|
# Prevent response body from being compressed
|
360
283
|
env['HTTP_ACCEPT_ENCODING'] = 'identity' if config.suppress_encoding
|
361
284
|
|
362
|
-
if
|
285
|
+
if matches_action?('flamegraph', env) || matches_action?('async-flamegraph', env) || env['HTTP_REFERER'] =~ /pp=async-flamegraph/
|
363
286
|
if defined?(StackProf) && StackProf.respond_to?(:run)
|
364
287
|
# do not sully our profile with mini profiler timings
|
365
288
|
current.measure = false
|
366
|
-
match_data =
|
289
|
+
match_data = action_parameters(env)['flamegraph_sample_rate']
|
367
290
|
|
368
291
|
if match_data && !match_data[1].to_f.zero?
|
369
292
|
sample_rate = match_data[1].to_f
|
@@ -371,7 +294,7 @@ module Rack
|
|
371
294
|
sample_rate = config.flamegraph_sample_rate
|
372
295
|
end
|
373
296
|
|
374
|
-
mode_match_data =
|
297
|
+
mode_match_data = action_parameters(env)['flamegraph_mode']
|
375
298
|
|
376
299
|
if mode_match_data && [:cpu, :wall, :object, :custom].include?(mode_match_data[1].to_sym)
|
377
300
|
mode = mode_match_data[1].to_sym
|
@@ -397,18 +320,7 @@ module Rack
|
|
397
320
|
)
|
398
321
|
end
|
399
322
|
elsif path == '/rack-mini-profiler/requests'
|
400
|
-
|
401
|
-
<!DOCTYPE html>
|
402
|
-
<html>
|
403
|
-
<head>
|
404
|
-
<title>Rack::MiniProfiler Requests</title>
|
405
|
-
</head>
|
406
|
-
<body>
|
407
|
-
</body>
|
408
|
-
</html>
|
409
|
-
HTML
|
410
|
-
|
411
|
-
status, headers, body = [200, { 'Content-Type' => 'text/html' }, [blank_page_html.dup]]
|
323
|
+
status, headers, body = [200, { 'Content-Type' => 'text/html' }, [blank_page_html]]
|
412
324
|
else
|
413
325
|
status, headers, body = @app.call(env)
|
414
326
|
end
|
@@ -429,7 +341,7 @@ module Rack
|
|
429
341
|
if trace_exceptions
|
430
342
|
body.close if body.respond_to? :close
|
431
343
|
|
432
|
-
query_params =
|
344
|
+
query_params = action_parameters(env)
|
433
345
|
trace_exceptions_filter = query_params['trace_exceptions_filter']
|
434
346
|
if trace_exceptions_filter
|
435
347
|
trace_exceptions_regex = Regexp.new(trace_exceptions_filter)
|
@@ -439,19 +351,19 @@ module Rack
|
|
439
351
|
return client_settings.handle_cookie(dump_exceptions exceptions)
|
440
352
|
end
|
441
353
|
|
442
|
-
if
|
354
|
+
if matches_action?("env", env)
|
443
355
|
return tool_disabled_message(client_settings) if !advanced_debugging_enabled?
|
444
356
|
body.close if body.respond_to? :close
|
445
357
|
return client_settings.handle_cookie(dump_env env)
|
446
358
|
end
|
447
359
|
|
448
|
-
if
|
360
|
+
if matches_action?("analyze-memory", env)
|
449
361
|
return tool_disabled_message(client_settings) if !advanced_debugging_enabled?
|
450
362
|
body.close if body.respond_to? :close
|
451
363
|
return client_settings.handle_cookie(analyze_memory)
|
452
364
|
end
|
453
365
|
|
454
|
-
if
|
366
|
+
if matches_action?("help", env)
|
455
367
|
body.close if body.respond_to? :close
|
456
368
|
return client_settings.handle_cookie(help(client_settings, env))
|
457
369
|
end
|
@@ -460,7 +372,7 @@ module Rack
|
|
460
372
|
page_struct[:user] = user(env)
|
461
373
|
page_struct[:root].record_time((Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) * 1000)
|
462
374
|
|
463
|
-
if flamegraph &&
|
375
|
+
if flamegraph && matches_action?("flamegraph", env)
|
464
376
|
body.close if body.respond_to? :close
|
465
377
|
return client_settings.handle_cookie(self.flamegraph(flamegraph, path, env))
|
466
378
|
elsif flamegraph # async-flamegraph
|
@@ -485,12 +397,20 @@ module Rack
|
|
485
397
|
end
|
486
398
|
|
487
399
|
client_settings.handle_cookie([status, headers, body])
|
488
|
-
|
489
400
|
ensure
|
490
401
|
# Make sure this always happens
|
491
402
|
self.current = nil
|
492
403
|
end
|
493
404
|
|
405
|
+
def matches_action?(action, env)
|
406
|
+
env['QUERY_STRING'] =~ /#{@config.profile_parameter}=#{action}/ ||
|
407
|
+
env['HTTP_X_RACK_MINI_PROFILER'] == action
|
408
|
+
end
|
409
|
+
|
410
|
+
def action_parameters(env)
|
411
|
+
query_params = Rack::Utils.parse_nested_query(env['QUERY_STRING'])
|
412
|
+
end
|
413
|
+
|
494
414
|
def inject_profiler(env, status, headers, body)
|
495
415
|
# mini profiler is meddling with stuff, we can not cache cause we will get incorrect data
|
496
416
|
# Rack::ETag has already inserted some nonesense in the chain
|
@@ -663,79 +583,6 @@ module Rack
|
|
663
583
|
[status, headers, [body]]
|
664
584
|
end
|
665
585
|
|
666
|
-
def make_link(postfix, env)
|
667
|
-
link = env["PATH_INFO"] + "?" + env["QUERY_STRING"].sub("#{@config.profile_parameter}=help", "#{@config.profile_parameter}=#{postfix}")
|
668
|
-
"#{@config.profile_parameter}=<a href='#{ERB::Util.html_escape(link)}'>#{postfix}</a>"
|
669
|
-
end
|
670
|
-
|
671
|
-
def help(client_settings, env)
|
672
|
-
headers = { 'Content-Type' => 'text/html' }
|
673
|
-
html = <<~HTML
|
674
|
-
<!DOCTYPE html>
|
675
|
-
<html>
|
676
|
-
<head>
|
677
|
-
<title>Rack::MiniProfiler Help</title>
|
678
|
-
</head>
|
679
|
-
<body>
|
680
|
-
<pre style='line-height: 30px; font-size: 16px'>
|
681
|
-
This is the help menu of the <a href='#{Rack::MiniProfiler::SOURCE_CODE_URI}'>rack-mini-profiler</a> gem, append the following to your query string for more options:
|
682
|
-
|
683
|
-
#{make_link "help", env} : display this screen
|
684
|
-
#{make_link "env", env} : display the rack environment
|
685
|
-
#{make_link "skip", env} : skip mini profiler for this request
|
686
|
-
#{make_link "no-backtrace", env} #{"(*) " if client_settings.backtrace_none?}: don't collect stack traces from all the SQL executed (sticky, use #{@config.profile_parameter}=normal-backtrace to enable)
|
687
|
-
#{make_link "normal-backtrace", env} #{"(*) " if client_settings.backtrace_default?}: collect stack traces from all the SQL executed and filter normally
|
688
|
-
#{make_link "full-backtrace", env} #{"(*) " if client_settings.backtrace_full?}: enable full backtraces for SQL executed (use #{@config.profile_parameter}=normal-backtrace to disable)
|
689
|
-
#{make_link "disable", env} : disable profiling for this session
|
690
|
-
#{make_link "enable", env} : enable profiling for this session (if previously disabled)
|
691
|
-
#{make_link "profile-gc", env} : perform gc profiling on this request, analyzes ObjectSpace generated by request
|
692
|
-
#{make_link "profile-memory", env} : requires the memory_profiler gem, new location based report
|
693
|
-
#{make_link "flamegraph", env} : a graph representing sampled activity (requires the stackprof gem).
|
694
|
-
#{make_link "async-flamegraph", env} : store flamegraph data for this page and all its AJAX requests. Flamegraph links will be available in the mini-profiler UI (requires the stackprof gem).
|
695
|
-
#{make_link "flamegraph&flamegraph_sample_rate=1", env}: creates a flamegraph with the specified sample rate (in ms). Overrides value set in config
|
696
|
-
#{make_link "flamegraph&flamegraph_mode=cpu", env}: creates a flamegraph with the specified mode (one of cpu, wall, object, or custom). Overrides value set in config
|
697
|
-
#{make_link "flamegraph_embed", env} : a graph representing sampled activity (requires the stackprof gem), embedded resources for use on an intranet.
|
698
|
-
#{make_link "trace-exceptions", env} : will return all the spots where your application raises exceptions
|
699
|
-
#{make_link "analyze-memory", env} : will perform basic memory analysis of heap
|
700
|
-
</pre>
|
701
|
-
</body>
|
702
|
-
</html>
|
703
|
-
HTML
|
704
|
-
|
705
|
-
[200, headers, [html]]
|
706
|
-
end
|
707
|
-
|
708
|
-
def flamegraph(graph, path, env)
|
709
|
-
headers = { 'Content-Type' => 'text/html' }
|
710
|
-
iframe_src = "#{public_base_path(env)}speedscope/index.html"
|
711
|
-
html = <<~HTML
|
712
|
-
<!DOCTYPE html>
|
713
|
-
<html>
|
714
|
-
<head>
|
715
|
-
<title>Rack::MiniProfiler Flamegraph</title>
|
716
|
-
<style>
|
717
|
-
body { margin: 0; height: 100vh; }
|
718
|
-
#speedscope-iframe { width: 100%; height: 100%; border: none; }
|
719
|
-
</style>
|
720
|
-
</head>
|
721
|
-
<body>
|
722
|
-
<script type="text/javascript">
|
723
|
-
var graph = #{JSON.generate(graph)};
|
724
|
-
var json = JSON.stringify(graph);
|
725
|
-
var blob = new Blob([json], { type: 'text/plain' });
|
726
|
-
var objUrl = encodeURIComponent(URL.createObjectURL(blob));
|
727
|
-
var iframe = document.createElement('IFRAME');
|
728
|
-
iframe.setAttribute('id', 'speedscope-iframe');
|
729
|
-
document.body.appendChild(iframe);
|
730
|
-
var iframeUrl = '#{iframe_src}#profileURL=' + objUrl + '&title=' + 'Flamegraph for #{CGI.escape(path)}';
|
731
|
-
iframe.setAttribute('src', iframeUrl);
|
732
|
-
</script>
|
733
|
-
</body>
|
734
|
-
</html>
|
735
|
-
HTML
|
736
|
-
[200, headers, [html]]
|
737
|
-
end
|
738
|
-
|
739
586
|
def ids(env)
|
740
587
|
all = ([current.page_struct[:id]] + (@storage.get_unviewed_ids(user(env)) || [])).uniq
|
741
588
|
if all.size > @config.max_traces_to_show
|
@@ -749,69 +596,6 @@ module Rack
|
|
749
596
|
ids(env).join(",")
|
750
597
|
end
|
751
598
|
|
752
|
-
# get_profile_script returns script to be injected inside current html page
|
753
|
-
# By default, profile_script is appended to the end of all html requests automatically.
|
754
|
-
# Calling get_profile_script cancels automatic append for the current page
|
755
|
-
# Use it when:
|
756
|
-
# * you have disabled auto append behaviour throught :auto_inject => false flag
|
757
|
-
# * you do not want script to be automatically appended for the current page. You can also call cancel_auto_inject
|
758
|
-
def get_profile_script(env)
|
759
|
-
path = public_base_path(env)
|
760
|
-
version = MiniProfiler::ASSET_VERSION
|
761
|
-
if @config.assets_url
|
762
|
-
url = @config.assets_url.call('rack-mini-profiler.js', version, env)
|
763
|
-
css_url = @config.assets_url.call('rack-mini-profiler.css', version, env)
|
764
|
-
end
|
765
|
-
|
766
|
-
url = "#{path}includes.js?v=#{version}" if !url
|
767
|
-
css_url = "#{path}includes.css?v=#{version}" if !css_url
|
768
|
-
|
769
|
-
content_security_policy_nonce = @config.content_security_policy_nonce ||
|
770
|
-
env["action_dispatch.content_security_policy_nonce"] ||
|
771
|
-
env["secure_headers_content_security_policy_nonce"]
|
772
|
-
|
773
|
-
settings = {
|
774
|
-
path: path,
|
775
|
-
url: url,
|
776
|
-
cssUrl: css_url,
|
777
|
-
version: version,
|
778
|
-
verticalPosition: @config.vertical_position,
|
779
|
-
horizontalPosition: @config.horizontal_position,
|
780
|
-
showTrivial: @config.show_trivial,
|
781
|
-
showChildren: @config.show_children,
|
782
|
-
maxTracesToShow: @config.max_traces_to_show,
|
783
|
-
showControls: @config.show_controls,
|
784
|
-
showTotalSqlCount: @config.show_total_sql_count,
|
785
|
-
authorized: true,
|
786
|
-
toggleShortcut: @config.toggle_shortcut,
|
787
|
-
startHidden: @config.start_hidden,
|
788
|
-
collapseResults: @config.collapse_results,
|
789
|
-
htmlContainer: @config.html_container,
|
790
|
-
hiddenCustomFields: @config.snapshot_hidden_custom_fields.join(','),
|
791
|
-
cspNonce: content_security_policy_nonce,
|
792
|
-
hotwireTurboDriveSupport: @config.enable_hotwire_turbo_drive_support,
|
793
|
-
}
|
794
|
-
|
795
|
-
if current && current.page_struct
|
796
|
-
settings[:ids] = ids_comma_separated(env)
|
797
|
-
settings[:currentId] = current.page_struct[:id]
|
798
|
-
else
|
799
|
-
settings[:ids] = []
|
800
|
-
settings[:currentId] = ""
|
801
|
-
end
|
802
|
-
|
803
|
-
# TODO : cache this snippet
|
804
|
-
script = ::File.read(::File.expand_path('html/profile_handler.js', ::File.dirname(__FILE__)))
|
805
|
-
# replace the variables
|
806
|
-
settings.each do |k, v|
|
807
|
-
regex = Regexp.new("\\{#{k.to_s}\\}")
|
808
|
-
script.gsub!(regex, v.to_s)
|
809
|
-
end
|
810
|
-
|
811
|
-
current.inject_js = false if current
|
812
|
-
script
|
813
|
-
end
|
814
|
-
|
815
599
|
# cancels automatic injection of profile script for the current page
|
816
600
|
def cancel_auto_inject(env)
|
817
601
|
current.inject_js = false
|
@@ -823,74 +607,6 @@ module Rack
|
|
823
607
|
|
824
608
|
private
|
825
609
|
|
826
|
-
def handle_snapshots_request(env)
|
827
|
-
self.current = nil
|
828
|
-
MiniProfiler.authorize_request
|
829
|
-
status = 200
|
830
|
-
headers = { 'Content-Type' => 'text/html' }
|
831
|
-
qp = Rack::Utils.parse_nested_query(env['QUERY_STRING'])
|
832
|
-
if group_name = qp["group_name"]
|
833
|
-
list = @storage.snapshots_group(group_name)
|
834
|
-
list.each do |snapshot|
|
835
|
-
snapshot[:url] = url_for_snapshot(snapshot[:id], group_name)
|
836
|
-
end
|
837
|
-
data = {
|
838
|
-
group_name: group_name,
|
839
|
-
list: list
|
840
|
-
}
|
841
|
-
else
|
842
|
-
list = @storage.snapshots_overview
|
843
|
-
list.each do |group|
|
844
|
-
group[:url] = url_for_snapshots_group(group[:name])
|
845
|
-
end
|
846
|
-
data = {
|
847
|
-
page: "overview",
|
848
|
-
list: list
|
849
|
-
}
|
850
|
-
end
|
851
|
-
data_html = <<~HTML
|
852
|
-
<div style="display: none;" id="snapshots-data">
|
853
|
-
#{data.to_json}
|
854
|
-
</div>
|
855
|
-
HTML
|
856
|
-
response = Rack::Response.new([], status, headers)
|
857
|
-
|
858
|
-
response.write <<~HTML
|
859
|
-
<!DOCTYPE html>
|
860
|
-
<html>
|
861
|
-
<head>
|
862
|
-
<title>Rack::MiniProfiler Snapshots</title>
|
863
|
-
</head>
|
864
|
-
<body class="mp-snapshots">
|
865
|
-
HTML
|
866
|
-
response.write(data_html)
|
867
|
-
script = self.get_profile_script(env)
|
868
|
-
response.write(script)
|
869
|
-
response.write <<~HTML
|
870
|
-
</body>
|
871
|
-
</html>
|
872
|
-
HTML
|
873
|
-
response.finish
|
874
|
-
end
|
875
|
-
|
876
|
-
def serve_flamegraph(env)
|
877
|
-
request = Rack::Request.new(env)
|
878
|
-
id = request.params['id']
|
879
|
-
page_struct = @storage.load(id)
|
880
|
-
|
881
|
-
if !page_struct
|
882
|
-
id = ERB::Util.html_escape(id)
|
883
|
-
user_info = ERB::Util.html_escape(user(env))
|
884
|
-
return [404, {}, ["Request not found: #{id} - user #{user_info}"]]
|
885
|
-
end
|
886
|
-
|
887
|
-
if !page_struct[:flamegraph]
|
888
|
-
return [404, {}, ["No flamegraph available for #{ERB::Util.html_escape(id)}"]]
|
889
|
-
end
|
890
|
-
|
891
|
-
self.flamegraph(page_struct[:flamegraph], page_struct[:request_path], env)
|
892
|
-
end
|
893
|
-
|
894
610
|
def rails_route_from_path(path, method)
|
895
611
|
if defined?(Rails) && defined?(ActionController::RoutingError)
|
896
612
|
hash = Rails.application.routes.recognize_path(path, method: method)
|
@@ -902,16 +618,6 @@ module Rack
|
|
902
618
|
nil
|
903
619
|
end
|
904
620
|
|
905
|
-
def url_for_snapshots_group(group_name)
|
906
|
-
qs = Rack::Utils.build_query({ group_name: group_name })
|
907
|
-
"/#{@config.base_url_path.gsub('/', '')}/snapshots?#{qs}"
|
908
|
-
end
|
909
|
-
|
910
|
-
def url_for_snapshot(id, group_name)
|
911
|
-
qs = Rack::Utils.build_query({ id: id, group: group_name })
|
912
|
-
"/#{@config.base_url_path.gsub('/', '')}/results?#{qs}"
|
913
|
-
end
|
914
|
-
|
915
621
|
def take_snapshot?(path)
|
916
622
|
@config.snapshot_every_n_requests > 0 &&
|
917
623
|
!path.start_with?(@config.base_url_path) &&
|
@@ -946,9 +652,5 @@ module Rack
|
|
946
652
|
self.current = nil
|
947
653
|
results
|
948
654
|
end
|
949
|
-
|
950
|
-
def public_base_path(env)
|
951
|
-
"#{env['RACK_MINI_PROFILER_ORIGINAL_SCRIPT_NAME']}#{@config.base_url_path}"
|
952
|
-
end
|
953
655
|
end
|
954
656
|
end
|
@@ -114,6 +114,16 @@ module Rack::MiniProfilerRails
|
|
114
114
|
Rack::MiniProfiler.binds_to_params(payload[:binds])
|
115
115
|
)
|
116
116
|
end
|
117
|
+
|
118
|
+
subscribe("instantiation.active_record") do |name, start, finish, id, payload|
|
119
|
+
next if !should_measure?
|
120
|
+
|
121
|
+
Rack::MiniProfiler.report_reader_duration(
|
122
|
+
(finish - start) * 1000,
|
123
|
+
payload[:record_count],
|
124
|
+
payload[:class_name]
|
125
|
+
)
|
126
|
+
end
|
117
127
|
end
|
118
128
|
end
|
119
129
|
@already_initialized = true
|
@@ -52,7 +52,7 @@ module Rack::MiniProfilerRailsMethods
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def get_webpacker_assets_path
|
55
|
-
if defined?(Webpacker) && Webpacker.config
|
55
|
+
if defined?(Webpacker) && Webpacker.try(:config)&.config_path&.exist?
|
56
56
|
Webpacker.config.public_output_path.to_s.gsub(Webpacker.config.public_path.to_s, "")
|
57
57
|
end
|
58
58
|
end
|
data/lib/patches/sql_patches.rb
CHANGED
@@ -30,8 +30,8 @@ class SqlPatches
|
|
30
30
|
def self.sql_patches
|
31
31
|
patches = []
|
32
32
|
|
33
|
-
patches << 'mysql2' if defined?(Mysql2::Client) && Mysql2::Client.class == Class
|
34
|
-
patches << 'pg' if defined?(PG::Result) && PG::Result.class == Class
|
33
|
+
patches << 'mysql2' if defined?(Mysql2::Client) && Mysql2::Client.class == Class && patch_rails?
|
34
|
+
patches << 'pg' if defined?(PG::Result) && PG::Result.class == Class && patch_rails?
|
35
35
|
patches << 'oracle_enhanced' if defined?(ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter) && ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class == Class &&
|
36
36
|
SqlPatches.correct_version?('~> 1.5.0', ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter) &&
|
37
37
|
patch_rails?
|
data/rack-mini-profiler.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
"CHANGELOG.md"
|
22
22
|
]
|
23
23
|
s.add_runtime_dependency 'rack', '>= 1.2.0'
|
24
|
-
s.required_ruby_version = '>= 2.
|
24
|
+
s.required_ruby_version = '>= 2.7.0'
|
25
25
|
|
26
26
|
s.metadata = {
|
27
27
|
'source_code_uri' => Rack::MiniProfiler::SOURCE_CODE_URI,
|