rack-bug 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +21 -0
- data/README.md +115 -0
- data/Rakefile +6 -19
- data/Thorfile +109 -0
- data/lib/rack/bug.rb +4 -2
- data/lib/rack/bug/filtered_backtrace.rb +38 -0
- data/lib/rack/bug/options.rb +4 -4
- data/lib/rack/bug/panel.rb +12 -12
- data/lib/rack/bug/panel_app.rb +8 -8
- data/lib/rack/bug/panels/active_record_panel.rb +11 -11
- data/lib/rack/bug/panels/active_record_panel/activerecord_extensions.rb +3 -3
- data/lib/rack/bug/panels/cache_panel.rb +1 -1
- data/lib/rack/bug/panels/cache_panel/memcache_extension.rb +4 -4
- data/lib/rack/bug/panels/cache_panel/panel_app.rb +11 -11
- data/lib/rack/bug/panels/cache_panel/stats.rb +20 -20
- data/lib/rack/bug/panels/log_panel.rb +27 -10
- data/lib/rack/bug/panels/log_panel/rails_extension.rb +2 -2
- data/lib/rack/bug/panels/memory_panel.rb +8 -8
- data/lib/rack/bug/panels/rails_info_panel.rb +5 -5
- data/lib/rack/bug/panels/redis_panel.rb +3 -3
- data/lib/rack/bug/panels/redis_panel/redis_extension.rb +3 -3
- data/lib/rack/bug/panels/redis_panel/stats.rb +17 -13
- data/lib/rack/bug/panels/request_variables_panel.rb +7 -7
- data/lib/rack/bug/panels/sphinx_panel.rb +44 -0
- data/lib/rack/bug/panels/sphinx_panel/sphinx_extension.rb +13 -0
- data/lib/rack/bug/panels/sphinx_panel/stats.rb +96 -0
- data/lib/rack/bug/panels/sql_panel.rb +1 -1
- data/lib/rack/bug/panels/sql_panel/panel_app.rb +7 -7
- data/lib/rack/bug/panels/sql_panel/query.rb +13 -23
- data/lib/rack/bug/panels/sql_panel/sql_extension.rb +2 -2
- data/lib/rack/bug/panels/templates_panel.rb +1 -1
- data/lib/rack/bug/panels/templates_panel/actionview_extension.rb +1 -1
- data/lib/rack/bug/panels/templates_panel/rendering.rb +14 -14
- data/lib/rack/bug/panels/templates_panel/trace.rb +8 -8
- data/lib/rack/bug/panels/timer_panel.rb +10 -10
- data/lib/rack/bug/params_signature.rb +18 -18
- data/lib/rack/bug/public/__rack_bug__/bookmarklet.js +7 -5
- data/lib/rack/bug/render.rb +16 -16
- data/lib/rack/bug/toolbar.rb +39 -33
- data/lib/rack/bug/views/panels/log.html.erb +4 -6
- data/lib/rack/bug/views/panels/redis.html.erb +14 -0
- data/lib/rack/bug/views/panels/sphinx.html.erb +32 -0
- data/rack-bug.gemspec +102 -97
- data/spec/fixtures/config.ru +3 -1
- data/spec/fixtures/sample_app.rb +7 -6
- data/spec/rack/bug/panels/active_record_panel_spec.rb +6 -6
- data/spec/rack/bug/panels/cache_panel_spec.rb +46 -46
- data/spec/rack/bug/panels/log_panel_spec.rb +8 -7
- data/spec/rack/bug/panels/memory_panel_spec.rb +6 -6
- data/spec/rack/bug/panels/rails_info_panel_spec.rb +5 -5
- data/spec/rack/bug/panels/redis_panel_spec.rb +31 -19
- data/spec/rack/bug/panels/sql_panel_spec.rb +45 -45
- data/spec/rack/bug/panels/templates_panel_spec.rb +18 -18
- data/spec/rack/bug/panels/timer_panel_spec.rb +12 -12
- data/spec/rack/toolbar_spec.rb +34 -28
- data/spec/spec_helper.rb +19 -9
- metadata +44 -13
- data/README.rdoc +0 -29
- data/VERSION +0 -1
@@ -4,11 +4,11 @@ if defined?(Redis)
|
|
4
4
|
Redis.class_eval do
|
5
5
|
|
6
6
|
def call_command_with_rack_bug(argv)
|
7
|
-
Rack::Bug::RedisPanel.record(argv) do
|
7
|
+
Rack::Bug::RedisPanel.record(argv, Kernel.caller) do
|
8
8
|
call_command_without_rack_bug(argv)
|
9
9
|
end
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
alias_method_chain :call_command, :rack_bug
|
13
13
|
end
|
14
|
-
end
|
14
|
+
end
|
@@ -1,48 +1,52 @@
|
|
1
1
|
module Rack
|
2
2
|
module Bug
|
3
3
|
class RedisPanel
|
4
|
-
|
4
|
+
|
5
5
|
class Stats
|
6
6
|
class Query
|
7
|
+
include Rack::Bug::FilteredBacktrace
|
8
|
+
|
7
9
|
attr_reader :time
|
8
10
|
attr_reader :command
|
9
|
-
|
10
|
-
def initialize(time,
|
11
|
+
|
12
|
+
def initialize(time, command_args, backtrace)
|
11
13
|
@time = time
|
12
14
|
@command = command_args.inspect
|
15
|
+
@backtrace = backtrace
|
13
16
|
end
|
14
|
-
|
17
|
+
|
15
18
|
def display_time
|
16
19
|
"%.2fms" % time
|
17
20
|
end
|
18
21
|
end
|
19
|
-
|
22
|
+
|
20
23
|
attr_reader :calls
|
21
24
|
attr_reader :queries
|
22
|
-
|
25
|
+
|
23
26
|
def initialize
|
24
27
|
@queries = []
|
25
28
|
@calls = 0
|
26
29
|
@time = 0.0
|
27
30
|
end
|
28
|
-
|
29
|
-
def record_call(time,
|
30
|
-
@queries << Query.new(time, command_args)
|
31
|
+
|
32
|
+
def record_call(time, command_args, backtrace)
|
33
|
+
@queries << Query.new(time, command_args, backtrace)
|
31
34
|
@calls += 1
|
32
35
|
@time += time
|
33
36
|
end
|
34
|
-
|
37
|
+
|
35
38
|
def display_time
|
36
39
|
"%.2fms" % time
|
37
40
|
end
|
38
|
-
|
41
|
+
|
39
42
|
def time
|
40
43
|
@queries.inject(0) do |memo, query|
|
41
44
|
memo + query.time
|
42
45
|
end
|
43
46
|
end
|
47
|
+
|
44
48
|
end
|
45
|
-
|
49
|
+
|
46
50
|
end
|
47
51
|
end
|
48
|
-
end
|
52
|
+
end
|
@@ -1,25 +1,25 @@
|
|
1
1
|
module Rack
|
2
2
|
module Bug
|
3
|
-
|
3
|
+
|
4
4
|
class RequestVariablesPanel < Panel
|
5
|
-
|
5
|
+
|
6
6
|
def name
|
7
7
|
"request_variables"
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
def before(env)
|
11
11
|
@env = env
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def heading
|
15
15
|
"Rack Env"
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def content
|
19
19
|
render_template "panels/request_variables", :request => @request, :env => @env
|
20
20
|
end
|
21
21
|
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
end
|
25
|
-
end
|
25
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Rack
|
2
|
+
module 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
|
@@ -0,0 +1,13 @@
|
|
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
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Rack
|
2
|
+
module 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 Riddle 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
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Rack
|
2
2
|
module Bug
|
3
3
|
class SQLPanel
|
4
|
-
|
4
|
+
|
5
5
|
class PanelApp < ::Rack::Bug::PanelApp
|
6
|
-
|
6
|
+
|
7
7
|
def dispatch
|
8
8
|
case request.path_info
|
9
9
|
when "/__rack_bug__/explain_sql" then explain_sql
|
@@ -12,26 +12,26 @@ module Rack
|
|
12
12
|
else not_found
|
13
13
|
end
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
def explain_sql
|
17
17
|
validate_params
|
18
18
|
query = Query.new(params["query"], params["time"].to_f)
|
19
19
|
render_template "panels/explain_sql", :result => query.explain, :query => query.sql, :time => query.time
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def profile_sql
|
23
23
|
validate_params
|
24
24
|
query = Query.new(params["query"], params["time"].to_f)
|
25
25
|
render_template "panels/profile_sql", :result => query.profile, :query => query.sql, :time => query.time
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
def execute_sql
|
29
29
|
validate_params
|
30
30
|
query = Query.new(params["query"], params["time"].to_f)
|
31
31
|
render_template "panels/execute_sql", :result => query.execute, :query => query.sql, :time => query.time
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
|
-
end
|
37
|
+
end
|
@@ -1,18 +1,19 @@
|
|
1
1
|
module Rack
|
2
2
|
module Bug
|
3
3
|
class SQLPanel
|
4
|
-
|
4
|
+
|
5
5
|
class Query
|
6
|
+
include Rack::Bug::FilteredBacktrace
|
7
|
+
|
6
8
|
attr_reader :sql
|
7
9
|
attr_reader :time
|
8
|
-
|
9
|
-
|
10
|
+
|
10
11
|
def initialize(sql, time, backtrace = [])
|
11
12
|
@sql = sql
|
12
13
|
@time = time
|
13
14
|
@backtrace = backtrace
|
14
15
|
end
|
15
|
-
|
16
|
+
|
16
17
|
def human_time
|
17
18
|
"%.2fms" % (@time * 1_000)
|
18
19
|
end
|
@@ -20,18 +21,18 @@ module Rack
|
|
20
21
|
def inspectable?
|
21
22
|
sql.strip =~ /^SELECT /i
|
22
23
|
end
|
23
|
-
|
24
|
+
|
24
25
|
def with_profiling
|
25
26
|
self.class.execute("SET PROFILING=1")
|
26
27
|
result = yield
|
27
28
|
self.class.execute("SET PROFILING=0")
|
28
29
|
return result
|
29
30
|
end
|
30
|
-
|
31
|
+
|
31
32
|
def explain
|
32
33
|
self.class.execute "EXPLAIN #{@sql}"
|
33
34
|
end
|
34
|
-
|
35
|
+
|
35
36
|
def profile
|
36
37
|
with_profiling do
|
37
38
|
execute
|
@@ -42,32 +43,21 @@ module Rack
|
|
42
43
|
SQL
|
43
44
|
end
|
44
45
|
end
|
45
|
-
|
46
|
+
|
46
47
|
def execute
|
47
48
|
self.class.execute(@sql)
|
48
49
|
end
|
49
|
-
|
50
|
+
|
50
51
|
def valid_hash?(secret_key, possible_hash)
|
51
52
|
hash = Digest::SHA1.hexdigest [secret_key, @sql].join(":")
|
52
53
|
possible_hash == hash
|
53
54
|
end
|
54
|
-
|
55
|
+
|
55
56
|
def self.execute(sql)
|
56
57
|
ActiveRecord::Base.connection.execute(sql)
|
57
58
|
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
59
|
end
|
70
|
-
|
60
|
+
|
71
61
|
end
|
72
62
|
end
|
73
|
-
end
|
63
|
+
end
|
@@ -1,37 +1,37 @@
|
|
1
1
|
module Rack
|
2
2
|
module Bug
|
3
3
|
class TemplatesPanel
|
4
|
-
|
4
|
+
|
5
5
|
class Rendering
|
6
6
|
attr_accessor :name
|
7
7
|
attr_accessor :start_time
|
8
8
|
attr_accessor :end_time
|
9
9
|
attr_accessor :parent
|
10
10
|
attr_reader :children
|
11
|
-
|
12
|
-
|
11
|
+
|
12
|
+
|
13
13
|
def initialize(name)
|
14
14
|
@name = name
|
15
15
|
@children = []
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def add(rendering)
|
19
19
|
@children << rendering
|
20
20
|
rendering.parent = self
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def time
|
24
24
|
@end_time - @start_time
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
def exclusive_time
|
28
28
|
time - child_time
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
def child_time
|
32
32
|
children.inject(0.0) { |memo, c| memo + c.time }
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
def time_summary
|
36
36
|
if children.any?
|
37
37
|
"%.2fms, %.2f exclusive" % [time * 1_000, exclusive_time * 1_000]
|
@@ -43,25 +43,25 @@ module Rack
|
|
43
43
|
<<-HTML
|
44
44
|
<li>
|
45
45
|
<p>#{name} (#{time_summary})</p>
|
46
|
-
|
46
|
+
|
47
47
|
#{children_html}
|
48
48
|
</li>
|
49
49
|
HTML
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
def children_html
|
53
53
|
return "" unless children.any?
|
54
|
-
|
54
|
+
|
55
55
|
<<-HTML
|
56
56
|
<ul>#{joined_children_html}</ul>
|
57
57
|
HTML
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
def joined_children_html
|
61
61
|
children.map { |c| c.html }.join
|
62
62
|
end
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
end
|
66
66
|
end
|
67
|
-
end
|
67
|
+
end
|