rack-mini-profiler 2.1.0 → 2.3.2
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 +26 -0
- data/README.md +37 -9
- data/lib/html/includes.css +3 -1
- data/lib/html/includes.js +225 -179
- data/lib/html/includes.scss +4 -1
- data/lib/html/includes.tmpl +29 -8
- data/lib/html/profile_handler.js +1 -1
- data/lib/html/speedscope/LICENSE +21 -0
- data/lib/html/speedscope/README.md +3 -0
- data/lib/html/speedscope/demangle-cpp.1768f4cc.js +4 -0
- data/lib/html/speedscope/favicon-16x16.f74b3187.png +0 -0
- data/lib/html/speedscope/favicon-32x32.bc503437.png +0 -0
- data/lib/html/speedscope/file-format-schema.json +324 -0
- data/lib/html/speedscope/fonts/source-code-pro-regular.css +8 -0
- data/lib/html/speedscope/fonts/source-code-pro-v13-regular.woff +0 -0
- data/lib/html/speedscope/fonts/source-code-pro-v13-regular.woff2 +0 -0
- data/lib/html/speedscope/import.cf0fa83f.js +115 -0
- data/lib/html/speedscope/index.html +2 -0
- data/lib/html/speedscope/release.txt +3 -0
- data/lib/html/speedscope/reset.8c46b7a1.css +2 -0
- data/lib/html/speedscope/source-map.438fa06b.js +24 -0
- data/lib/html/speedscope/speedscope.44364064.js +200 -0
- data/lib/html/vendor.js +5 -5
- data/lib/mini_profiler/asset_version.rb +1 -1
- data/lib/mini_profiler/client_settings.rb +6 -5
- data/lib/mini_profiler/config.rb +28 -2
- data/lib/mini_profiler/profiler.rb +104 -25
- data/lib/mini_profiler/profiling_methods.rb +11 -2
- data/lib/mini_profiler/snapshots_transporter.rb +109 -0
- data/lib/mini_profiler/storage/abstract_store.rb +14 -8
- data/lib/mini_profiler/timer_struct/page.rb +57 -4
- data/lib/mini_profiler/timer_struct/sql.rb +2 -2
- data/lib/mini_profiler/version.rb +1 -1
- data/lib/mini_profiler_rails/railtie.rb +1 -1
- data/lib/patches/db/mysql2.rb +4 -27
- data/lib/patches/db/mysql2/alias_method.rb +30 -0
- data/lib/patches/db/mysql2/prepend.rb +34 -0
- data/lib/prepend_mysql2_patch.rb +5 -0
- data/lib/rack-mini-profiler.rb +1 -0
- data/rack-mini-profiler.gemspec +6 -4
- metadata +61 -14
data/lib/mini_profiler/config.rb
CHANGED
@@ -52,6 +52,11 @@ module Rack
|
|
52
52
|
@toggle_shortcut = 'alt+p'
|
53
53
|
@html_container = 'body'
|
54
54
|
@position = "top-left"
|
55
|
+
@snapshot_hidden_custom_fields = []
|
56
|
+
@snapshots_transport_destination_url = nil
|
57
|
+
@snapshots_transport_auth_key = nil
|
58
|
+
@snapshots_redact_sql_queries = true
|
59
|
+
@snapshots_transport_gzip_requests = false
|
55
60
|
|
56
61
|
self
|
57
62
|
}
|
@@ -63,19 +68,40 @@ module Rack
|
|
63
68
|
:flamegraph_sample_rate, :logger, :pre_authorize_cb, :skip_paths,
|
64
69
|
:skip_schema_queries, :storage, :storage_failure, :storage_instance,
|
65
70
|
:storage_options, :user_provider, :enable_advanced_debugging_tools,
|
66
|
-
:
|
67
|
-
attr_accessor :skip_sql_param_names, :suppress_encoding, :max_sql_param_length
|
71
|
+
:skip_sql_param_names, :suppress_encoding, :max_sql_param_length
|
68
72
|
|
69
73
|
# ui accessors
|
70
74
|
attr_accessor :collapse_results, :max_traces_to_show, :position,
|
71
75
|
:show_children, :show_controls, :show_trivial, :show_total_sql_count,
|
72
76
|
:start_hidden, :toggle_shortcut, :html_container
|
73
77
|
|
78
|
+
# snapshot related config
|
79
|
+
attr_accessor :snapshot_every_n_requests, :snapshots_limit,
|
80
|
+
:snapshot_hidden_custom_fields, :snapshots_transport_destination_url,
|
81
|
+
:snapshots_transport_auth_key, :snapshots_redact_sql_queries,
|
82
|
+
:snapshots_transport_gzip_requests
|
83
|
+
|
74
84
|
# Deprecated options
|
75
85
|
attr_accessor :use_existing_jquery
|
76
86
|
|
77
87
|
attr_reader :assets_url
|
78
88
|
|
89
|
+
# redefined - since the accessor defines it first
|
90
|
+
undef :authorization_mode=
|
91
|
+
def authorization_mode=(mode)
|
92
|
+
if mode == :whitelist
|
93
|
+
warn "[DEPRECATION] `:whitelist` authorization mode is deprecated. Please use `:allow_authorized` instead."
|
94
|
+
|
95
|
+
mode = :allow_authorized
|
96
|
+
end
|
97
|
+
|
98
|
+
warn <<~DEP unless mode == :allow_authorized || mode == :allow_all
|
99
|
+
[DEPRECATION] unknown authorization mode #{mode}. Expected `:allow_all` or `:allow_authorized`.
|
100
|
+
DEP
|
101
|
+
|
102
|
+
@authorization_mode = mode
|
103
|
+
end
|
104
|
+
|
79
105
|
def assets_url=(lmbda)
|
80
106
|
if defined?(Rack::MiniProfilerRails)
|
81
107
|
Rack::MiniProfilerRails.create_engine
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'cgi'
|
4
|
+
|
3
5
|
module Rack
|
4
6
|
class MiniProfiler
|
5
7
|
class << self
|
@@ -39,6 +41,7 @@ module Rack
|
|
39
41
|
def current=(c)
|
40
42
|
# we use TLS cause we need access to this from sql blocks and code blocks that have no access to env
|
41
43
|
Thread.current[:mini_profiler_snapshot_custom_fields] = nil
|
44
|
+
Thread.current[:mp_ongoing_snapshot] = nil
|
42
45
|
Thread.current[:mini_profiler_private] = c
|
43
46
|
end
|
44
47
|
|
@@ -94,6 +97,16 @@ module Rack
|
|
94
97
|
params
|
95
98
|
end
|
96
99
|
end
|
100
|
+
|
101
|
+
def snapshots_transporter?
|
102
|
+
!!config.snapshots_transport_destination_url &&
|
103
|
+
!!config.snapshots_transport_auth_key
|
104
|
+
end
|
105
|
+
|
106
|
+
def redact_sql_queries?
|
107
|
+
Thread.current[:mp_ongoing_snapshot] == true &&
|
108
|
+
Rack::MiniProfiler.config.snapshots_redact_sql_queries
|
109
|
+
end
|
97
110
|
end
|
98
111
|
|
99
112
|
#
|
@@ -169,6 +182,7 @@ module Rack
|
|
169
182
|
|
170
183
|
return serve_results(env) if file_name.eql?('results')
|
171
184
|
return handle_snapshots_request(env) if file_name.eql?('snapshots')
|
185
|
+
return serve_flamegraph(env) if file_name.eql?('flamegraph')
|
172
186
|
|
173
187
|
resources_env = env.dup
|
174
188
|
resources_env['PATH_INFO'] = file_name
|
@@ -200,7 +214,7 @@ module Rack
|
|
200
214
|
def call(env)
|
201
215
|
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
202
216
|
client_settings = ClientSettings.new(env, @storage, start)
|
203
|
-
MiniProfiler.deauthorize_request if @config.authorization_mode == :
|
217
|
+
MiniProfiler.deauthorize_request if @config.authorization_mode == :allow_authorized
|
204
218
|
|
205
219
|
status = headers = body = nil
|
206
220
|
query_string = env['QUERY_STRING']
|
@@ -226,7 +240,7 @@ module Rack
|
|
226
240
|
skip_it = (@config.pre_authorize_cb && !@config.pre_authorize_cb.call(env))
|
227
241
|
|
228
242
|
if skip_it || (
|
229
|
-
@config.authorization_mode == :
|
243
|
+
@config.authorization_mode == :allow_authorized &&
|
230
244
|
!client_settings.has_valid_cookie?
|
231
245
|
)
|
232
246
|
if take_snapshot?(path)
|
@@ -268,6 +282,15 @@ module Rack
|
|
268
282
|
# profile memory
|
269
283
|
if query_string =~ /pp=profile-memory/
|
270
284
|
return tool_disabled_message(client_settings) if !advanced_debugging_enabled?
|
285
|
+
|
286
|
+
unless defined?(MemoryProfiler) && MemoryProfiler.respond_to?(:report)
|
287
|
+
message = "Please install the memory_profiler gem and require it: add gem 'memory_profiler' to your Gemfile"
|
288
|
+
_, _, body = @app.call(env)
|
289
|
+
body.close if body.respond_to? :close
|
290
|
+
|
291
|
+
return client_settings.handle_cookie(text_result(message))
|
292
|
+
end
|
293
|
+
|
271
294
|
query_params = Rack::Utils.parse_nested_query(query_string)
|
272
295
|
options = {
|
273
296
|
ignore_files: query_params['memory_profiler_ignore_files'],
|
@@ -323,24 +346,28 @@ module Rack
|
|
323
346
|
# Prevent response body from being compressed
|
324
347
|
env['HTTP_ACCEPT_ENCODING'] = 'identity' if config.suppress_encoding
|
325
348
|
|
326
|
-
if query_string =~ /pp=flamegraph/
|
327
|
-
unless defined?(
|
328
|
-
|
329
|
-
|
330
|
-
|
349
|
+
if query_string =~ /pp=(async-)?flamegraph/ || env['HTTP_REFERER'] =~ /pp=async-flamegraph/
|
350
|
+
unless defined?(StackProf) && StackProf.respond_to?(:run)
|
351
|
+
headers = { 'Content-Type' => 'text/html' }
|
352
|
+
message = "Please install the stackprof gem and require it: add gem 'stackprof' to your Gemfile"
|
353
|
+
body.close if body.respond_to? :close
|
354
|
+
return client_settings.handle_cookie([500, headers, message])
|
331
355
|
else
|
332
356
|
# do not sully our profile with mini profiler timings
|
333
357
|
current.measure = false
|
334
358
|
match_data = query_string.match(/flamegraph_sample_rate=([\d\.]+)/)
|
335
359
|
|
336
|
-
mode = query_string =~ /mode=c/ ? :c : :ruby
|
337
|
-
|
338
360
|
if match_data && !match_data[1].to_f.zero?
|
339
361
|
sample_rate = match_data[1].to_f
|
340
362
|
else
|
341
363
|
sample_rate = config.flamegraph_sample_rate
|
342
364
|
end
|
343
|
-
flamegraph =
|
365
|
+
flamegraph = StackProf.run(
|
366
|
+
mode: :wall,
|
367
|
+
raw: true,
|
368
|
+
aggregate: false,
|
369
|
+
interval: (sample_rate * 1000).to_i
|
370
|
+
) do
|
344
371
|
status, headers, body = @app.call(env)
|
345
372
|
end
|
346
373
|
end
|
@@ -363,7 +390,7 @@ module Rack
|
|
363
390
|
|
364
391
|
skip_it = current.discard
|
365
392
|
|
366
|
-
if (config.authorization_mode == :
|
393
|
+
if (config.authorization_mode == :allow_authorized && !MiniProfiler.request_authorized?)
|
367
394
|
skip_it = true
|
368
395
|
end
|
369
396
|
|
@@ -404,9 +431,12 @@ module Rack
|
|
404
431
|
page_struct[:user] = user(env)
|
405
432
|
page_struct[:root].record_time((Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) * 1000)
|
406
433
|
|
407
|
-
if flamegraph
|
434
|
+
if flamegraph && query_string =~ /pp=flamegraph/
|
408
435
|
body.close if body.respond_to? :close
|
409
|
-
return client_settings.handle_cookie(self.flamegraph(flamegraph))
|
436
|
+
return client_settings.handle_cookie(self.flamegraph(flamegraph, path))
|
437
|
+
elsif flamegraph # async-flamegraph
|
438
|
+
page_struct[:has_flamegraph] = true
|
439
|
+
page_struct[:flamegraph] = flamegraph
|
410
440
|
end
|
411
441
|
|
412
442
|
begin
|
@@ -623,13 +653,14 @@ Append the following to your query string:
|
|
623
653
|
#{make_link "full-backtrace", env} #{"(*) " if client_settings.backtrace_full?}: enable full backtraces for SQL executed (use pp=normal-backtrace to disable)
|
624
654
|
#{make_link "disable", env} : disable profiling for this session
|
625
655
|
#{make_link "enable", env} : enable profiling for this session (if previously disabled)
|
626
|
-
#{make_link "profile-gc", env} : perform gc profiling on this request, analyzes ObjectSpace generated by request
|
656
|
+
#{make_link "profile-gc", env} : perform gc profiling on this request, analyzes ObjectSpace generated by request
|
627
657
|
#{make_link "profile-memory", env} : requires the memory_profiler gem, new location based report
|
628
|
-
#{make_link "flamegraph", env} :
|
658
|
+
#{make_link "flamegraph", env} : a graph representing sampled activity (requires the stackprof gem).
|
659
|
+
#{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).
|
629
660
|
#{make_link "flamegraph&flamegraph_sample_rate=1", env}: creates a flamegraph with the specified sample rate (in ms). Overrides value set in config
|
630
|
-
#{make_link "flamegraph_embed", env} :
|
631
|
-
#{make_link "trace-exceptions", env} :
|
632
|
-
#{make_link "analyze-memory", env} :
|
661
|
+
#{make_link "flamegraph_embed", env} : a graph representing sampled activity (requires the stackprof gem), embedded resources for use on an intranet.
|
662
|
+
#{make_link "trace-exceptions", env} : will return all the spots where your application raises exceptions
|
663
|
+
#{make_link "analyze-memory", env} : will perform basic memory analysis of heap
|
633
664
|
</pre>
|
634
665
|
</body>
|
635
666
|
</html>
|
@@ -638,9 +669,33 @@ Append the following to your query string:
|
|
638
669
|
[200, headers, [body]]
|
639
670
|
end
|
640
671
|
|
641
|
-
def flamegraph(graph)
|
672
|
+
def flamegraph(graph, path)
|
642
673
|
headers = { 'Content-Type' => 'text/html' }
|
643
|
-
|
674
|
+
html = <<~HTML
|
675
|
+
<!DOCTYPE html>
|
676
|
+
<html>
|
677
|
+
<head>
|
678
|
+
<style>
|
679
|
+
body { margin: 0; height: 100vh; }
|
680
|
+
#speedscope-iframe { width: 100%; height: 100%; border: none; }
|
681
|
+
</style>
|
682
|
+
</head>
|
683
|
+
<body>
|
684
|
+
<script type="text/javascript">
|
685
|
+
var graph = #{JSON.generate(graph)};
|
686
|
+
var json = JSON.stringify(graph);
|
687
|
+
var blob = new Blob([json], { type: 'text/plain' });
|
688
|
+
var objUrl = encodeURIComponent(URL.createObjectURL(blob));
|
689
|
+
var iframe = document.createElement('IFRAME');
|
690
|
+
iframe.setAttribute('id', 'speedscope-iframe');
|
691
|
+
document.body.appendChild(iframe);
|
692
|
+
var iframeUrl = '#{@config.base_url_path}speedscope/index.html#profileURL=' + objUrl + '&title=' + 'Flamegraph for #{CGI.escape(path)}';
|
693
|
+
iframe.setAttribute('src', iframeUrl);
|
694
|
+
</script>
|
695
|
+
</body>
|
696
|
+
</html>
|
697
|
+
HTML
|
698
|
+
[200, headers, [html]]
|
644
699
|
end
|
645
700
|
|
646
701
|
def ids(env)
|
@@ -689,7 +744,8 @@ Append the following to your query string:
|
|
689
744
|
toggleShortcut: @config.toggle_shortcut,
|
690
745
|
startHidden: @config.start_hidden,
|
691
746
|
collapseResults: @config.collapse_results,
|
692
|
-
htmlContainer: @config.html_container
|
747
|
+
htmlContainer: @config.html_container,
|
748
|
+
hiddenCustomFields: @config.snapshot_hidden_custom_fields.join(',')
|
693
749
|
}
|
694
750
|
|
695
751
|
if current && current.page_struct
|
@@ -770,6 +826,24 @@ Append the following to your query string:
|
|
770
826
|
response.finish
|
771
827
|
end
|
772
828
|
|
829
|
+
def serve_flamegraph(env)
|
830
|
+
request = Rack::Request.new(env)
|
831
|
+
id = request.params['id']
|
832
|
+
page_struct = @storage.load(id)
|
833
|
+
|
834
|
+
if !page_struct
|
835
|
+
id = ERB::Util.html_escape(id)
|
836
|
+
user_info = ERB::Util.html_escape(user(env))
|
837
|
+
return [404, {}, ["Request not found: #{id} - user #{user_info}"]]
|
838
|
+
end
|
839
|
+
|
840
|
+
if !page_struct[:flamegraph]
|
841
|
+
return [404, {}, ["No flamegraph available for #{ERB::Util.html_escape(id)}"]]
|
842
|
+
end
|
843
|
+
|
844
|
+
self.flamegraph(page_struct[:flamegraph], page_struct[:request_path])
|
845
|
+
end
|
846
|
+
|
773
847
|
def rails_route_from_path(path, method)
|
774
848
|
if defined?(Rails) && defined?(ActionController::RoutingError)
|
775
849
|
hash = Rails.application.routes.recognize_path(path, method: method)
|
@@ -799,6 +873,7 @@ Append the following to your query string:
|
|
799
873
|
|
800
874
|
def take_snapshot(env, start)
|
801
875
|
MiniProfiler.create_current(env, @config)
|
876
|
+
Thread.current[:mp_ongoing_snapshot] = true
|
802
877
|
results = @app.call(env)
|
803
878
|
status = results[0].to_i
|
804
879
|
if status >= 200 && status < 300
|
@@ -808,10 +883,14 @@ Append the following to your query string:
|
|
808
883
|
)
|
809
884
|
custom_fields = MiniProfiler.get_snapshot_custom_fields
|
810
885
|
page_struct[:custom_fields] = custom_fields if custom_fields
|
811
|
-
|
812
|
-
page_struct
|
813
|
-
|
814
|
-
|
886
|
+
if Rack::MiniProfiler.snapshots_transporter?
|
887
|
+
Rack::MiniProfiler::SnapshotsTransporter.transport(page_struct)
|
888
|
+
else
|
889
|
+
@storage.push_snapshot(
|
890
|
+
page_struct,
|
891
|
+
@config
|
892
|
+
)
|
893
|
+
end
|
815
894
|
end
|
816
895
|
self.current = nil
|
817
896
|
results
|
@@ -7,7 +7,14 @@ module Rack
|
|
7
7
|
def record_sql(query, elapsed_ms, params = nil)
|
8
8
|
return unless current && current.current_timer
|
9
9
|
c = current
|
10
|
-
c.current_timer.add_sql(
|
10
|
+
c.current_timer.add_sql(
|
11
|
+
redact_sql_queries? ? nil : query,
|
12
|
+
elapsed_ms,
|
13
|
+
c.page_struct,
|
14
|
+
redact_sql_queries? ? nil : params,
|
15
|
+
c.skip_backtrace,
|
16
|
+
c.full_backtrace
|
17
|
+
)
|
11
18
|
end
|
12
19
|
|
13
20
|
def start_step(name)
|
@@ -108,6 +115,9 @@ module Rack
|
|
108
115
|
end
|
109
116
|
end
|
110
117
|
end
|
118
|
+
if klass.respond_to?(:ruby2_keywords, true)
|
119
|
+
klass.send(:ruby2_keywords, with_profiling)
|
120
|
+
end
|
111
121
|
klass.send :alias_method, method, with_profiling
|
112
122
|
end
|
113
123
|
|
@@ -147,7 +157,6 @@ module Rack
|
|
147
157
|
def clean_method_name(method)
|
148
158
|
method.to_s.gsub(/[\?\!]/, "")
|
149
159
|
end
|
150
|
-
|
151
160
|
end
|
152
161
|
end
|
153
162
|
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ::Rack::MiniProfiler::SnapshotsTransporter
|
4
|
+
@@transported_snapshots_count = 0
|
5
|
+
@@successful_http_requests_count = 0
|
6
|
+
@@failed_http_requests_count = 0
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def transported_snapshots_count
|
10
|
+
@@transported_snapshots_count
|
11
|
+
end
|
12
|
+
def successful_http_requests_count
|
13
|
+
@@successful_http_requests_count
|
14
|
+
end
|
15
|
+
def failed_http_requests_count
|
16
|
+
@@failed_http_requests_count
|
17
|
+
end
|
18
|
+
|
19
|
+
def transport(snapshot)
|
20
|
+
@transporter ||= self.new(Rack::MiniProfiler.config)
|
21
|
+
@transporter.ship(snapshot)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :buffer
|
26
|
+
attr_accessor :max_buffer_size, :gzip_requests
|
27
|
+
|
28
|
+
def initialize(config)
|
29
|
+
@uri = URI(config.snapshots_transport_destination_url)
|
30
|
+
@auth_key = config.snapshots_transport_auth_key
|
31
|
+
@gzip_requests = config.snapshots_transport_gzip_requests
|
32
|
+
@thread = nil
|
33
|
+
@thread_mutex = Mutex.new
|
34
|
+
@buffer = []
|
35
|
+
@buffer_mutex = Mutex.new
|
36
|
+
@max_buffer_size = 100
|
37
|
+
@consecutive_failures_count = 0
|
38
|
+
@testing = false
|
39
|
+
end
|
40
|
+
|
41
|
+
def ship(snapshot)
|
42
|
+
@buffer_mutex.synchronize do
|
43
|
+
@buffer << snapshot
|
44
|
+
@buffer.shift if @buffer.size > @max_buffer_size
|
45
|
+
end
|
46
|
+
@thread_mutex.synchronize { start_thread }
|
47
|
+
end
|
48
|
+
|
49
|
+
def flush_buffer
|
50
|
+
buffer_content = @buffer_mutex.synchronize do
|
51
|
+
@buffer.dup if @buffer.size > 0
|
52
|
+
end
|
53
|
+
if buffer_content
|
54
|
+
headers = {
|
55
|
+
'Content-Type' => 'application/json',
|
56
|
+
'Mini-Profiler-Transport-Auth' => @auth_key
|
57
|
+
}
|
58
|
+
json = { snapshots: buffer_content }.to_json
|
59
|
+
body = if @gzip_requests
|
60
|
+
require 'zlib'
|
61
|
+
io = StringIO.new
|
62
|
+
gzip_writer = Zlib::GzipWriter.new(io)
|
63
|
+
gzip_writer.write(json)
|
64
|
+
gzip_writer.close
|
65
|
+
headers['Content-Encoding'] = 'gzip'
|
66
|
+
io.string
|
67
|
+
else
|
68
|
+
json
|
69
|
+
end
|
70
|
+
request = Net::HTTP::Post.new(@uri, headers)
|
71
|
+
request.body = body
|
72
|
+
http = Net::HTTP.new(@uri.hostname, @uri.port)
|
73
|
+
http.use_ssl = @uri.scheme == 'https'
|
74
|
+
res = http.request(request)
|
75
|
+
if res.code.to_i == 200
|
76
|
+
@@successful_http_requests_count += 1
|
77
|
+
@@transported_snapshots_count += buffer_content.size
|
78
|
+
@buffer_mutex.synchronize do
|
79
|
+
@buffer -= buffer_content
|
80
|
+
end
|
81
|
+
@consecutive_failures_count = 0
|
82
|
+
else
|
83
|
+
@@failed_http_requests_count += 1
|
84
|
+
@consecutive_failures_count += 1
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def requests_interval
|
90
|
+
[30 + backoff_delay, 60 * 60].min
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def backoff_delay
|
96
|
+
return 0 if @consecutive_failures_count == 0
|
97
|
+
2**@consecutive_failures_count
|
98
|
+
end
|
99
|
+
|
100
|
+
def start_thread
|
101
|
+
return if @thread&.alive? || @testing
|
102
|
+
@thread = Thread.new do
|
103
|
+
while true
|
104
|
+
sleep requests_interval
|
105
|
+
flush_buffer
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -36,7 +36,7 @@ module Rack
|
|
36
36
|
""
|
37
37
|
end
|
38
38
|
|
39
|
-
# a list of tokens that are permitted to access profiler in
|
39
|
+
# a list of tokens that are permitted to access profiler in explicit mode
|
40
40
|
def allowed_tokens
|
41
41
|
raise NotImplementedError.new("allowed_tokens is not implemented")
|
42
42
|
end
|
@@ -58,17 +58,21 @@ module Rack
|
|
58
58
|
fetch_snapshots do |batch|
|
59
59
|
batch.each do |snapshot|
|
60
60
|
group_name = default_snapshot_grouping(snapshot)
|
61
|
-
|
62
|
-
|
61
|
+
hash = groups[group_name] ||= {}
|
62
|
+
hash[:snapshots_count] ||= 0
|
63
|
+
hash[:snapshots_count] += 1
|
64
|
+
if !hash[:worst_score] || hash[:worst_score] < snapshot.duration_ms
|
65
|
+
groups[group_name][:worst_score] = snapshot.duration_ms
|
66
|
+
end
|
67
|
+
if !hash[:best_score] || hash[:best_score] > snapshot.duration_ms
|
68
|
+
groups[group_name][:best_score] = snapshot.duration_ms
|
63
69
|
end
|
64
70
|
end
|
65
71
|
end
|
66
72
|
groups = groups.to_a
|
67
|
-
groups.sort_by! { |name,
|
73
|
+
groups.sort_by! { |name, hash| hash[:worst_score] }
|
68
74
|
groups.reverse!
|
69
|
-
groups.map!
|
70
|
-
{ name: name, worst_score: score }
|
71
|
-
end
|
75
|
+
groups.map! { |name, hash| hash.merge(name: name) }
|
72
76
|
groups
|
73
77
|
end
|
74
78
|
|
@@ -81,7 +85,9 @@ module Rack
|
|
81
85
|
data << {
|
82
86
|
id: snapshot[:id],
|
83
87
|
duration: snapshot.duration_ms,
|
84
|
-
|
88
|
+
sql_count: snapshot[:sql_count],
|
89
|
+
timestamp: snapshot[:started_at],
|
90
|
+
custom_fields: snapshot[:custom_fields]
|
85
91
|
}
|
86
92
|
end
|
87
93
|
end
|