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
@@ -1,34 +1,34 @@
|
|
1
1
|
module Rack
|
2
2
|
module Bug
|
3
3
|
class TemplatesPanel
|
4
|
-
|
4
|
+
|
5
5
|
class Trace
|
6
|
-
|
6
|
+
|
7
7
|
def start(template_name)
|
8
8
|
rendering = Rendering.new(template_name)
|
9
9
|
rendering.start_time = Time.now
|
10
10
|
@current.add(rendering)
|
11
11
|
@current = rendering
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def finished(template_name)
|
15
15
|
@current.end_time = Time.now
|
16
16
|
@current = @current.parent
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def initialize
|
20
20
|
@current = root
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def total_time
|
24
24
|
root.child_time
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
def root
|
28
28
|
@root ||= Rendering.new("root")
|
29
29
|
end
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
end
|
33
33
|
end
|
34
|
-
end
|
34
|
+
end
|
@@ -2,39 +2,39 @@ require "benchmark"
|
|
2
2
|
|
3
3
|
module Rack
|
4
4
|
module Bug
|
5
|
-
|
5
|
+
|
6
6
|
class TimerPanel < Panel
|
7
|
-
|
7
|
+
|
8
8
|
def name
|
9
9
|
"timer"
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def call(env)
|
13
13
|
status, headers, body = nil
|
14
14
|
@times = Benchmark.measure do
|
15
15
|
status, headers, body = @app.call(env)
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
@measurements = [
|
19
19
|
["User CPU time", "%.2fms" % (@times.utime * 1_000)],
|
20
20
|
["System CPU time", "%.2fms" % (@times.stime * 1_000)],
|
21
21
|
["Total CPU time", "%.2fms" % (@times.total * 1_000)],
|
22
22
|
["Elapsed time", "%.2fms" % (@times.real * 1_000)]
|
23
23
|
]
|
24
|
-
|
24
|
+
|
25
25
|
env["rack-bug.panels"] << self
|
26
26
|
return [status, headers, body]
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def heading
|
30
30
|
"%.2fms" % (@times.real * 1_000)
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
def content
|
34
34
|
render_template "panels/timer", :measurements => @measurements
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
end
|
40
|
-
end
|
40
|
+
end
|
@@ -2,64 +2,64 @@ require "digest"
|
|
2
2
|
|
3
3
|
module Rack
|
4
4
|
module Bug
|
5
|
-
|
5
|
+
|
6
6
|
class ParamsSignature
|
7
7
|
extend ERB::Util
|
8
|
-
|
8
|
+
|
9
9
|
def self.sign(request, hash)
|
10
10
|
parts = []
|
11
|
-
|
11
|
+
|
12
12
|
hash.keys.sort.each do |key|
|
13
13
|
parts << "#{key}=#{u(hash[key])}"
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
signature = new(request).signature(hash)
|
17
17
|
parts << "hash=#{u(signature)}"
|
18
|
-
|
18
|
+
|
19
19
|
parts.join("&")
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
attr_reader :request
|
23
|
-
|
23
|
+
|
24
24
|
def initialize(request)
|
25
25
|
@request = request
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
def secret_key
|
29
29
|
@request.env['rack-bug.secret_key']
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
def secret_key_blank?
|
33
33
|
secret_key.nil? || secret_key == ""
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
def validate!
|
37
37
|
if secret_key_blank?
|
38
38
|
raise SecurityError.new("Missing secret key")
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
if secret_key_blank? || request.params["hash"] != signature(request.params)
|
42
42
|
raise SecurityError.new("Invalid query hash.")
|
43
43
|
end
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
def signature(params)
|
47
47
|
Digest::SHA1.hexdigest(signature_base(params))
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
def signature_base(params)
|
51
51
|
signature = []
|
52
52
|
signature << secret_key
|
53
|
-
|
53
|
+
|
54
54
|
params.keys.sort.each do |key|
|
55
55
|
next if key == "hash"
|
56
56
|
signature << params[key].to_s
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
signature.join(":")
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
end
|
65
|
-
end
|
65
|
+
end
|
@@ -203,12 +203,14 @@ document.rackBugBookmarklet = function() {
|
|
203
203
|
if (document.readCookie('rack_bug_password')) {
|
204
204
|
document.eraseCookie('rack_bug_password');
|
205
205
|
document.eraseCookie('rack_bug_enabled');
|
206
|
-
|
206
|
+
window.location.reload();
|
207
207
|
} else {
|
208
|
-
var password = prompt("Rack::Bug password:", "")
|
209
|
-
|
210
|
-
|
211
|
-
|
208
|
+
var password = prompt("Rack::Bug password:", "");
|
209
|
+
if (password != null) {
|
210
|
+
document.createCookie('rack_bug_password', document.SHA1('rack_bug:'+password));
|
211
|
+
document.createCookie('rack_bug_enabled', "1");
|
212
|
+
window.location.reload();
|
213
|
+
}
|
212
214
|
}
|
213
215
|
}
|
214
216
|
|
data/lib/rack/bug/render.rb
CHANGED
@@ -2,50 +2,50 @@ require "erb"
|
|
2
2
|
|
3
3
|
module Rack
|
4
4
|
module Bug
|
5
|
-
|
5
|
+
|
6
6
|
module Render
|
7
7
|
include ERB::Util
|
8
|
-
|
8
|
+
|
9
9
|
def signed_params(hash)
|
10
10
|
ParamsSignature.sign(request, hash)
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
module CompiledTemplates
|
14
14
|
end
|
15
15
|
include CompiledTemplates
|
16
|
-
|
16
|
+
|
17
17
|
def render_template(filename, local_assigns = {})
|
18
18
|
compile(filename, local_assigns)
|
19
19
|
render_symbol = method_name(filename, local_assigns)
|
20
20
|
send(render_symbol, local_assigns)
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def compile(filename, local_assigns)
|
24
24
|
render_symbol = method_name(filename, local_assigns)
|
25
|
-
|
25
|
+
|
26
26
|
if !CompiledTemplates.instance_methods.include?(render_symbol.to_s)
|
27
27
|
compile!(filename, local_assigns)
|
28
28
|
end
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
def compile!(filename, local_assigns)
|
32
|
-
render_symbol = method_name(filename, local_assigns)
|
32
|
+
render_symbol = method_name(filename, local_assigns)
|
33
33
|
locals_code = local_assigns.keys.map { |key| "#{key} = local_assigns[:#{key}];" }.join
|
34
|
-
|
34
|
+
|
35
35
|
source = <<-end_src
|
36
36
|
def #{render_symbol}(local_assigns)
|
37
37
|
#{locals_code}
|
38
38
|
#{compiled_source(filename)}
|
39
39
|
end
|
40
40
|
end_src
|
41
|
-
|
41
|
+
|
42
42
|
CompiledTemplates.module_eval(source, filename, 0)
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
def compiled_source(filename)
|
46
46
|
::ERB.new(::File.read(::File.dirname(__FILE__) + "/../bug/views/#{filename}.html.erb"), nil, "-").src
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
def method_name(filename, local_assigns)
|
50
50
|
if local_assigns && local_assigns.any?
|
51
51
|
method_name = method_name_without_locals(filename).dup
|
@@ -55,12 +55,12 @@ module Rack
|
|
55
55
|
end
|
56
56
|
method_name.to_sym
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
def method_name_without_locals(filename)
|
60
60
|
filename.split("/").join("_")
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
end
|
66
|
-
end
|
66
|
+
end
|
data/lib/rack/bug/toolbar.rb
CHANGED
@@ -8,7 +8,7 @@ module Rack
|
|
8
8
|
@app = app
|
9
9
|
@static_app = static_app
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def call(env)
|
13
13
|
if env["PATH_INFO"]
|
14
14
|
@static_app.call(env)
|
@@ -17,27 +17,27 @@ module Rack
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
class Toolbar
|
22
22
|
include Options
|
23
23
|
include Render
|
24
|
-
|
24
|
+
|
25
25
|
MIME_TYPES = ["text/html", "application/xhtml+xml"]
|
26
|
-
|
26
|
+
|
27
27
|
def initialize(app, options = {})
|
28
28
|
@app = asset_server(app)
|
29
29
|
initialize_options options
|
30
30
|
instance_eval(&block) if block_given?
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
def asset_server(app)
|
34
34
|
RackStaticBugAvoider.new(app, Rack::Static.new(app, :urls => ["/__rack_bug__"], :root => public_path))
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
def public_path
|
38
38
|
::File.expand_path(::File.dirname(__FILE__) + "/../bug/public")
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
def call(env)
|
42
42
|
env.replace @default_options.merge(env)
|
43
43
|
@env = env
|
@@ -49,29 +49,30 @@ module Rack
|
|
49
49
|
pass
|
50
50
|
end
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
def pass
|
54
54
|
@app.call(@env)
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
def dispatch
|
58
58
|
@env["rack-bug.panels"] = []
|
59
|
-
|
59
|
+
|
60
60
|
Rack::Bug.enable
|
61
61
|
status, headers, body = builder.call(@env)
|
62
62
|
Rack::Bug.disable
|
63
|
-
|
63
|
+
|
64
64
|
@response = Rack::Response.new(body, status, headers)
|
65
|
-
|
65
|
+
|
66
66
|
if @response.redirect? && options["rack-bug.intercept_redirects"]
|
67
67
|
intercept_redirect
|
68
|
-
|
68
|
+
end
|
69
|
+
if modify?
|
69
70
|
inject_toolbar
|
70
71
|
end
|
71
|
-
|
72
|
+
|
72
73
|
return @response.to_a
|
73
74
|
end
|
74
|
-
|
75
|
+
|
75
76
|
def intercept_redirect
|
76
77
|
redirect_to = @response.location
|
77
78
|
new_body = render_template("redirect", :redirect_to => @response.location)
|
@@ -79,59 +80,64 @@ module Rack
|
|
79
80
|
new_response["Content-Length"] = new_body.size.to_s
|
80
81
|
@response = new_response
|
81
82
|
end
|
82
|
-
|
83
|
+
|
83
84
|
def toolbar_requested?
|
84
85
|
@original_request.cookies["rack_bug_enabled"]
|
85
86
|
end
|
86
|
-
|
87
|
+
|
87
88
|
def ip_authorized?
|
88
89
|
return true unless options["rack-bug.ip_masks"]
|
89
|
-
|
90
|
+
|
90
91
|
options["rack-bug.ip_masks"].any? do |ip_mask|
|
91
92
|
ip_mask.include?(IPAddr.new(@original_request.ip))
|
92
93
|
end
|
93
94
|
end
|
94
|
-
|
95
|
+
|
95
96
|
def password_authorized?
|
96
97
|
return true unless options["rack-bug.password"]
|
97
|
-
|
98
|
+
|
98
99
|
expected_sha = Digest::SHA1.hexdigest ["rack_bug", options["rack-bug.password"]].join(":")
|
99
100
|
actual_sha = @original_request.cookies["rack_bug_password"]
|
100
|
-
|
101
|
+
|
101
102
|
actual_sha == expected_sha
|
102
103
|
end
|
103
|
-
|
104
|
+
|
104
105
|
def modify?
|
105
106
|
@response.ok? &&
|
106
|
-
@env["
|
107
|
+
@env["HTTP_X_REQUESTED_WITH"] != "XMLHttpRequest" &&
|
107
108
|
MIME_TYPES.include?(@response.content_type.split(";").first)
|
108
109
|
end
|
109
|
-
|
110
|
+
|
110
111
|
def builder
|
111
112
|
builder = Rack::Builder.new
|
112
|
-
|
113
|
+
|
113
114
|
options["rack-bug.panel_classes"].each do |panel_class|
|
114
115
|
builder.use panel_class
|
115
116
|
end
|
116
|
-
|
117
|
+
|
117
118
|
builder.run @app
|
118
|
-
|
119
|
+
|
119
120
|
return builder
|
120
121
|
end
|
121
|
-
|
122
|
+
|
122
123
|
def inject_toolbar
|
123
124
|
full_body = @response.body.join
|
124
125
|
full_body.sub! /<\/body>/, render + "</body>"
|
125
|
-
|
126
|
+
|
126
127
|
@response["Content-Length"] = full_body.size.to_s
|
128
|
+
|
129
|
+
# Ensure that browser does
|
130
|
+
@response["Etag"] = ""
|
131
|
+
@response["Cache-Control"] = "no-cache"
|
132
|
+
|
127
133
|
@response.body = [full_body]
|
128
134
|
end
|
129
|
-
|
135
|
+
|
130
136
|
def render
|
131
137
|
render_template("toolbar", :panels => @env["rack-bug.panels"].reverse)
|
132
138
|
end
|
133
|
-
|
139
|
+
|
134
140
|
end
|
135
|
-
|
141
|
+
|
136
142
|
end
|
137
|
-
end
|
143
|
+
end
|
@@ -5,17 +5,15 @@
|
|
5
5
|
<th>Level</th>
|
6
6
|
<th>Time</th>
|
7
7
|
<th>Message</th>
|
8
|
-
<th>Location</th>
|
9
8
|
</tr>
|
10
9
|
</thead>
|
11
10
|
<tbody>
|
12
11
|
<% i = 1 %>
|
13
|
-
<% logs.each do |
|
12
|
+
<% logs.each do |entry| %>
|
14
13
|
<tr class="<%= i % 2 == 0 ? "even" : "odd" %>">
|
15
|
-
<td
|
16
|
-
<td
|
17
|
-
<td><%=
|
18
|
-
<td></td>
|
14
|
+
<td><%= entry.level %></td>
|
15
|
+
<td><%= entry.time %>ms</td>
|
16
|
+
<td><%= entry.cleaned_message %></td>
|
19
17
|
</tr>
|
20
18
|
<% i += 1 %>
|
21
19
|
<% end %>
|