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.
Files changed (74) hide show
  1. data/.gitignore +4 -0
  2. data/History.txt +0 -0
  3. data/MIT-LICENSE.txt +19 -0
  4. data/README.rdoc +30 -0
  5. data/Rakefile +40 -0
  6. data/VERSION.yml +4 -0
  7. data/lib/rack/bug.rb +24 -0
  8. data/lib/rack/bug/options.rb +90 -0
  9. data/lib/rack/bug/panel.rb +50 -0
  10. data/lib/rack/bug/panel_app.rb +35 -0
  11. data/lib/rack/bug/panels/active_record_panel.rb +46 -0
  12. data/lib/rack/bug/panels/active_record_panel/activerecord_extensions.rb +18 -0
  13. data/lib/rack/bug/panels/cache_panel.rb +51 -0
  14. data/lib/rack/bug/panels/cache_panel/memcache_extension.rb +129 -0
  15. data/lib/rack/bug/panels/cache_panel/panel_app.rb +50 -0
  16. data/lib/rack/bug/panels/cache_panel/stats.rb +97 -0
  17. data/lib/rack/bug/panels/env_panel.rb +25 -0
  18. data/lib/rack/bug/panels/log_panel.rb +39 -0
  19. data/lib/rack/bug/panels/log_panel/rails_extension.rb +11 -0
  20. data/lib/rack/bug/panels/memory_panel.rb +27 -0
  21. data/lib/rack/bug/panels/rails_info_panel.rb +23 -0
  22. data/lib/rack/bug/panels/request_variables_panel.rb +25 -0
  23. data/lib/rack/bug/panels/sql_panel.rb +55 -0
  24. data/lib/rack/bug/panels/sql_panel/panel_app.rb +39 -0
  25. data/lib/rack/bug/panels/sql_panel/query.rb +73 -0
  26. data/lib/rack/bug/panels/sql_panel/sql_extension.rb +11 -0
  27. data/lib/rack/bug/panels/templates_panel.rb +44 -0
  28. data/lib/rack/bug/panels/templates_panel/actionview_extension.rb +12 -0
  29. data/lib/rack/bug/panels/templates_panel/rendering.rb +67 -0
  30. data/lib/rack/bug/panels/templates_panel/trace.rb +34 -0
  31. data/lib/rack/bug/panels/timer_panel.rb +41 -0
  32. data/lib/rack/bug/params_signature.rb +65 -0
  33. data/lib/rack/bug/public/__rack_bug__/bookmarklet.html +10 -0
  34. data/lib/rack/bug/public/__rack_bug__/bookmarklet.js +215 -0
  35. data/lib/rack/bug/public/__rack_bug__/bug.css +186 -0
  36. data/lib/rack/bug/public/__rack_bug__/bug.js +69 -0
  37. data/lib/rack/bug/public/__rack_bug__/jquery-1.3.2.js +4376 -0
  38. data/lib/rack/bug/public/__rack_bug__/spinner.gif +0 -0
  39. data/lib/rack/bug/render.rb +67 -0
  40. data/lib/rack/bug/toolbar.rb +145 -0
  41. data/lib/rack/bug/views/error.html.erb +16 -0
  42. data/lib/rack/bug/views/panels/active_record.html.erb +17 -0
  43. data/lib/rack/bug/views/panels/cache.html.erb +93 -0
  44. data/lib/rack/bug/views/panels/env.html.erb +19 -0
  45. data/lib/rack/bug/views/panels/execute_sql.html.erb +32 -0
  46. data/lib/rack/bug/views/panels/explain_sql.html.erb +32 -0
  47. data/lib/rack/bug/views/panels/log.html.erb +23 -0
  48. data/lib/rack/bug/views/panels/profile_sql.html.erb +32 -0
  49. data/lib/rack/bug/views/panels/rails_info.html.erb +19 -0
  50. data/lib/rack/bug/views/panels/request_variables.html.erb +87 -0
  51. data/lib/rack/bug/views/panels/sql.html.erb +43 -0
  52. data/lib/rack/bug/views/panels/templates.html.erb +7 -0
  53. data/lib/rack/bug/views/panels/timer.html.erb +19 -0
  54. data/lib/rack/bug/views/panels/view_cache.html.erb +19 -0
  55. data/lib/rack/bug/views/redirect.html.erb +16 -0
  56. data/lib/rack/bug/views/toolbar.html.erb +41 -0
  57. data/rack-bug.gemspec +121 -0
  58. data/spec/fixtures/config.ru +8 -0
  59. data/spec/fixtures/dummy_panel.rb +2 -0
  60. data/spec/fixtures/sample_app.rb +29 -0
  61. data/spec/rack/bug/panels/active_record_panel_spec.rb +30 -0
  62. data/spec/rack/bug/panels/cache_panel_spec.rb +159 -0
  63. data/spec/rack/bug/panels/env_panel_spec.rb +24 -0
  64. data/spec/rack/bug/panels/log_panel_spec.rb +25 -0
  65. data/spec/rack/bug/panels/memory_panel_spec.rb +21 -0
  66. data/spec/rack/bug/panels/rails_info_panel_spec.rb +25 -0
  67. data/spec/rack/bug/panels/sql_panel_spec.rb +136 -0
  68. data/spec/rack/bug/panels/templates_panel_spec.rb +71 -0
  69. data/spec/rack/bug/panels/timer_panel_spec.rb +38 -0
  70. data/spec/rack/toolbar_spec.rb +100 -0
  71. data/spec/rcov.opts +1 -0
  72. data/spec/spec.opts +1 -0
  73. data/spec/spec_helper.rb +70 -0
  74. 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,11 @@
1
+ if defined?(Rails) && Rails.logger
2
+ module LoggingExtensions
3
+ def add(*args, &block)
4
+ logged_message = super
5
+ Rack::Bug::LogPanel.record(logged_message)
6
+ return logged_message
7
+ end
8
+ end
9
+
10
+ Rails.logger.extend LoggingExtensions
11
+ 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 &#916;, #{@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