perfectline-rack-bug 0.1.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.
- data/.gitignore +4 -0
- data/History.txt +0 -0
- data/MIT-LICENSE.txt +19 -0
- data/README.rdoc +30 -0
- data/Rakefile +40 -0
- data/VERSION.yml +4 -0
- data/lib/rack/bug.rb +24 -0
- data/lib/rack/bug/options.rb +90 -0
- data/lib/rack/bug/panel.rb +50 -0
- data/lib/rack/bug/panel_app.rb +35 -0
- data/lib/rack/bug/panels/active_record_panel.rb +46 -0
- data/lib/rack/bug/panels/active_record_panel/activerecord_extensions.rb +18 -0
- data/lib/rack/bug/panels/cache_panel.rb +51 -0
- data/lib/rack/bug/panels/cache_panel/memcache_extension.rb +129 -0
- data/lib/rack/bug/panels/cache_panel/panel_app.rb +50 -0
- data/lib/rack/bug/panels/cache_panel/stats.rb +97 -0
- data/lib/rack/bug/panels/env_panel.rb +25 -0
- data/lib/rack/bug/panels/log_panel.rb +39 -0
- data/lib/rack/bug/panels/log_panel/rails_extension.rb +11 -0
- data/lib/rack/bug/panels/memory_panel.rb +27 -0
- data/lib/rack/bug/panels/rails_info_panel.rb +23 -0
- data/lib/rack/bug/panels/request_variables_panel.rb +25 -0
- data/lib/rack/bug/panels/sql_panel.rb +55 -0
- data/lib/rack/bug/panels/sql_panel/panel_app.rb +39 -0
- data/lib/rack/bug/panels/sql_panel/query.rb +73 -0
- data/lib/rack/bug/panels/sql_panel/sql_extension.rb +11 -0
- data/lib/rack/bug/panels/templates_panel.rb +44 -0
- data/lib/rack/bug/panels/templates_panel/actionview_extension.rb +12 -0
- data/lib/rack/bug/panels/templates_panel/rendering.rb +67 -0
- data/lib/rack/bug/panels/templates_panel/trace.rb +34 -0
- data/lib/rack/bug/panels/timer_panel.rb +41 -0
- data/lib/rack/bug/params_signature.rb +65 -0
- data/lib/rack/bug/public/__rack_bug__/bookmarklet.html +10 -0
- data/lib/rack/bug/public/__rack_bug__/bookmarklet.js +215 -0
- data/lib/rack/bug/public/__rack_bug__/bug.css +186 -0
- data/lib/rack/bug/public/__rack_bug__/bug.js +69 -0
- data/lib/rack/bug/public/__rack_bug__/jquery-1.3.2.js +4376 -0
- data/lib/rack/bug/public/__rack_bug__/spinner.gif +0 -0
- data/lib/rack/bug/render.rb +67 -0
- data/lib/rack/bug/toolbar.rb +145 -0
- data/lib/rack/bug/views/error.html.erb +16 -0
- data/lib/rack/bug/views/panels/active_record.html.erb +17 -0
- data/lib/rack/bug/views/panels/cache.html.erb +93 -0
- data/lib/rack/bug/views/panels/env.html.erb +19 -0
- data/lib/rack/bug/views/panels/execute_sql.html.erb +32 -0
- data/lib/rack/bug/views/panels/explain_sql.html.erb +32 -0
- data/lib/rack/bug/views/panels/log.html.erb +23 -0
- data/lib/rack/bug/views/panels/profile_sql.html.erb +32 -0
- data/lib/rack/bug/views/panels/rails_info.html.erb +19 -0
- data/lib/rack/bug/views/panels/request_variables.html.erb +87 -0
- data/lib/rack/bug/views/panels/sql.html.erb +43 -0
- data/lib/rack/bug/views/panels/templates.html.erb +7 -0
- data/lib/rack/bug/views/panels/timer.html.erb +19 -0
- data/lib/rack/bug/views/panels/view_cache.html.erb +19 -0
- data/lib/rack/bug/views/redirect.html.erb +16 -0
- data/lib/rack/bug/views/toolbar.html.erb +41 -0
- data/rack-bug.gemspec +121 -0
- data/spec/fixtures/config.ru +8 -0
- data/spec/fixtures/dummy_panel.rb +2 -0
- data/spec/fixtures/sample_app.rb +29 -0
- data/spec/rack/bug/panels/active_record_panel_spec.rb +30 -0
- data/spec/rack/bug/panels/cache_panel_spec.rb +159 -0
- data/spec/rack/bug/panels/env_panel_spec.rb +24 -0
- data/spec/rack/bug/panels/log_panel_spec.rb +25 -0
- data/spec/rack/bug/panels/memory_panel_spec.rb +21 -0
- data/spec/rack/bug/panels/rails_info_panel_spec.rb +25 -0
- data/spec/rack/bug/panels/sql_panel_spec.rb +136 -0
- data/spec/rack/bug/panels/templates_panel_spec.rb +71 -0
- data/spec/rack/bug/panels/timer_panel_spec.rb +38 -0
- data/spec/rack/toolbar_spec.rb +100 -0
- data/spec/rcov.opts +1 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +70 -0
- metadata +138 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require "rack/bug/panel_app"
|
|
2
|
+
|
|
3
|
+
module Rack
|
|
4
|
+
module Bug
|
|
5
|
+
class CachePanel
|
|
6
|
+
|
|
7
|
+
class PanelApp < ::Rack::Bug::PanelApp
|
|
8
|
+
|
|
9
|
+
def dispatch
|
|
10
|
+
case request.path_info
|
|
11
|
+
when "/__rack_bug__/view_cache" then view_cache
|
|
12
|
+
when "/__rack_bug__/delete_cache" then delete_cache
|
|
13
|
+
when "/__rack_bug__/delete_cache_list" then delete_cache_list
|
|
14
|
+
else not_found
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def ok
|
|
19
|
+
Rack::Response.new(["OK"]).to_a
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def view_cache
|
|
23
|
+
validate_params
|
|
24
|
+
render_template "panels/view_cache", :key => params["key"], :value => Rails.cache.read(params["key"])
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def delete_cache
|
|
28
|
+
validate_params
|
|
29
|
+
raise "Rails not found... can't delete key" unless defined?(Rails)
|
|
30
|
+
Rails.cache.delete(params["key"])
|
|
31
|
+
ok
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def delete_cache_list
|
|
35
|
+
validate_params
|
|
36
|
+
raise "Rails not found... can't delete key" unless defined?(Rails)
|
|
37
|
+
|
|
38
|
+
params.each do |key, value|
|
|
39
|
+
next unless key =~ /^keys_/
|
|
40
|
+
Rails.cache.delete(value)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
ok
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
module Rack
|
|
2
|
+
module Bug
|
|
3
|
+
class CachePanel
|
|
4
|
+
|
|
5
|
+
class Stats
|
|
6
|
+
class Query
|
|
7
|
+
attr_reader :method, :time, :hit, :keys
|
|
8
|
+
|
|
9
|
+
def initialize(method, time, hit, keys)
|
|
10
|
+
@method = method
|
|
11
|
+
@time = time
|
|
12
|
+
@hit = hit
|
|
13
|
+
@keys = keys
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def display_time
|
|
17
|
+
"%.2fms" % time
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def display_keys
|
|
21
|
+
if keys.size == 1
|
|
22
|
+
keys.first
|
|
23
|
+
else
|
|
24
|
+
keys.join(", ")
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
attr_reader :calls
|
|
30
|
+
attr_reader :keys
|
|
31
|
+
attr_reader :queries
|
|
32
|
+
|
|
33
|
+
def initialize
|
|
34
|
+
@queries = []
|
|
35
|
+
@misses =
|
|
36
|
+
@calls = 0
|
|
37
|
+
@time = 0.0
|
|
38
|
+
@keys = []
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def record_call(method, time, hit, *keys)
|
|
42
|
+
@queries << Query.new(method, time, hit, keys)
|
|
43
|
+
@calls += 1
|
|
44
|
+
@time += time
|
|
45
|
+
@keys += keys
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def display_time
|
|
49
|
+
"%.2fms" % time
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def time
|
|
53
|
+
@queries.inject(0) do |memo, query|
|
|
54
|
+
memo + query.time
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def gets
|
|
59
|
+
count_queries(:get)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def sets
|
|
63
|
+
count_queries(:set)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def deletes
|
|
67
|
+
count_queries(:delete)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def get_multis
|
|
71
|
+
count_queries(:get_multi)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def hits
|
|
75
|
+
@queries.select { |q| [:get, :get_multi].include?(q.method) && q.hit }.size
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def misses
|
|
79
|
+
@queries.select { |q| [:get, :get_multi].include?(q.method) && !q.hit }.size
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def count_queries(method)
|
|
83
|
+
@queries.select { |q| q.method == method }.size
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def queries_to_param
|
|
87
|
+
params = {}
|
|
88
|
+
@queries.each_with_index do |query, index|
|
|
89
|
+
params["keys_#{index}"] = query.keys.first
|
|
90
|
+
end
|
|
91
|
+
params
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Rack
|
|
2
|
+
module Bug
|
|
3
|
+
|
|
4
|
+
class EnvPanel < Panel
|
|
5
|
+
|
|
6
|
+
def name
|
|
7
|
+
"env"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def before(env)
|
|
11
|
+
@env = env
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def heading
|
|
15
|
+
"Rack Env"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def content
|
|
19
|
+
render_template "panels/env", :env => @env
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require "rack/bug/panels/log_panel/rails_extension"
|
|
2
|
+
|
|
3
|
+
module Rack
|
|
4
|
+
module Bug
|
|
5
|
+
|
|
6
|
+
class LogPanel < Panel
|
|
7
|
+
|
|
8
|
+
def self.record(message)
|
|
9
|
+
return unless Rack::Bug.enabled?
|
|
10
|
+
return unless message
|
|
11
|
+
logs << message.to_s
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.reset
|
|
15
|
+
Thread.current["rack.bug.logs"] = []
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.logs
|
|
19
|
+
Thread.current["rack.bug.logs"] ||= []
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def name
|
|
23
|
+
"log"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def heading
|
|
27
|
+
"Log"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def content
|
|
31
|
+
result = render_template "panels/log", :logs => self.class.logs
|
|
32
|
+
self.class.reset
|
|
33
|
+
return result
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#
|
|
2
|
+
module Rack
|
|
3
|
+
module Bug
|
|
4
|
+
|
|
5
|
+
class MemoryPanel < Panel
|
|
6
|
+
|
|
7
|
+
def before(env)
|
|
8
|
+
@original_memory = `ps -o rss= -p #{$$}`.to_i
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def after(env, status, headers, body)
|
|
12
|
+
@total_memory = `ps -o rss= -p #{$$}`.to_i
|
|
13
|
+
@memory_increase = @total_memory - @original_memory
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def heading
|
|
17
|
+
"#{@memory_increase} KB Δ, #{@total_memory} KB total"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def has_content?
|
|
21
|
+
false
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Rack
|
|
2
|
+
module Bug
|
|
3
|
+
|
|
4
|
+
class RailsInfoPanel < Panel
|
|
5
|
+
|
|
6
|
+
def name
|
|
7
|
+
"rails_info"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def heading
|
|
11
|
+
return unless defined?(Rails)
|
|
12
|
+
"Rails #{Rails.version}"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def content
|
|
16
|
+
return unless defined?(Rails)
|
|
17
|
+
render_template "panels/rails_info"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Rack
|
|
2
|
+
module Bug
|
|
3
|
+
|
|
4
|
+
class RequestVariablesPanel < Panel
|
|
5
|
+
|
|
6
|
+
def name
|
|
7
|
+
"request_variables"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def before(env)
|
|
11
|
+
@env = env
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def heading
|
|
15
|
+
"Request Vars"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def content
|
|
19
|
+
render_template "panels/request_variables", :request => @request
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require "digest"
|
|
2
|
+
|
|
3
|
+
module Rack
|
|
4
|
+
module Bug
|
|
5
|
+
|
|
6
|
+
class SQLPanel < Panel
|
|
7
|
+
|
|
8
|
+
require "rack/bug/panels/sql_panel/sql_extension"
|
|
9
|
+
require "rack/bug/panels/sql_panel/query"
|
|
10
|
+
require "rack/bug/panels/sql_panel/panel_app"
|
|
11
|
+
|
|
12
|
+
def panel_app
|
|
13
|
+
PanelApp.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.record(sql, backtrace = [], &block)
|
|
17
|
+
return block.call unless Rack::Bug.enabled?
|
|
18
|
+
|
|
19
|
+
start_time = Time.now
|
|
20
|
+
result = block.call
|
|
21
|
+
queries << Query.new(sql, Time.now - start_time, backtrace)
|
|
22
|
+
|
|
23
|
+
return result
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.reset
|
|
27
|
+
Thread.current["rack.test.queries"] = []
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.queries
|
|
31
|
+
Thread.current["rack.test.queries"] ||= []
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.total_time
|
|
35
|
+
(queries.inject(0) { |memo, query| memo + query.time}) * 1_000
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def name
|
|
39
|
+
"sql"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def heading
|
|
43
|
+
"#{self.class.queries.size} Queries (%.2fms)" % self.class.total_time
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def content
|
|
47
|
+
result = render_template "panels/sql", :queries => self.class.queries
|
|
48
|
+
self.class.reset
|
|
49
|
+
return result
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require "rack/bug/panel_app"
|
|
2
|
+
|
|
3
|
+
module Rack
|
|
4
|
+
module Bug
|
|
5
|
+
class SQLPanel
|
|
6
|
+
|
|
7
|
+
class PanelApp < ::Rack::Bug::PanelApp
|
|
8
|
+
|
|
9
|
+
def dispatch
|
|
10
|
+
case request.path_info
|
|
11
|
+
when "/__rack_bug__/explain_sql" then explain_sql
|
|
12
|
+
when "/__rack_bug__/profile_sql" then profile_sql
|
|
13
|
+
when "/__rack_bug__/execute_sql" then execute_sql
|
|
14
|
+
else not_found
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def explain_sql
|
|
19
|
+
validate_params
|
|
20
|
+
query = Query.new(params["query"], params["time"].to_f)
|
|
21
|
+
render_template "panels/explain_sql", :result => query.explain, :query => query.sql, :time => query.time
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def profile_sql
|
|
25
|
+
validate_params
|
|
26
|
+
query = Query.new(params["query"], params["time"].to_f)
|
|
27
|
+
render_template "panels/profile_sql", :result => query.profile, :query => query.sql, :time => query.time
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def execute_sql
|
|
31
|
+
validate_params
|
|
32
|
+
query = Query.new(params["query"], params["time"].to_f)
|
|
33
|
+
render_template "panels/execute_sql", :result => query.execute, :query => query.sql, :time => query.time
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
module Rack
|
|
2
|
+
module Bug
|
|
3
|
+
class SQLPanel
|
|
4
|
+
|
|
5
|
+
class Query
|
|
6
|
+
attr_reader :sql
|
|
7
|
+
attr_reader :time
|
|
8
|
+
attr_reader :backtrace
|
|
9
|
+
|
|
10
|
+
def initialize(sql, time, backtrace = [])
|
|
11
|
+
@sql = sql
|
|
12
|
+
@time = time
|
|
13
|
+
@backtrace = backtrace
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def human_time
|
|
17
|
+
"%.2fms" % (@time * 1_000)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def inspectable?
|
|
21
|
+
sql.strip =~ /^SELECT /i
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def with_profiling
|
|
25
|
+
self.class.execute("SET PROFILING=1")
|
|
26
|
+
result = yield
|
|
27
|
+
self.class.execute("SET PROFILING=0")
|
|
28
|
+
return result
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def explain
|
|
32
|
+
self.class.execute "EXPLAIN #{@sql}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def profile
|
|
36
|
+
with_profiling do
|
|
37
|
+
execute
|
|
38
|
+
self.class.execute <<-SQL
|
|
39
|
+
SELECT *
|
|
40
|
+
FROM information_schema.profiling
|
|
41
|
+
WHERE query_id = (SELECT query_id FROM information_schema.profiling ORDER BY query_id DESC LIMIT 1)
|
|
42
|
+
SQL
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def execute
|
|
47
|
+
self.class.execute(@sql)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def valid_hash?(secret_key, possible_hash)
|
|
51
|
+
hash = Digest::SHA1.hexdigest [secret_key, @sql].join(":")
|
|
52
|
+
possible_hash == hash
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.execute(sql)
|
|
56
|
+
ActiveRecord::Base.connection.execute(sql)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def has_backtrace?
|
|
60
|
+
filtered_backtrace.any?
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def filtered_backtrace
|
|
64
|
+
@filtered_backtrace ||= @backtrace.map { |l| l.to_s.strip }.select do |line|
|
|
65
|
+
line.starts_with?(Rails.root) &&
|
|
66
|
+
!line.starts_with?(Rails.root.join("vendor"))
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|