rack-insight 0.5.0

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 (126) hide show
  1. data/.gitignore +13 -0
  2. data/.rspec +1 -0
  3. data/.simplecov +4 -0
  4. data/.travis.yml +8 -0
  5. data/CHANGELOG +58 -0
  6. data/Gemfile +3 -0
  7. data/Gemfile.lock +82 -0
  8. data/LICENSE +24 -0
  9. data/README.md +189 -0
  10. data/Rakefile +27 -0
  11. data/TODO +7 -0
  12. data/lib/rack-insight.rb +1 -0
  13. data/lib/rack/insight.rb +19 -0
  14. data/lib/rack/insight/app.rb +198 -0
  15. data/lib/rack/insight/config.rb +30 -0
  16. data/lib/rack/insight/database.rb +193 -0
  17. data/lib/rack/insight/enable-button.rb +43 -0
  18. data/lib/rack/insight/filtered_backtrace.rb +45 -0
  19. data/lib/rack/insight/instrumentation.rb +9 -0
  20. data/lib/rack/insight/instrumentation/backstage.rb +10 -0
  21. data/lib/rack/insight/instrumentation/client.rb +20 -0
  22. data/lib/rack/insight/instrumentation/instrument.rb +109 -0
  23. data/lib/rack/insight/instrumentation/package-definition.rb +58 -0
  24. data/lib/rack/insight/instrumentation/probe-definition.rb +20 -0
  25. data/lib/rack/insight/instrumentation/probe.rb +196 -0
  26. data/lib/rack/insight/instrumentation/setup.rb +32 -0
  27. data/lib/rack/insight/logger.rb +53 -0
  28. data/lib/rack/insight/options.rb +116 -0
  29. data/lib/rack/insight/panel.rb +135 -0
  30. data/lib/rack/insight/panel_app.rb +31 -0
  31. data/lib/rack/insight/panels-content.rb +22 -0
  32. data/lib/rack/insight/panels-header.rb +18 -0
  33. data/lib/rack/insight/panels/active_record_panel.rb +46 -0
  34. data/lib/rack/insight/panels/active_resource_panel.rb +48 -0
  35. data/lib/rack/insight/panels/active_resource_panel/query.rb +27 -0
  36. data/lib/rack/insight/panels/cache_panel.rb +68 -0
  37. data/lib/rack/insight/panels/cache_panel/panel_app.rb +46 -0
  38. data/lib/rack/insight/panels/cache_panel/stats.rb +90 -0
  39. data/lib/rack/insight/panels/log_panel.rb +53 -0
  40. data/lib/rack/insight/panels/memory_panel.rb +36 -0
  41. data/lib/rack/insight/panels/mongo_panel.rb +41 -0
  42. data/lib/rack/insight/panels/mongo_panel/mongo_extension.rb +24 -0
  43. data/lib/rack/insight/panels/mongo_panel/stats.rb +46 -0
  44. data/lib/rack/insight/panels/rails_info_panel.rb +19 -0
  45. data/lib/rack/insight/panels/redis_panel.rb +42 -0
  46. data/lib/rack/insight/panels/redis_panel/redis_extension.rb +23 -0
  47. data/lib/rack/insight/panels/redis_panel/stats.rb +50 -0
  48. data/lib/rack/insight/panels/request_variables_panel.rb +70 -0
  49. data/lib/rack/insight/panels/speedtracer_panel.rb +89 -0
  50. data/lib/rack/insight/panels/speedtracer_panel/profiling.rb +29 -0
  51. data/lib/rack/insight/panels/speedtracer_panel/trace-app.rb +52 -0
  52. data/lib/rack/insight/panels/speedtracer_panel/tracer.rb +213 -0
  53. data/lib/rack/insight/panels/sphinx_panel.rb +41 -0
  54. data/lib/rack/insight/panels/sphinx_panel/stats.rb +94 -0
  55. data/lib/rack/insight/panels/sql_panel.rb +53 -0
  56. data/lib/rack/insight/panels/sql_panel/panel_app.rb +37 -0
  57. data/lib/rack/insight/panels/sql_panel/query.rb +94 -0
  58. data/lib/rack/insight/panels/templates_panel.rb +58 -0
  59. data/lib/rack/insight/panels/templates_panel/rendering.rb +81 -0
  60. data/lib/rack/insight/panels/timer_panel.rb +40 -0
  61. data/lib/rack/insight/params_signature.rb +61 -0
  62. data/lib/rack/insight/path-filter.rb +23 -0
  63. data/lib/rack/insight/public/__insight__/bookmarklet.html +10 -0
  64. data/lib/rack/insight/public/__insight__/bookmarklet.js +223 -0
  65. data/lib/rack/insight/public/__insight__/insight.css +235 -0
  66. data/lib/rack/insight/public/__insight__/insight.js +127 -0
  67. data/lib/rack/insight/public/__insight__/jquery-1.3.2.js +4376 -0
  68. data/lib/rack/insight/public/__insight__/jquery.tablesorter.min.js +1 -0
  69. data/lib/rack/insight/public/__insight__/spinner.gif +0 -0
  70. data/lib/rack/insight/rack_static_bug_avoider.rb +16 -0
  71. data/lib/rack/insight/redirect_interceptor.rb +25 -0
  72. data/lib/rack/insight/render.rb +72 -0
  73. data/lib/rack/insight/request-recorder.rb +22 -0
  74. data/lib/rack/insight/rspec_matchers.rb +33 -0
  75. data/lib/rack/insight/toolbar.rb +69 -0
  76. data/lib/rack/insight/version.rb +7 -0
  77. data/lib/rack/insight/views/enable-button.html.erb +21 -0
  78. data/lib/rack/insight/views/error.html.erb +17 -0
  79. data/lib/rack/insight/views/headers_fragment.html.erb +20 -0
  80. data/lib/rack/insight/views/panels/active_record.html.erb +17 -0
  81. data/lib/rack/insight/views/panels/active_resource.html.erb +47 -0
  82. data/lib/rack/insight/views/panels/cache.html.erb +93 -0
  83. data/lib/rack/insight/views/panels/execute_sql.html.erb +32 -0
  84. data/lib/rack/insight/views/panels/explain_sql.html.erb +32 -0
  85. data/lib/rack/insight/views/panels/log.html.erb +21 -0
  86. data/lib/rack/insight/views/panels/mongo.html.erb +32 -0
  87. data/lib/rack/insight/views/panels/profile_sql.html.erb +32 -0
  88. data/lib/rack/insight/views/panels/rails_info.html.erb +19 -0
  89. data/lib/rack/insight/views/panels/redis.html.erb +46 -0
  90. data/lib/rack/insight/views/panels/request_variables.html.erb +25 -0
  91. data/lib/rack/insight/views/panels/speedtracer/serverevent.html.erb +10 -0
  92. data/lib/rack/insight/views/panels/speedtracer/servertrace.html.erb +12 -0
  93. data/lib/rack/insight/views/panels/speedtracer/traces.html.erb +18 -0
  94. data/lib/rack/insight/views/panels/sphinx.html.erb +32 -0
  95. data/lib/rack/insight/views/panels/sql.html.erb +43 -0
  96. data/lib/rack/insight/views/panels/templates.html.erb +6 -0
  97. data/lib/rack/insight/views/panels/timer.html.erb +19 -0
  98. data/lib/rack/insight/views/panels/view_cache.html.erb +19 -0
  99. data/lib/rack/insight/views/redirect.html.erb +16 -0
  100. data/lib/rack/insight/views/request_fragment.html.erb +25 -0
  101. data/lib/rack/insight/views/toolbar.html.erb +29 -0
  102. data/rack-insight.gemspec +40 -0
  103. data/spec/custom_matchers.rb +0 -0
  104. data/spec/fixtures/config.ru +8 -0
  105. data/spec/fixtures/dummy_panel.rb +2 -0
  106. data/spec/fixtures/sample_app.rb +72 -0
  107. data/spec/fixtures/star_trek_panel.rb +1 -0
  108. data/spec/insight_spec.rb +163 -0
  109. data/spec/instrumentation_spec.rb +188 -0
  110. data/spec/rack/insight/config_spec.rb +20 -0
  111. data/spec/rack/insight/panels/active_record_panel_spec.rb +43 -0
  112. data/spec/rack/insight/panels/active_resource_panel_spec.rb +40 -0
  113. data/spec/rack/insight/panels/cache_panel_spec.rb +178 -0
  114. data/spec/rack/insight/panels/log_panel_spec.rb +44 -0
  115. data/spec/rack/insight/panels/memory_panel_spec.rb +21 -0
  116. data/spec/rack/insight/panels/mongo_panel_spec_pending.rb +52 -0
  117. data/spec/rack/insight/panels/rails_info_panel_spec.rb +29 -0
  118. data/spec/rack/insight/panels/redis_panel_spec.rb +67 -0
  119. data/spec/rack/insight/panels/speedtracer_panel_spec.rb +86 -0
  120. data/spec/rack/insight/panels/sql_panel_spec.rb +146 -0
  121. data/spec/rack/insight/panels/templates_panel_spec.rb +86 -0
  122. data/spec/rack/insight/panels/timer_panel_spec.rb +38 -0
  123. data/spec/rcov.opts +1 -0
  124. data/spec/spec.opts +1 -0
  125. data/spec/spec_helper.rb +111 -0
  126. metadata +380 -0
