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,25 @@
|
|
1
|
+
require 'riddle'
|
2
|
+
|
3
|
+
if defined?(Riddle)
|
4
|
+
Riddle::Client.class_eval do
|
5
|
+
def request_with_rack_bug(command, messages)
|
6
|
+
Rack::Bug::SphinxPanel.record(command, messages) do
|
7
|
+
request_without_rack_bug(command, messages)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
alias_method_chain :request, :rack_bug
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
if defined?(Sphinx::Client)
|
16
|
+
Sphinx::Client.class_eval do
|
17
|
+
def PerformRequest_with_rack_bug(command, request, additional = nil)
|
18
|
+
Rack::Bug::SphinxPanel.record(command, request) do
|
19
|
+
PerformRequest_without_rack_bug(command, request, additional)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
alias_method_chain :PerformRequest, :rack_bug
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Rack
|
2
|
+
class Bug
|
3
|
+
class SphinxPanel
|
4
|
+
|
5
|
+
class Stats
|
6
|
+
class Query
|
7
|
+
attr_reader :time
|
8
|
+
attr_reader :command
|
9
|
+
|
10
|
+
def initialize(time, *command_args)
|
11
|
+
@time = time
|
12
|
+
if command_args.flatten.first == :search
|
13
|
+
@command = "search: " + decode_message(command_args.first.flatten.last).collect{|k,v| "#{k} => #{v}"}.join(", ")
|
14
|
+
else
|
15
|
+
@command = command_args.flatten.first.to_s + ": No more info is available for this Sphinx request type"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def display_time
|
20
|
+
"%.2fms" % time
|
21
|
+
end
|
22
|
+
|
23
|
+
def decode_message(m)
|
24
|
+
@m = m.clone
|
25
|
+
params = ActiveSupport::OrderedHash.new
|
26
|
+
|
27
|
+
params[:offset] = consume_int
|
28
|
+
params[:limit] = consume_int
|
29
|
+
params[:match_mode] = consume_int
|
30
|
+
params[:rank_mode] = consume_int
|
31
|
+
params[:sort_mode] = consume_int
|
32
|
+
params[:sort_by] = consume_string
|
33
|
+
params[:query] = consume_string
|
34
|
+
wl = consume_int
|
35
|
+
weights = []
|
36
|
+
wl.times do weights << consume_int end
|
37
|
+
params[:weights] = weights
|
38
|
+
|
39
|
+
params[:index] = consume_string
|
40
|
+
|
41
|
+
consume_string
|
42
|
+
|
43
|
+
params[:id_range] = [consume_64int, consume_64int]
|
44
|
+
params
|
45
|
+
end
|
46
|
+
|
47
|
+
def consume_int
|
48
|
+
i = @m.unpack("N").first
|
49
|
+
@m = @m.slice(4, @m.length - 4)
|
50
|
+
i
|
51
|
+
end
|
52
|
+
|
53
|
+
def consume_64int
|
54
|
+
i = @m.unpack("NN").first
|
55
|
+
@m = @m.slice(8, @m.length - 8)
|
56
|
+
i
|
57
|
+
end
|
58
|
+
|
59
|
+
def consume_string
|
60
|
+
len = consume_int
|
61
|
+
s = @m.slice(0, len)
|
62
|
+
@m = @m.slice(len, @m.length - len)
|
63
|
+
s
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
attr_reader :calls
|
68
|
+
attr_reader :queries
|
69
|
+
|
70
|
+
def initialize
|
71
|
+
@queries = []
|
72
|
+
@calls = 0
|
73
|
+
@time = 0.0
|
74
|
+
end
|
75
|
+
|
76
|
+
def record_call(time, *command_args)
|
77
|
+
|
78
|
+
@queries << Query.new(time, command_args)
|
79
|
+
@calls += 1
|
80
|
+
@time += time
|
81
|
+
end
|
82
|
+
|
83
|
+
def display_time
|
84
|
+
"%.2fms" % time
|
85
|
+
end
|
86
|
+
|
87
|
+
def time
|
88
|
+
@queries.inject(0) do |memo, query|
|
89
|
+
memo + query.time
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "digest"
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
class Bug
|
5
|
+
|
6
|
+
class SQLPanel < Panel
|
7
|
+
require "rack/bug/panels/sql_panel/sql_extension"
|
8
|
+
|
9
|
+
autoload :PanelApp, "rack/bug/panels/sql_panel/panel_app"
|
10
|
+
autoload :Query, "rack/bug/panels/sql_panel/query"
|
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,37 @@
|
|
1
|
+
module Rack
|
2
|
+
class Bug
|
3
|
+
class SQLPanel
|
4
|
+
|
5
|
+
class PanelApp < ::Rack::Bug::PanelApp
|
6
|
+
|
7
|
+
def dispatch
|
8
|
+
case request.path_info
|
9
|
+
when "/__rack_bug__/explain_sql" then explain_sql
|
10
|
+
when "/__rack_bug__/profile_sql" then profile_sql
|
11
|
+
when "/__rack_bug__/execute_sql" then execute_sql
|
12
|
+
else not_found
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def explain_sql
|
17
|
+
validate_params
|
18
|
+
query = Query.new(params["query"], params["time"].to_f)
|
19
|
+
render_template "panels/explain_sql", :result => query.explain, :query => query.sql, :time => query.time
|
20
|
+
end
|
21
|
+
|
22
|
+
def profile_sql
|
23
|
+
validate_params
|
24
|
+
query = Query.new(params["query"], params["time"].to_f)
|
25
|
+
render_template "panels/profile_sql", :result => query.profile, :query => query.sql, :time => query.time
|
26
|
+
end
|
27
|
+
|
28
|
+
def execute_sql
|
29
|
+
validate_params
|
30
|
+
query = Query.new(params["query"], params["time"].to_f)
|
31
|
+
render_template "panels/execute_sql", :result => query.execute, :query => query.sql, :time => query.time
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Rack
|
2
|
+
class Bug
|
3
|
+
class SQLPanel
|
4
|
+
|
5
|
+
class Query
|
6
|
+
include Rack::Bug::FilteredBacktrace
|
7
|
+
|
8
|
+
attr_reader :sql
|
9
|
+
attr_reader :time
|
10
|
+
|
11
|
+
def initialize(sql, time, backtrace = [])
|
12
|
+
@sql = sql
|
13
|
+
@time = time
|
14
|
+
@backtrace = backtrace
|
15
|
+
end
|
16
|
+
|
17
|
+
def human_time
|
18
|
+
"%.2fms" % (@time * 1_000)
|
19
|
+
end
|
20
|
+
|
21
|
+
def inspectable?
|
22
|
+
sql.strip =~ /^SELECT /i
|
23
|
+
end
|
24
|
+
|
25
|
+
def with_profiling
|
26
|
+
self.class.execute("SET PROFILING=1")
|
27
|
+
result = yield
|
28
|
+
self.class.execute("SET PROFILING=0")
|
29
|
+
return result
|
30
|
+
end
|
31
|
+
|
32
|
+
def explain
|
33
|
+
self.class.execute "EXPLAIN #{@sql}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def profile
|
37
|
+
with_profiling do
|
38
|
+
execute
|
39
|
+
self.class.execute <<-SQL
|
40
|
+
SELECT *
|
41
|
+
FROM information_schema.profiling
|
42
|
+
WHERE query_id = (SELECT query_id FROM information_schema.profiling ORDER BY query_id DESC LIMIT 1)
|
43
|
+
SQL
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def execute
|
48
|
+
self.class.execute(@sql)
|
49
|
+
end
|
50
|
+
|
51
|
+
def valid_hash?(secret_key, possible_hash)
|
52
|
+
hash = Digest::SHA1.hexdigest [secret_key, @sql].join(":")
|
53
|
+
possible_hash == hash
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.execute(sql)
|
57
|
+
ActiveRecord::Base.connection.execute(sql)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
if defined?(ActiveRecord) && defined?(ActiveRecord::ConnectionAdapters)
|
2
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
|
3
|
+
def log_with_rack_bug(sql, name, &block)
|
4
|
+
Rack::Bug::SQLPanel.record(sql, Kernel.caller) do
|
5
|
+
log_without_rack_bug(sql, name, &block)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
alias_method_chain :log, :rack_bug
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Rack
|
2
|
+
class Bug
|
3
|
+
|
4
|
+
class TemplatesPanel < Panel
|
5
|
+
require "rack/bug/panels/templates_panel/actionview_extension"
|
6
|
+
|
7
|
+
autoload :Trace, "rack/bug/panels/templates_panel/trace"
|
8
|
+
autoload :Rendering, "rack/bug/panels/templates_panel/rendering"
|
9
|
+
|
10
|
+
def self.record(template, &block)
|
11
|
+
return block.call unless Rack::Bug.enabled?
|
12
|
+
|
13
|
+
template_trace.start(template)
|
14
|
+
result = block.call
|
15
|
+
template_trace.finished(template)
|
16
|
+
return result
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.reset
|
20
|
+
Thread.current["rack.bug.template_trace"] = Trace.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.template_trace
|
24
|
+
Thread.current["rack.bug.template_trace"] ||= Trace.new
|
25
|
+
end
|
26
|
+
|
27
|
+
def name
|
28
|
+
"templates"
|
29
|
+
end
|
30
|
+
|
31
|
+
def heading
|
32
|
+
"Templates: %.2fms" % (self.class.template_trace.total_time * 1_000)
|
33
|
+
end
|
34
|
+
|
35
|
+
def content
|
36
|
+
result = render_template "panels/templates", :template_trace => self.class.template_trace
|
37
|
+
self.class.reset
|
38
|
+
return result
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
if defined?(ActionView) && defined?(ActionView::Template)
|
2
|
+
ActionView::Template.class_eval do
|
3
|
+
|
4
|
+
def render_template_with_rack_bug(*args, &block)
|
5
|
+
Rack::Bug::TemplatesPanel.record(path_without_format_and_extension) do
|
6
|
+
render_template_without_rack_bug(*args, &block)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
alias_method_chain :render_template, :rack_bug
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Rack
|
2
|
+
class Bug
|
3
|
+
class TemplatesPanel
|
4
|
+
|
5
|
+
class Rendering
|
6
|
+
attr_accessor :name
|
7
|
+
attr_accessor :start_time
|
8
|
+
attr_accessor :end_time
|
9
|
+
attr_accessor :parent
|
10
|
+
attr_reader :children
|
11
|
+
|
12
|
+
|
13
|
+
def initialize(name)
|
14
|
+
@name = name
|
15
|
+
@children = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def add(rendering)
|
19
|
+
@children << rendering
|
20
|
+
rendering.parent = self
|
21
|
+
end
|
22
|
+
|
23
|
+
def time
|
24
|
+
@end_time - @start_time
|
25
|
+
end
|
26
|
+
|
27
|
+
def exclusive_time
|
28
|
+
time - child_time
|
29
|
+
end
|
30
|
+
|
31
|
+
def child_time
|
32
|
+
children.inject(0.0) { |memo, c| memo + c.time }
|
33
|
+
end
|
34
|
+
|
35
|
+
def time_summary
|
36
|
+
if children.any?
|
37
|
+
"%.2fms, %.2f exclusive" % [time * 1_000, exclusive_time * 1_000]
|
38
|
+
else
|
39
|
+
"%.2fms" % (time * 1_000)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
def html
|
43
|
+
<<-HTML
|
44
|
+
<li>
|
45
|
+
<p>#{name} (#{time_summary})</p>
|
46
|
+
|
47
|
+
#{children_html}
|
48
|
+
</li>
|
49
|
+
HTML
|
50
|
+
end
|
51
|
+
|
52
|
+
def children_html
|
53
|
+
return "" unless children.any?
|
54
|
+
|
55
|
+
<<-HTML
|
56
|
+
<ul>#{joined_children_html}</ul>
|
57
|
+
HTML
|
58
|
+
end
|
59
|
+
|
60
|
+
def joined_children_html
|
61
|
+
children.map { |c| c.html }.join
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Rack
|
2
|
+
class Bug
|
3
|
+
class TemplatesPanel
|
4
|
+
|
5
|
+
class Trace
|
6
|
+
|
7
|
+
def start(template_name)
|
8
|
+
rendering = Rendering.new(template_name)
|
9
|
+
rendering.start_time = Time.now
|
10
|
+
@current.add(rendering)
|
11
|
+
@current = rendering
|
12
|
+
end
|
13
|
+
|
14
|
+
def finished(template_name)
|
15
|
+
@current.end_time = Time.now
|
16
|
+
@current = @current.parent
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@current = root
|
21
|
+
end
|
22
|
+
|
23
|
+
def total_time
|
24
|
+
root.child_time
|
25
|
+
end
|
26
|
+
|
27
|
+
def root
|
28
|
+
@root ||= Rendering.new("root")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|