ghazel-rack-bug 0.3.0.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 +3 -0
- data/History.txt +45 -0
- data/MIT-LICENSE.txt +19 -0
- data/README.md +118 -0
- data/Rakefile +23 -0
- data/Thorfile +113 -0
- data/lib/rack/bug.rb +83 -0
- data/lib/rack/bug/autoloading.rb +24 -0
- data/lib/rack/bug/filtered_backtrace.rb +38 -0
- data/lib/rack/bug/options.rb +89 -0
- data/lib/rack/bug/panel.rb +50 -0
- data/lib/rack/bug/panel_app.rb +33 -0
- data/lib/rack/bug/panels/active_record_panel.rb +45 -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/dalli_extension.rb +16 -0
- data/lib/rack/bug/panels/cache_panel/memcache_extension.rb +129 -0
- data/lib/rack/bug/panels/cache_panel/panel_app.rb +48 -0
- data/lib/rack/bug/panels/cache_panel/stats.rb +97 -0
- data/lib/rack/bug/panels/log_panel.rb +56 -0
- data/lib/rack/bug/panels/log_panel/logger_extension.rb +24 -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/redis_panel.rb +44 -0
- data/lib/rack/bug/panels/redis_panel/redis_extension.rb +28 -0
- data/lib/rack/bug/panels/redis_panel/stats.rb +52 -0
- data/lib/rack/bug/panels/request_variables_panel.rb +52 -0
- data/lib/rack/bug/panels/sphinx_panel.rb +44 -0
- data/lib/rack/bug/panels/sphinx_panel/sphinx_extension.rb +25 -0
- data/lib/rack/bug/panels/sphinx_panel/stats.rb +96 -0
- data/lib/rack/bug/panels/sql_panel.rb +55 -0
- data/lib/rack/bug/panels/sql_panel/panel_app.rb +37 -0
- data/lib/rack/bug/panels/sql_panel/query.rb +63 -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 +40 -0
- data/lib/rack/bug/params_signature.rb +63 -0
- data/lib/rack/bug/public/__rack_bug__/bookmarklet.html +10 -0
- data/lib/rack/bug/public/__rack_bug__/bookmarklet.js +217 -0
- data/lib/rack/bug/public/__rack_bug__/bug.css +216 -0
- data/lib/rack/bug/public/__rack_bug__/bug.js +84 -0
- data/lib/rack/bug/public/__rack_bug__/jquery-1.3.2.js +4376 -0
- data/lib/rack/bug/public/__rack_bug__/jquery.tablesorter.min.js +1 -0
- data/lib/rack/bug/public/__rack_bug__/spinner.gif +0 -0
- data/lib/rack/bug/rack_static_bug_avoider.rb +16 -0
- data/lib/rack/bug/redirect_interceptor.rb +27 -0
- data/lib/rack/bug/render.rb +66 -0
- data/lib/rack/bug/toolbar.rb +66 -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/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 +21 -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/redis.html.erb +46 -0
- data/lib/rack/bug/views/panels/request_variables.html.erb +29 -0
- data/lib/rack/bug/views/panels/sphinx.html.erb +32 -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 +42 -0
- data/rack-bug.gemspec +147 -0
- data/spec/fixtures/config.ru +8 -0
- data/spec/fixtures/dummy_panel.rb +2 -0
- data/spec/fixtures/sample_app.rb +46 -0
- data/spec/rack/bug/panels/active_record_panel_spec.rb +30 -0
- data/spec/rack/bug/panels/cache_panel_spec.rb +167 -0
- data/spec/rack/bug/panels/log_panel_spec.rb +43 -0
- data/spec/rack/bug/panels/memory_panel_spec.rb +22 -0
- data/spec/rack/bug/panels/rails_info_panel_spec.rb +40 -0
- data/spec/rack/bug/panels/redis_panel_spec.rb +69 -0
- data/spec/rack/bug/panels/sql_panel_spec.rb +146 -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/bug_spec.rb +137 -0
- data/spec/rcov.opts +1 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +44 -0
- metadata +201 -0
@@ -0,0 +1,97 @@
|
|
1
|
+
module Rack
|
2
|
+
class 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,56 @@
|
|
1
|
+
require "rack/bug/panels/log_panel/logger_extension"
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
class Bug
|
5
|
+
|
6
|
+
class LogPanel < Panel
|
7
|
+
class LogEntry
|
8
|
+
attr_reader :level, :time, :message
|
9
|
+
LEVELS = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL']
|
10
|
+
|
11
|
+
def initialize(level, time, message)
|
12
|
+
@level = LEVELS[level]
|
13
|
+
@time = time
|
14
|
+
@message = message
|
15
|
+
end
|
16
|
+
|
17
|
+
def cleaned_message
|
18
|
+
@message.to_s.gsub(/\e\[[;\d]+m/, "")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.record(message, log_level)
|
23
|
+
return unless Rack::Bug.enabled?
|
24
|
+
return unless message
|
25
|
+
Thread.current["rack.bug.logs.start"] ||= Time.now
|
26
|
+
timestamp = ((Time.now - Thread.current["rack.bug.logs.start"]) * 1000).to_i
|
27
|
+
logs << LogEntry.new(log_level, timestamp, message)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.reset
|
31
|
+
Thread.current["rack.bug.logs"] = []
|
32
|
+
Thread.current["rack.bug.logs.start"] = nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.logs
|
36
|
+
Thread.current["rack.bug.logs"] ||= []
|
37
|
+
end
|
38
|
+
|
39
|
+
def name
|
40
|
+
"log"
|
41
|
+
end
|
42
|
+
|
43
|
+
def heading
|
44
|
+
"Log"
|
45
|
+
end
|
46
|
+
|
47
|
+
def content
|
48
|
+
result = render_template "panels/log", :logs => self.class.logs
|
49
|
+
self.class.reset
|
50
|
+
return result
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Rack::Bug::LoggerExtension
|
2
|
+
def self.included(target)
|
3
|
+
target.send :alias_method, :add_without_rack_bug, :add
|
4
|
+
target.send :alias_method, :add, :add_with_rack_bug
|
5
|
+
end
|
6
|
+
|
7
|
+
def add_with_rack_bug(*args, &block)
|
8
|
+
logger_return = add_without_rack_bug(*args, &block)
|
9
|
+
logged_message = logger_return
|
10
|
+
logged_message = args[1] || args[2] unless logged_message.is_a?(String)
|
11
|
+
Rack::Bug::LogPanel.record(logged_message, args[0])
|
12
|
+
return logger_return
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
if defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
|
17
|
+
logger = Rails.logger
|
18
|
+
elsif defined?(LOGGER)
|
19
|
+
logger = LOGGER
|
20
|
+
end
|
21
|
+
|
22
|
+
if logger
|
23
|
+
logger.class.send :include, Rack::Bug::LoggerExtension
|
24
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#
|
2
|
+
module Rack
|
3
|
+
class 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
|
+
class Bug
|
3
|
+
|
4
|
+
class RailsInfoPanel < Panel
|
5
|
+
|
6
|
+
def name
|
7
|
+
"rails_info"
|
8
|
+
end
|
9
|
+
|
10
|
+
def heading
|
11
|
+
return unless (defined?(Rails) && defined?(Rails::Info))
|
12
|
+
"Rails #{Rails.version}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def content
|
16
|
+
return unless (defined?(Rails) && defined?(Rails::Info))
|
17
|
+
render_template "panels/rails_info"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Rack
|
2
|
+
class Bug
|
3
|
+
|
4
|
+
class RedisPanel < Panel
|
5
|
+
require "rack/bug/panels/redis_panel/redis_extension"
|
6
|
+
|
7
|
+
autoload :Stats, "rack/bug/panels/redis_panel/stats"
|
8
|
+
|
9
|
+
def self.record(redis_command_args, backtrace, &block)
|
10
|
+
return block.call unless Rack::Bug.enabled?
|
11
|
+
|
12
|
+
start_time = Time.now
|
13
|
+
result = block.call
|
14
|
+
total_time = Time.now - start_time
|
15
|
+
stats.record_call(total_time * 1_000, redis_command_args, backtrace)
|
16
|
+
return result
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.reset
|
20
|
+
Thread.current["rack.bug.redis"] = Stats.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.stats
|
24
|
+
Thread.current["rack.bug.redis"] ||= Stats.new
|
25
|
+
end
|
26
|
+
|
27
|
+
def name
|
28
|
+
"redis"
|
29
|
+
end
|
30
|
+
|
31
|
+
def heading
|
32
|
+
"Redis: %.2fms (#{self.class.stats.queries.size} calls)" % self.class.stats.time
|
33
|
+
end
|
34
|
+
|
35
|
+
def content
|
36
|
+
result = render_template "panels/redis", :stats => self.class.stats
|
37
|
+
self.class.reset
|
38
|
+
return result
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'redis'
|
2
|
+
|
3
|
+
if defined?(Redis)
|
4
|
+
Redis.class_eval do
|
5
|
+
if Redis.methods.include?('call_command') # older versions of redis-rb
|
6
|
+
def call_command_with_rack_bug(*argv)
|
7
|
+
Rack::Bug::RedisPanel.record(argv, Kernel.caller) do
|
8
|
+
call_command_without_rack_bug(*argv)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
alias_method_chain :call_command, :rack_bug
|
13
|
+
|
14
|
+
elsif defined?(Redis::Client) # newer versions of redis-rb
|
15
|
+
|
16
|
+
Redis::Client.class_eval do
|
17
|
+
def call_with_rack_bug(*argv)
|
18
|
+
Rack::Bug::RedisPanel.record(argv, Kernel.caller) do
|
19
|
+
call_without_rack_bug(*argv)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
alias_method_chain :call, :rack_bug
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Rack
|
2
|
+
class Bug
|
3
|
+
class RedisPanel
|
4
|
+
|
5
|
+
class Stats
|
6
|
+
class Query
|
7
|
+
include Rack::Bug::FilteredBacktrace
|
8
|
+
|
9
|
+
attr_reader :time
|
10
|
+
attr_reader :command
|
11
|
+
|
12
|
+
def initialize(time, command_args, backtrace)
|
13
|
+
@time = time
|
14
|
+
@command = command_args.inspect
|
15
|
+
@backtrace = backtrace
|
16
|
+
end
|
17
|
+
|
18
|
+
def display_time
|
19
|
+
"%.2fms" % time
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :calls
|
24
|
+
attr_reader :queries
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
@queries = []
|
28
|
+
@calls = 0
|
29
|
+
@time = 0.0
|
30
|
+
end
|
31
|
+
|
32
|
+
def record_call(time, command_args, backtrace)
|
33
|
+
@queries << Query.new(time, command_args, backtrace)
|
34
|
+
@calls += 1
|
35
|
+
@time += time
|
36
|
+
end
|
37
|
+
|
38
|
+
def display_time
|
39
|
+
"%.2fms" % time
|
40
|
+
end
|
41
|
+
|
42
|
+
def time
|
43
|
+
@queries.inject(0) do |memo, query|
|
44
|
+
memo + query.time
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Rack
|
2
|
+
class 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
|
+
"Rack Env"
|
16
|
+
end
|
17
|
+
|
18
|
+
def content
|
19
|
+
sections = {}
|
20
|
+
sections["GET"] = sort(@request.GET) if @request.GET.any?
|
21
|
+
sections["POST"] = sort(@request.GET) if @request.POST.any?
|
22
|
+
sections["Session"] = sort(@request.env["rack.session"]) if @request.env["rack.session"] && @request.env["rack.session"].any?
|
23
|
+
sections["Cookies"] = sort(@request.env["rack.request.cookie_hash"]) if @request.env["rack.request.cookie_hash"] && @request.env["rack.request.cookie_hash"].any?
|
24
|
+
server, rack = split_and_filter_env(@env)
|
25
|
+
sections["SERVER VARIABLES"] = sort(server)
|
26
|
+
sections["Rack ENV"] = sort(rack)
|
27
|
+
render_template "panels/request_variables", :sections => sections
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def sort(hash)
|
32
|
+
hash.sort_by { |k, v| k.to_s }
|
33
|
+
end
|
34
|
+
|
35
|
+
def split_and_filter_env(env)
|
36
|
+
server, rack = {}, {}
|
37
|
+
env.each do |k,v|
|
38
|
+
if k.index("rack.") == 0
|
39
|
+
rack[k] = v
|
40
|
+
elsif k.index("rack-bug.") == 0
|
41
|
+
#don't output the rack-bug variables - especially secret_key
|
42
|
+
else
|
43
|
+
server[k] = v
|
44
|
+
end
|
45
|
+
end
|
46
|
+
return server, rack
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Rack
|
2
|
+
class Bug
|
3
|
+
|
4
|
+
class SphinxPanel < Panel
|
5
|
+
require "rack/bug/panels/sphinx_panel/sphinx_extension"
|
6
|
+
|
7
|
+
autoload :Stats, "rack/bug/panels/sphinx_panel/stats"
|
8
|
+
|
9
|
+
def self.record(*sphinx_command_args, &block)
|
10
|
+
return block.call unless Rack::Bug.enabled?
|
11
|
+
|
12
|
+
start_time = Time.now
|
13
|
+
result = block.call
|
14
|
+
total_time = Time.now - start_time
|
15
|
+
stats.record_call(total_time * 1_000, sphinx_command_args)
|
16
|
+
return result
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.reset
|
20
|
+
Thread.current["rack.bug.sphinx"] = Stats.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.stats
|
24
|
+
Thread.current["rack.bug.sphinx"] ||= Stats.new
|
25
|
+
end
|
26
|
+
|
27
|
+
def name
|
28
|
+
"sphinx"
|
29
|
+
end
|
30
|
+
|
31
|
+
def heading
|
32
|
+
"Sphinx: %.2fms (#{self.class.stats.queries.size} calls)" % self.class.stats.time
|
33
|
+
end
|
34
|
+
|
35
|
+
def content
|
36
|
+
result = render_template "panels/sphinx", :stats => self.class.stats
|
37
|
+
self.class.reset
|
38
|
+
return result
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|