@@ -0,0 +1,48 @@
1
+ require "digest"
2
+
3
+ module Rack::Insight
4
+ class ActiveResourcePanel < Panel
5
+ require 'rack/insight/panels/active_resource_panel/query'
6
+ #require "rack/insight/panels/sql_panel/panel_app"
7
+ #require "rack/insight/panels/sql_panel/query"
8
+
9
+ def initialize(app)
10
+ super
11
+ probe(self) do
12
+ instrument "ActiveResource::Connection" do
13
+ instance_probe :request
14
+ end
15
+ end
16
+ table_setup("active_resource_requests")
17
+ end
18
+
19
+ def after_detect(method_call, timing, arguments, results)
20
+ body = "<no body>"
21
+ if results.respond_to? :body
22
+ body = results.body
23
+ end
24
+ store(@env, RequestResult.new(arguments[0], arguments[1..-1], timing.duration, method_call.backtrace[0..5], body))
25
+ end
26
+
27
+ def total_time(queries)
28
+ (queries.inject(0) do |memo, query|
29
+ memo + query.time
30
+ end)
31
+ end
32
+
33
+ def name
34
+ "active_resource"
35
+ end
36
+
37
+ def heading_for_request(number)
38
+ queries = retrieve(number)
39
+ "ARes: #{queries.size} Queries (%.2fms)" % total_time(queries)
40
+ end
41
+
42
+ def content_for_request(number)
43
+ queries = retrieve(number)
44
+ logger.debug{ "ARes: #{queries.inspect}" }
45
+ render_template "panels/active_resource", :queries => queries
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,27 @@
1
+ module Rack::Insight
2
+ class ActiveResourcePanel
3
+ class RequestResult
4
+ include Rack::Insight::FilteredBacktrace
5
+
6
+ attr_reader :path, :args, :result, :time
7
+ alias results result
8
+
9
+ def initialize(path, args, time, backtrace = [], result=nil)
10
+ @path = path
11
+ @args = args
12
+ @time = time
13
+ @backtrace = backtrace
14
+ @result = result
15
+ end
16
+
17
+ def human_time
18
+ "%.2fms" % (@time)
19
+ end
20
+
21
+ def valid_hash?(secret_key, possible_hash)
22
+ hash = Digest::SHA1.hexdigest [secret_key, @sql].join(":")
23
+ possible_hash == hash
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,68 @@
1
+
2
+ module Rack::Insight
3
+
4
+ class CachePanel < Panel
5
+ require "rack/insight/panels/cache_panel/panel_app"
6
+ require "rack/insight/panels/cache_panel/stats"
7
+
8
+ def initialize(app)
9
+ super
10
+
11
+ probe(self) do
12
+ instrument("Memcached") do
13
+ instance_probe :decrement, :get, :increment, :set, :add,
14
+ :replace, :delete, :prepend, :append
15
+ end
16
+
17
+ instrument("MemCache") do
18
+ instance_probe :decr, :get, :get_multi, :incr, :set, :add, :delete
19
+ end
20
+
21
+ instrument("Dalli::Client") do
22
+ instance_probe :perform
23
+ end
24
+ end
25
+
26
+ table_setup("cache")
27
+ end
28
+
29
+ def request_start(env, start)
30
+ @stats = Stats.new
31
+ end
32
+
33
+ def request_finish(env, st, hd, bd, timing)
34
+ store(env, @stats)
35
+ end
36
+
37
+ def after_detect(method_call, timing, args, result)
38
+ method, key = method_call.method, args.first
39
+ if(defined? Dalli and Dalli::Client === method_call.object)
40
+ method, key = args[0], args[1]
41
+ end
42
+ logger.info{ "Cache panel got #{method} #{key.inspect}" }
43
+ @stats.record_call(method, timing.duration, !result.nil?, key)
44
+ end
45
+
46
+ def panel_app
47
+ PanelApp.new
48
+ end
49
+
50
+ def name
51
+ "cache"
52
+ end
53
+
54
+ def heading_for_request(number)
55
+ stats = retrieve(number).first
56
+
57
+ "Cache: %.2fms (#{stats.queries.size} calls)" % stats.time
58
+ end
59
+
60
+ def content_for_request(number)
61
+ logger.debug{{ :req_num => number }}
62
+ stats = retrieve(number).first
63
+ render_template "panels/cache", :stats => stats
64
+ end
65
+
66
+ end
67
+
68
+ end
@@ -0,0 +1,46 @@
1
+ module Rack::Insight
2
+ class CachePanel
3
+
4
+ class PanelApp < ::Rack::Insight::PanelApp
5
+
6
+ def dispatch
7
+ case request.path_info
8
+ when "/__insight__/view_cache" then view_cache
9
+ when "/__insight__/delete_cache" then delete_cache
10
+ when "/__insight__/delete_cache_list" then delete_cache_list
11
+ else not_found
12
+ end
13
+ end
14
+
15
+ def ok
16
+ Rack::Response.new(["OK"]).to_a
17
+ end
18
+
19
+ def view_cache
20
+ validate_params
21
+ render_template "panels/view_cache", :key => params["key"], :value => Rails.cache.read(params["key"])
22
+ end
23
+
24
+ def delete_cache
25
+ validate_params
26
+ raise "Rails not found... can't delete key" unless defined?(Rails)
27
+ Rails.cache.delete(params["key"])
28
+ ok
29
+ end
30
+
31
+ def delete_cache_list
32
+ validate_params
33
+ raise "Rails not found... can't delete key" unless defined?(Rails)
34
+
35
+ params.each do |key, value|
36
+ next unless key =~ /^keys_/
37
+ Rails.cache.delete(value)
38
+ end
39
+
40
+ ok
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,90 @@
1
+ module Rack::Insight
2
+ class CachePanel
3
+
4
+ class Stats
5
+ class Query
6
+ attr_reader :method, :time, :hit, :keys
7
+
8
+ def initialize(method, time, hit, keys)
9
+ @method = method
10
+ @time = time
11
+ @hit = hit
12
+ @keys = keys
13
+ end
14
+
15
+ def display_time
16
+ "%.2fms" % time
17
+ end
18
+
19
+ def display_keys
20
+ if keys.size == 1
21
+ keys.first
22
+ else
23
+ keys.join(", ")
24
+ end
25
+ end
26
+ end
27
+
28
+ attr_reader :calls, :keys, :queries, :time
29
+
30
+ def initialize
31
+ @queries = []
32
+ @misses =
33
+ @calls = 0
34
+ @time = 0.0
35
+ @keys = []
36
+ end
37
+
38
+ def record_call(method, time, hit, key)
39
+ if Array === key
40
+ @queries << Query.new(:get_multi, time, hit, key)
41
+ else
42
+ @queries << Query.new(method.to_sym, time, hit, [key])
43
+ end
44
+ @calls += 1
45
+ @time += time
46
+ @keys += keys
47
+ end
48
+
49
+ def display_time
50
+ "%.2fms" % time
51
+ end
52
+
53
+ def gets
54
+ count_queries(:get)
55
+ end
56
+
57
+ def sets
58
+ count_queries(:set)
59
+ end
60
+
61
+ def deletes
62
+ count_queries(:delete)
63
+ end
64
+
65
+ def get_multis
66
+ count_queries(:get_multi)
67
+ end
68
+
69
+ def hits
70
+ @queries.select { |q| [:get, :get_multi].include?(q.method) && q.hit }.size
71
+ end
72
+
73
+ def misses
74
+ @queries.select { |q| [:get, :get_multi].include?(q.method) && !q.hit }.size
75
+ end
76
+
77
+ def count_queries(method)
78
+ @queries.select { |q| q.method == method }.size
79
+ end
80
+
81
+ def queries_to_param
82
+ params = {}
83
+ @queries.each_with_index do |query, index|
84
+ params["keys_#{index}"] = query.keys.first
85
+ end
86
+ params
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,53 @@
1
+ module Rack::Insight
2
+ class LogPanel < Panel
3
+ class LogEntry
4
+ attr_reader :level, :time, :message
5
+ LEVELS = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL']
6
+
7
+ def initialize(level, time, message)
8
+ @level = LEVELS[level]
9
+ @time = time
10
+ @message = message
11
+ end
12
+
13
+ def cleaned_message
14
+ @message.to_s.gsub(/\e\[[;\d]+m/, "")
15
+ end
16
+ end
17
+
18
+ def after_detect(method_call, timing, args, message)
19
+ message = args[1] || args[2] unless message.is_a?(String)
20
+ log_level = args[0]
21
+ store(@env, LogEntry.new(log_level, timing.delta_t, message))
22
+ end
23
+
24
+ def initialize(app)
25
+ probe(self) do
26
+ instrument "ActiveSupport::BufferedLogger" do
27
+ instance_probe :add
28
+ end
29
+
30
+ instrument "Logger" do
31
+ instance_probe :add
32
+ end
33
+ end
34
+
35
+ table_setup("log_entries")
36
+
37
+ super
38
+ end
39
+
40
+ def name
41
+ "log"
42
+ end
43
+
44
+ def heading
45
+ "Log"
46
+ end
47
+
48
+ def content_for_request(number)
49
+ render_template "panels/log", :logs => retrieve(number)
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,36 @@
1
+ module Rack::Insight
2
+
3
+ class MemoryPanel < Panel
4
+ def initialize(app)
5
+ super
6
+ table_setup("memory_records")
7
+ end
8
+
9
+ def before(env)
10
+ @original_memory = `ps -o rss= -p #{$$}`.to_i
11
+ end
12
+
13
+ def after(env, status, headers, body)
14
+ total_memory = `ps -o rss= -p #{$$}`.to_i
15
+ store(env, {:total_memory => total_memory,
16
+ :memory_increase => total_memory - @original_memory,
17
+ :original_memory => @original_memory})
18
+ end
19
+
20
+ def heading_for_request(number)
21
+ record = retrieve(number).first
22
+
23
+ "#{record[:memory_increase]} KB &#916;, #{record[:total_memory]} KB total"
24
+ end
25
+
26
+ def has_content?
27
+ false
28
+ end
29
+
30
+ def name
31
+ "Memory"
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,41 @@
1
+ module Rack::Insight
2
+
3
+ class MongoPanel < Panel
4
+ require "rack/insight/panels/mongo_panel/mongo_extension"
5
+ require "rack/insight/panels/mongo_panel/stats"
6
+
7
+ def self.record(command, &block)
8
+ return block.call unless Rack::Insight.enabled?
9
+
10
+ start_time = Time.now
11
+ result = block.call
12
+ total_time = Time.now - start_time
13
+ stats.record_call(total_time * 1_000, command)
14
+ return result
15
+ end
16
+
17
+ def self.reset
18
+ Thread.current["rack-insight.mongo"] = Stats.new
19
+ end
20
+
21
+ def self.stats
22
+ Thread.current["rack-insight.mongo"] ||= Stats.new
23
+ end
24
+
25
+ def name
26
+ "mongo"
27
+ end
28
+
29
+ def heading
30
+ "Mongo: %.2fms (#{self.class.stats.queries.size} calls)" % self.class.stats.time
31
+ end
32
+
33
+ def content
34
+ result = render_template "panels/mongo", :stats => self.class.stats
35
+ self.class.reset
36
+ return result
37
+ end
38
+
39
+ end
40
+
41
+ end
@@ -0,0 +1,24 @@
1
+ require 'mongo'
2
+ if defined?(Mongo)
3
+ Mongo::Connection.class_eval do
4
+
5
+ def send_message_with_insight(operation, message, log_message=nil)
6
+ Rack::Insight::MongoPanel.record(log_message || message) do
7
+ send_message_without_insight(operation, message, log_message)
8
+ end
9
+ end
10
+ alias_method_chain :send_message, :insight
11
+
12
+ def send_message_with_safe_check_with_insight(operation, message, db_name, log_message=nil, last_error_params=false)
13
+ Rack::Insight::MongoPanel.record(log_message || message) do
14
+ send_message_with_safe_check_without_insight(operation, message, db_name, log_message, last_error_params)
15
+ end
16
+ end
17
+ alias_method_chain :send_message_with_safe_check, :insight
18
+
19
+ def receive_message_with_insight(operation, message, log_message=nil, socket=nil)
20
+ end
21
+ end
22
+ alias_method_chain :receive_message, :insight
23
+ end
24
+