rack-mini-profiler 0.10.6 → 2.3.0
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 +5 -5
- data/CHANGELOG.md +129 -16
- data/README.md +116 -63
- data/lib/enable_rails_patches.rb +5 -0
- data/lib/generators/rack_profiler/install_generator.rb +2 -0
- data/lib/generators/rack_profiler/templates/rack_profiler.rb +2 -0
- data/lib/html/dot.1.1.2.min.js +2 -0
- data/lib/html/includes.css +141 -40
- data/lib/html/includes.js +1398 -970
- data/lib/html/includes.scss +547 -442
- data/lib/html/includes.tmpl +227 -142
- data/lib/html/pretty-print.js +810 -0
- data/lib/html/profile_handler.js +1 -1
- data/lib/html/rack-mini-profiler.css +3 -0
- data/lib/html/rack-mini-profiler.js +2 -0
- data/lib/html/share.html +0 -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/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 +848 -0
- data/lib/mini_profiler/asset_version.rb +3 -2
- data/lib/mini_profiler/client_settings.rb +27 -16
- data/lib/mini_profiler/config.rb +73 -46
- data/lib/mini_profiler/context.rb +5 -3
- data/lib/mini_profiler/gc_profiler.rb +17 -16
- data/lib/mini_profiler/profiler.rb +332 -94
- data/lib/mini_profiler/profiling_methods.rb +20 -15
- data/lib/mini_profiler/snapshots_transporter.rb +109 -0
- data/lib/mini_profiler/storage/abstract_store.rb +80 -0
- data/lib/mini_profiler/storage/file_store.rb +18 -13
- data/lib/mini_profiler/storage/memcache_store.rb +10 -7
- data/lib/mini_profiler/storage/memory_store.rb +63 -13
- data/lib/mini_profiler/storage/redis_store.rb +143 -7
- data/lib/mini_profiler/timer_struct/base.rb +4 -2
- data/lib/mini_profiler/timer_struct/client.rb +9 -8
- data/lib/mini_profiler/timer_struct/custom.rb +8 -5
- data/lib/mini_profiler/timer_struct/page.rb +79 -24
- data/lib/mini_profiler/timer_struct/request.rb +83 -38
- data/lib/mini_profiler/timer_struct/sql.rb +25 -22
- data/lib/mini_profiler/version.rb +3 -1
- data/lib/mini_profiler_rails/railtie.rb +91 -8
- data/lib/mini_profiler_rails/railtie_methods.rb +61 -0
- data/lib/patches/db/activerecord.rb +5 -14
- data/lib/patches/db/mongo.rb +3 -1
- data/lib/patches/db/moped.rb +5 -3
- data/lib/patches/db/mysql2.rb +8 -6
- data/lib/patches/db/neo4j.rb +3 -1
- data/lib/patches/db/nobrainer.rb +4 -2
- data/lib/patches/db/oracle_enhanced.rb +4 -2
- data/lib/patches/db/pg.rb +41 -21
- data/lib/patches/db/plucky.rb +7 -5
- data/lib/patches/db/riak.rb +15 -13
- data/lib/patches/db/rsolr.rb +6 -4
- data/lib/patches/db/sequel.rb +2 -0
- data/lib/patches/net_patches.rb +20 -8
- data/lib/patches/sql_patches.rb +17 -7
- data/lib/prepend_net_http_patch.rb +5 -0
- data/lib/rack-mini-profiler.rb +3 -3
- data/rack-mini-profiler.gemspec +23 -9
- metadata +146 -31
- data/lib/html/jquery.1.7.1.js +0 -4
- data/lib/html/jquery.tmpl.js +0 -486
- data/lib/html/list.css +0 -9
- data/lib/html/list.js +0 -38
- data/lib/html/list.tmpl +0 -34
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rack
|
2
4
|
class MiniProfiler
|
3
5
|
class ClientSettings
|
@@ -11,18 +13,19 @@ module Rack
|
|
11
13
|
attr_accessor :disable_profiling
|
12
14
|
attr_accessor :backtrace_level
|
13
15
|
|
14
|
-
|
15
16
|
def initialize(env, store, start)
|
16
|
-
request = ::Rack::Request.new(env)
|
17
|
-
@cookie = request.cookies[COOKIE_NAME]
|
17
|
+
@request = ::Rack::Request.new(env)
|
18
|
+
@cookie = @request.cookies[COOKIE_NAME]
|
18
19
|
@store = store
|
19
20
|
@start = start
|
21
|
+
@backtrace_level = nil
|
22
|
+
@orig_disable_profiling = @disable_profiling = nil
|
20
23
|
|
21
24
|
@allowed_tokens, @orig_auth_tokens = nil
|
22
25
|
|
23
26
|
if @cookie
|
24
|
-
@cookie.split(",").map{|pair| pair.split("=")}.each do |k,v|
|
25
|
-
@orig_disable_profiling = @disable_profiling = (v=='t') if k == "dp"
|
27
|
+
@cookie.split(",").map { |pair| pair.split("=") }.each do |k, v|
|
28
|
+
@orig_disable_profiling = @disable_profiling = (v == 't') if k == "dp"
|
26
29
|
@backtrace_level = v.to_i if k == "bt"
|
27
30
|
@orig_auth_tokens = v.to_s.split("|") if k == "a"
|
28
31
|
end
|
@@ -37,12 +40,12 @@ module Rack
|
|
37
40
|
end
|
38
41
|
|
39
42
|
def handle_cookie(result)
|
40
|
-
status,headers,_body = result
|
43
|
+
status, headers, _body = result
|
41
44
|
|
42
45
|
if (MiniProfiler.config.authorization_mode == :whitelist && !MiniProfiler.request_authorized?)
|
43
46
|
# this is non-obvious, don't kill the profiling cookie on errors or short requests
|
44
47
|
# this ensures that stuff that never reaches the rails stack does not kill profiling
|
45
|
-
if status.to_i >= 200 && status.to_i < 300 && ((
|
48
|
+
if status.to_i >= 200 && status.to_i < 300 && ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - @start) > 0.1)
|
46
49
|
discard_cookie!(headers)
|
47
50
|
end
|
48
51
|
else
|
@@ -66,36 +69,44 @@ module Rack
|
|
66
69
|
@cookie.nil? ||
|
67
70
|
tokens_changed
|
68
71
|
|
69
|
-
settings = {"p" =>
|
72
|
+
settings = { "p" => "t" }
|
70
73
|
settings["dp"] = "t" if @disable_profiling
|
71
74
|
settings["bt"] = @backtrace_level if @backtrace_level
|
72
75
|
settings["a"] = @allowed_tokens.join("|") if @allowed_tokens && MiniProfiler.request_authorized?
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
+
settings_string = settings.map { |k, v| "#{k}=#{v}" }.join(",")
|
77
|
+
cookie = { value: settings_string, path: '/', httponly: true }
|
78
|
+
cookie[:secure] = true if @request.ssl?
|
79
|
+
cookie[:same_site] = 'Lax'
|
80
|
+
Rack::Utils.set_cookie_header!(headers, COOKIE_NAME, cookie)
|
76
81
|
end
|
77
82
|
end
|
78
83
|
|
79
84
|
def discard_cookie!(headers)
|
80
85
|
if @cookie
|
81
|
-
Rack::Utils.delete_cookie_header!(headers, COOKIE_NAME, :
|
86
|
+
Rack::Utils.delete_cookie_header!(headers, COOKIE_NAME, path: '/')
|
82
87
|
end
|
83
88
|
end
|
84
89
|
|
85
90
|
def has_valid_cookie?
|
86
91
|
valid_cookie = !@cookie.nil?
|
87
92
|
|
88
|
-
if (MiniProfiler.config.authorization_mode == :whitelist)
|
89
|
-
|
93
|
+
if (MiniProfiler.config.authorization_mode == :whitelist) && valid_cookie
|
94
|
+
begin
|
95
|
+
@allowed_tokens ||= @store.allowed_tokens
|
96
|
+
rescue => e
|
97
|
+
if MiniProfiler.config.storage_failure != nil
|
98
|
+
MiniProfiler.config.storage_failure.call(e)
|
99
|
+
end
|
100
|
+
end
|
90
101
|
|
91
|
-
valid_cookie =
|
102
|
+
valid_cookie = @allowed_tokens &&
|
103
|
+
(Array === @orig_auth_tokens) &&
|
92
104
|
((@allowed_tokens & @orig_auth_tokens).length > 0)
|
93
105
|
end
|
94
106
|
|
95
107
|
valid_cookie
|
96
108
|
end
|
97
109
|
|
98
|
-
|
99
110
|
def disable_profiling?
|
100
111
|
@disable_profiling
|
101
112
|
end
|
data/lib/mini_profiler/config.rb
CHANGED
@@ -1,45 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rack
|
2
4
|
class MiniProfiler
|
3
5
|
class Config
|
6
|
+
def self.attr_accessor(*vars)
|
7
|
+
@attributes ||= []
|
8
|
+
@attributes.concat vars
|
9
|
+
super(*vars)
|
10
|
+
end
|
4
11
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
super(*vars)
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.attributes
|
12
|
-
@attributes
|
13
|
-
end
|
14
|
-
|
15
|
-
attr_accessor :authorization_mode, :auto_inject, :backtrace_ignores,
|
16
|
-
:backtrace_includes, :backtrace_remove, :backtrace_threshold_ms,
|
17
|
-
:base_url_path, :disable_caching, :disable_env_dump, :enabled,
|
18
|
-
:flamegraph_sample_rate, :logger, :pre_authorize_cb, :skip_paths,
|
19
|
-
:skip_schema_queries, :storage, :storage_failure, :storage_instance,
|
20
|
-
:storage_options, :user_provider
|
21
|
-
attr_accessor :skip_sql_param_names, :suppress_encoding, :max_sql_param_length
|
22
|
-
|
23
|
-
# ui accessors
|
24
|
-
attr_accessor :collapse_results, :max_traces_to_show, :position, :vertical_position, :horizontal_position,
|
25
|
-
:show_children, :show_controls, :show_trivial, :start_hidden,
|
26
|
-
:toggle_shortcut, :html_container
|
27
|
-
|
28
|
-
# Deprecated options
|
29
|
-
attr_accessor :use_existing_jquery
|
12
|
+
def self.attributes
|
13
|
+
@attributes
|
14
|
+
end
|
30
15
|
|
31
16
|
def self.default
|
32
17
|
new.instance_eval {
|
33
18
|
@auto_inject = true # automatically inject on every html page
|
34
|
-
@base_url_path = "/mini-profiler-resources/"
|
19
|
+
@base_url_path = "/mini-profiler-resources/".dup
|
35
20
|
@disable_caching = true
|
36
21
|
# called prior to rack chain, to ensure we are allowed to profile
|
37
|
-
@pre_authorize_cb = lambda {|env| true}
|
22
|
+
@pre_authorize_cb = lambda { |env| true }
|
38
23
|
|
39
24
|
# called after rack chain, to ensure we are REALLY allowed to profile
|
40
25
|
@skip_schema_queries = false
|
41
26
|
@storage = MiniProfiler::MemoryStore
|
42
|
-
@user_provider = Proc.new{|env| Rack::Request.new(env).ip}
|
27
|
+
@user_provider = Proc.new { |env| Rack::Request.new(env).ip }
|
43
28
|
@authorization_mode = :allow_all
|
44
29
|
@backtrace_threshold_ms = 0
|
45
30
|
@flamegraph_sample_rate = 0.5
|
@@ -49,44 +34,86 @@ module Rack
|
|
49
34
|
end
|
50
35
|
end
|
51
36
|
@enabled = true
|
52
|
-
@disable_env_dump = false
|
53
37
|
@max_sql_param_length = 0 # disable sql parameter collection by default
|
54
38
|
@skip_sql_param_names = /password/ # skips parameters with the name password by default
|
39
|
+
@enable_advanced_debugging_tools = false
|
40
|
+
@snapshot_every_n_requests = -1
|
41
|
+
@snapshots_limit = 1000
|
55
42
|
|
56
43
|
# ui parameters
|
57
|
-
@autorized
|
58
|
-
@collapse_results
|
59
|
-
@max_traces_to_show
|
60
|
-
@show_children
|
61
|
-
@show_controls
|
62
|
-
@show_trivial
|
63
|
-
@
|
64
|
-
@
|
65
|
-
@
|
44
|
+
@autorized = true
|
45
|
+
@collapse_results = true
|
46
|
+
@max_traces_to_show = 20
|
47
|
+
@show_children = false
|
48
|
+
@show_controls = false
|
49
|
+
@show_trivial = false
|
50
|
+
@show_total_sql_count = false
|
51
|
+
@start_hidden = false
|
52
|
+
@toggle_shortcut = 'alt+p'
|
53
|
+
@html_container = 'body'
|
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
|
66
60
|
|
67
61
|
self
|
68
62
|
}
|
69
63
|
end
|
70
64
|
|
65
|
+
attr_accessor :authorization_mode, :auto_inject, :backtrace_ignores,
|
66
|
+
:backtrace_includes, :backtrace_remove, :backtrace_threshold_ms,
|
67
|
+
:base_url_path, :disable_caching, :enabled,
|
68
|
+
:flamegraph_sample_rate, :logger, :pre_authorize_cb, :skip_paths,
|
69
|
+
:skip_schema_queries, :storage, :storage_failure, :storage_instance,
|
70
|
+
:storage_options, :user_provider, :enable_advanced_debugging_tools,
|
71
|
+
:skip_sql_param_names, :suppress_encoding, :max_sql_param_length
|
72
|
+
|
73
|
+
# ui accessors
|
74
|
+
attr_accessor :collapse_results, :max_traces_to_show, :position,
|
75
|
+
:show_children, :show_controls, :show_trivial, :show_total_sql_count,
|
76
|
+
:start_hidden, :toggle_shortcut, :html_container
|
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
|
+
|
84
|
+
# Deprecated options
|
85
|
+
attr_accessor :use_existing_jquery
|
86
|
+
|
87
|
+
attr_reader :assets_url
|
88
|
+
|
89
|
+
def assets_url=(lmbda)
|
90
|
+
if defined?(Rack::MiniProfilerRails)
|
91
|
+
Rack::MiniProfilerRails.create_engine
|
92
|
+
end
|
93
|
+
@assets_url = lmbda
|
94
|
+
end
|
95
|
+
|
96
|
+
def vertical_position
|
97
|
+
position.include?('bottom') ? 'bottom' : 'top'
|
98
|
+
end
|
99
|
+
|
100
|
+
def horizontal_position
|
101
|
+
position.include?('right') ? 'right' : 'left'
|
102
|
+
end
|
103
|
+
|
71
104
|
def merge!(config)
|
72
105
|
if config
|
73
106
|
if Hash === config
|
74
|
-
config.each{|k,v| instance_variable_set "@#{k}",v}
|
107
|
+
config.each { |k, v| instance_variable_set "@#{k}", v }
|
75
108
|
else
|
76
|
-
self.class.attributes.each{ |k|
|
109
|
+
self.class.attributes.each { |k|
|
77
110
|
v = config.send k
|
78
111
|
instance_variable_set "@#{k}", v if v
|
79
112
|
}
|
80
113
|
end
|
81
114
|
end
|
82
|
-
set_positions!
|
83
115
|
end
|
84
116
|
|
85
|
-
def set_positions!
|
86
|
-
position = (self.position && self.position.match("-")) ? self.position.split("-") : ["top", "left"]
|
87
|
-
self.vertical_position = position.first
|
88
|
-
self.horizontal_position = position.last
|
89
|
-
end
|
90
117
|
end
|
91
118
|
end
|
92
119
|
end
|
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Rack::MiniProfiler::Context
|
2
|
-
attr_accessor :inject_js
|
3
|
-
:full_backtrace
|
4
|
+
attr_accessor :inject_js, :current_timer, :page_struct, :skip_backtrace,
|
5
|
+
:full_backtrace, :discard, :mpt_init, :measure
|
4
6
|
|
5
7
|
def initialize(opts = {})
|
6
8
|
opts["measure"] = true unless opts.key? "measure"
|
7
|
-
opts.each do |k,v|
|
9
|
+
opts.each do |k, v|
|
8
10
|
self.instance_variable_set('@' + k, v)
|
9
11
|
end
|
10
12
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Rack::MiniProfiler::GCProfiler
|
2
4
|
|
3
5
|
def initialize
|
@@ -28,7 +30,7 @@ class Rack::MiniProfiler::GCProfiler
|
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
31
|
-
result = {:
|
33
|
+
result = { stats: stats, ids: ids }
|
32
34
|
@ignore << result.__id__
|
33
35
|
|
34
36
|
result
|
@@ -36,10 +38,10 @@ class Rack::MiniProfiler::GCProfiler
|
|
36
38
|
|
37
39
|
def diff_object_stats(before, after)
|
38
40
|
diff = {}.compare_by_identity
|
39
|
-
after.each do |k,v|
|
41
|
+
after.each do |k, v|
|
40
42
|
diff[k] = v - before[k]
|
41
43
|
end
|
42
|
-
before.each do |k,v|
|
44
|
+
before.each do |k, v|
|
43
45
|
diff[k] = 0 - v unless after.has_key?(k)
|
44
46
|
end
|
45
47
|
|
@@ -48,7 +50,7 @@ class Rack::MiniProfiler::GCProfiler
|
|
48
50
|
|
49
51
|
def analyze_strings(ids_before, ids_after)
|
50
52
|
result = {}
|
51
|
-
ids_after.each do |id,_|
|
53
|
+
ids_after.each do |id, _|
|
52
54
|
obj = ObjectSpace._id2ref(id)
|
53
55
|
if String === obj && !ids_before.include?(obj.object_id)
|
54
56
|
result[obj] ||= 0
|
@@ -62,8 +64,8 @@ class Rack::MiniProfiler::GCProfiler
|
|
62
64
|
new_objects = 0
|
63
65
|
memory_allocated = 0
|
64
66
|
|
65
|
-
ids_after.each do |id,_|
|
66
|
-
if !ids_before.include?(id) && obj=ObjectSpace._id2ref(id)
|
67
|
+
ids_after.each do |id, _|
|
68
|
+
if !ids_before.include?(id) && obj = ObjectSpace._id2ref(id)
|
67
69
|
# this is going to be version specific (may change in 2.1)
|
68
70
|
size = ObjectSpace.memsize_of(obj)
|
69
71
|
memory_allocated += size
|
@@ -78,15 +80,15 @@ class Rack::MiniProfiler::GCProfiler
|
|
78
80
|
memory_allocated = 0
|
79
81
|
objects = 0
|
80
82
|
|
81
|
-
ids_before.each do |id,_|
|
82
|
-
if obj=ObjectSpace._id2ref(id)
|
83
|
+
ids_before.each do |id, _|
|
84
|
+
if obj = ObjectSpace._id2ref(id)
|
83
85
|
# this is going to be version specific (may change in 2.1)
|
84
86
|
memory_allocated += ObjectSpace.memsize_of(obj)
|
85
87
|
objects += 1
|
86
88
|
end
|
87
89
|
end
|
88
90
|
|
89
|
-
[objects,memory_allocated]
|
91
|
+
[objects, memory_allocated]
|
90
92
|
end
|
91
93
|
|
92
94
|
def profile_gc(app, env)
|
@@ -105,7 +107,7 @@ class Rack::MiniProfiler::GCProfiler
|
|
105
107
|
# so we don't blow out on memory
|
106
108
|
prev_gc_state ? GC.disable : GC.enable
|
107
109
|
|
108
|
-
diff = diff_object_stats(stat_before[:stats],stat_after[:stats])
|
110
|
+
diff = diff_object_stats(stat_before[:stats], stat_after[:stats])
|
109
111
|
string_analysis = analyze_strings(stat_before[:ids], stat_after[:ids])
|
110
112
|
new_objects, memory_allocated = analyze_growth(stat_before[:ids], stat_after[:ids])
|
111
113
|
objects_before, memory_before = analyze_initial_state(stat_before[:ids])
|
@@ -120,7 +122,7 @@ Memory allocated outside heap (bytes): #{memory_before}
|
|
120
122
|
|
121
123
|
GC Stats:
|
122
124
|
--------
|
123
|
-
#{stat.map{|k,v| "#{k} : #{v}" }.sort!.join("\n")}
|
125
|
+
#{stat.map { |k, v| "#{k} : #{v}" }.sort!.join("\n")}
|
124
126
|
|
125
127
|
New bytes allocated outside of Ruby heaps: #{memory_allocated}
|
126
128
|
New objects: #{new_objects}
|
@@ -129,7 +131,7 @@ New objects: #{new_objects}
|
|
129
131
|
body << "
|
130
132
|
ObjectSpace delta caused by request:
|
131
133
|
-----------------------------------\n"
|
132
|
-
diff.to_a.delete_if{|_k, v| v == 0}.sort_by! { |_k, v| v }.reverse_each do |k,v|
|
134
|
+
diff.to_a.delete_if { |_k, v| v == 0 }.sort_by! { |_k, v| v }.reverse_each do |k, v|
|
133
135
|
body << "#{k} : #{v}\n"
|
134
136
|
end
|
135
137
|
|
@@ -137,20 +139,19 @@ ObjectSpace delta caused by request:
|
|
137
139
|
ObjectSpace stats:
|
138
140
|
-----------------\n"
|
139
141
|
|
140
|
-
stat_after[:stats].to_a.sort_by!{ |_k, v| v }.reverse_each do |k,v|
|
142
|
+
stat_after[:stats].to_a.sort_by! { |_k, v| v }.reverse_each do |k, v|
|
141
143
|
body << "#{k} : #{v}\n"
|
142
144
|
end
|
143
145
|
|
144
|
-
|
145
146
|
body << "\n
|
146
147
|
String stats:
|
147
148
|
------------\n"
|
148
149
|
|
149
|
-
string_analysis.to_a.sort_by!{ |_k, v| -v }.take(1000).each do |string,count|
|
150
|
+
string_analysis.to_a.sort_by! { |_k, v| -v }.take(1000).each do |string, count|
|
150
151
|
body << "#{count} : #{string}\n"
|
151
152
|
end
|
152
153
|
|
153
|
-
|
154
|
+
[200, { 'Content-Type' => 'text/plain' }, body]
|
154
155
|
ensure
|
155
156
|
prev_gc_state ? GC.disable : GC.enable
|
156
157
|
end
|