logical-insight 0.4.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 (100) hide show
  1. data/History.txt +45 -0
  2. data/MIT-LICENSE.txt +19 -0
  3. data/README.md +123 -0
  4. data/Rakefile +24 -0
  5. data/Thorfile +113 -0
  6. data/lib/insight.rb +17 -0
  7. data/lib/insight/app.rb +189 -0
  8. data/lib/insight/database.rb +186 -0
  9. data/lib/insight/enable-button.rb +43 -0
  10. data/lib/insight/filtered_backtrace.rb +45 -0
  11. data/lib/insight/instrumentation.rb +9 -0
  12. data/lib/insight/instrumentation/backstage.rb +10 -0
  13. data/lib/insight/instrumentation/client.rb +20 -0
  14. data/lib/insight/instrumentation/instrument.rb +109 -0
  15. data/lib/insight/instrumentation/package-definition.rb +58 -0
  16. data/lib/insight/instrumentation/probe-definition.rb +20 -0
  17. data/lib/insight/instrumentation/probe.rb +199 -0
  18. data/lib/insight/instrumentation/setup.rb +32 -0
  19. data/lib/insight/logger.rb +55 -0
  20. data/lib/insight/options.rb +102 -0
  21. data/lib/insight/panel.rb +119 -0
  22. data/lib/insight/panel_app.rb +31 -0
  23. data/lib/insight/panels-content.rb +22 -0
  24. data/lib/insight/panels-header.rb +18 -0
  25. data/lib/insight/panels/active_record_panel.rb +46 -0
  26. data/lib/insight/panels/cache_panel.rb +69 -0
  27. data/lib/insight/panels/cache_panel/panel_app.rb +46 -0
  28. data/lib/insight/panels/cache_panel/stats.rb +98 -0
  29. data/lib/insight/panels/log_panel.rb +54 -0
  30. data/lib/insight/panels/memory_panel.rb +32 -0
  31. data/lib/insight/panels/rails_info_panel.rb +19 -0
  32. data/lib/insight/panels/redis_panel.rb +42 -0
  33. data/lib/insight/panels/redis_panel/redis_extension.rb +23 -0
  34. data/lib/insight/panels/redis_panel/stats.rb +50 -0
  35. data/lib/insight/panels/request_variables_panel.rb +70 -0
  36. data/lib/insight/panels/speedtracer_panel.rb +89 -0
  37. data/lib/insight/panels/speedtracer_panel/trace-app.rb +52 -0
  38. data/lib/insight/panels/speedtracer_panel/tracer.rb +212 -0
  39. data/lib/insight/panels/sql_panel.rb +53 -0
  40. data/lib/insight/panels/sql_panel/panel_app.rb +37 -0
  41. data/lib/insight/panels/sql_panel/query.rb +94 -0
  42. data/lib/insight/panels/templates_panel.rb +58 -0
  43. data/lib/insight/panels/templates_panel/rendering.rb +81 -0
  44. data/lib/insight/panels/timer_panel.rb +40 -0
  45. data/lib/insight/params_signature.rb +61 -0
  46. data/lib/insight/public/__insight__/bookmarklet.html +10 -0
  47. data/lib/insight/public/__insight__/bookmarklet.js +223 -0
  48. data/lib/insight/public/__insight__/insight.css +235 -0
  49. data/lib/insight/public/__insight__/insight.js +123 -0
  50. data/lib/insight/public/__insight__/jquery-1.3.2.js +4376 -0
  51. data/lib/insight/public/__insight__/jquery.tablesorter.min.js +1 -0
  52. data/lib/insight/public/__insight__/spinner.gif +0 -0
  53. data/lib/insight/rack_static_bug_avoider.rb +16 -0
  54. data/lib/insight/redirect_interceptor.rb +25 -0
  55. data/lib/insight/render.rb +72 -0
  56. data/lib/insight/request-recorder.rb +23 -0
  57. data/lib/insight/toolbar.rb +63 -0
  58. data/lib/insight/views/enable-button.html.erb +1 -0
  59. data/lib/insight/views/error.html.erb +17 -0
  60. data/lib/insight/views/headers_fragment.html.erb +20 -0
  61. data/lib/insight/views/panels/active_record.html.erb +17 -0
  62. data/lib/insight/views/panels/cache.html.erb +93 -0
  63. data/lib/insight/views/panels/execute_sql.html.erb +32 -0
  64. data/lib/insight/views/panels/explain_sql.html.erb +32 -0
  65. data/lib/insight/views/panels/log.html.erb +21 -0
  66. data/lib/insight/views/panels/profile_sql.html.erb +32 -0
  67. data/lib/insight/views/panels/rails_info.html.erb +19 -0
  68. data/lib/insight/views/panels/redis.html.erb +46 -0
  69. data/lib/insight/views/panels/request_variables.html.erb +25 -0
  70. data/lib/insight/views/panels/speedtracer/serverevent.html.erb +10 -0
  71. data/lib/insight/views/panels/speedtracer/servertrace.html.erb +12 -0
  72. data/lib/insight/views/panels/speedtracer/traces.html.erb +18 -0
  73. data/lib/insight/views/panels/sql.html.erb +43 -0
  74. data/lib/insight/views/panels/templates.html.erb +6 -0
  75. data/lib/insight/views/panels/timer.html.erb +19 -0
  76. data/lib/insight/views/panels/view_cache.html.erb +19 -0
  77. data/lib/insight/views/redirect.html.erb +16 -0
  78. data/lib/insight/views/request_fragment.html.erb +25 -0
  79. data/lib/insight/views/toolbar.html.erb +29 -0
  80. data/lib/logical-insight.rb +1 -0
  81. data/spec/custom_matchers.rb +31 -0
  82. data/spec/fixtures/config.ru +8 -0
  83. data/spec/fixtures/dummy_panel.rb +2 -0
  84. data/spec/fixtures/sample_app.rb +72 -0
  85. data/spec/insight/panels/active_record_panel_spec.rb +42 -0
  86. data/spec/insight/panels/cache_panel_spec.rb +176 -0
  87. data/spec/insight/panels/log_panel_spec.rb +44 -0
  88. data/spec/insight/panels/memory_panel_spec.rb +19 -0
  89. data/spec/insight/panels/mongo_panel_spec_pending.rb +50 -0
  90. data/spec/insight/panels/rails_info_panel_spec.rb +27 -0
  91. data/spec/insight/panels/redis_panel_spec.rb +66 -0
  92. data/spec/insight/panels/sql_panel_spec.rb +145 -0
  93. data/spec/insight/panels/templates_panel_spec.rb +84 -0
  94. data/spec/insight/panels/timer_panel_spec.rb +36 -0
  95. data/spec/insight_spec.rb +141 -0
  96. data/spec/instrumentation_spec.rb +188 -0
  97. data/spec/rcov.opts +1 -0
  98. data/spec/spec.opts +1 -0
  99. data/spec/spec_helper.rb +93 -0
  100. metadata +187 -0
@@ -0,0 +1,32 @@
1
+ <a class="back" href="">&laquo;&nbsp;Back</a>
2
+
3
+ <h3>SQL Profiled</h3>
4
+
5
+ <dl>
6
+ <dt>Executed SQL</dt>
7
+ <dd><pre><%=h query %></pre></dd>
8
+
9
+ <dt>Time</dt>
10
+ <dd><%=h "%.2f" % (time * 1_000) %>ms</dd>
11
+ </dl>
12
+
13
+ <table class="sortable">
14
+ <thead>
15
+ <tr>
16
+ <% result.fetch_fields.each do |field| %>
17
+ <th><%= field.name.upcase %></th>
18
+ <% end %>
19
+ </tr>
20
+ </thead>
21
+ <tbody>
22
+ <% i = 1 %>
23
+ <% result.each do |row| %>
24
+ <tr class="<%= i % 2 == 0 ? "even" : "odd" %>">
25
+ <% row.each do |value| %>
26
+ <td><%= value %></td>
27
+ <% end %>
28
+ </tr>
29
+ <% i += 1 %>
30
+ <% end %>
31
+ </tbody>
32
+ </table>
@@ -0,0 +1,19 @@
1
+ <h3>Rails Environment</h3>
2
+ <table>
3
+ <thead>
4
+ <tr>
5
+ <th>Variable</th>
6
+ <th>Value</th>
7
+ </tr>
8
+ </thead>
9
+ <tbody>
10
+ <% i = 1 %>
11
+ <% Rails::Info.properties.each do |key, val| %>
12
+ <tr class="<%= i % 2 == 0 ? "even" : "odd" %>">
13
+ <td><%=h key %></td>
14
+ <td class="code"><div><%=h val %></div></td>
15
+ </tr>
16
+ <% i += 1 %>
17
+ <% end %>
18
+ </tbody>
19
+ </table>
@@ -0,0 +1,46 @@
1
+ <h3>Redis Usage</h3>
2
+ <table id="redis_usage">
3
+ <tr>
4
+ <th>Total Calls</th>
5
+ <td><%= stats.calls %></td>
6
+
7
+ <th>Total Time</th>
8
+ <td><%= stats.display_time %></td>
9
+ </tr>
10
+ </table>
11
+
12
+ <% if stats.queries.any? %>
13
+ <h3>Breakdown</h3>
14
+ <table id="redis_breakdown">
15
+ <thead>
16
+ <tr>
17
+ <th>Time&nbsp;(ms)</th>
18
+ <th>Command</th>
19
+ <th class="backtrace"></th>
20
+ </tr>
21
+ </thead>
22
+ <tbody>
23
+ <% i = 1 %>
24
+ <% stats.queries.each do |query| %>
25
+ <tr class="<%= i % 2 == 0 ? "even" : "odd" %>">
26
+ <td><%= query.display_time %></td>
27
+ <td><%= query.command %></td>
28
+ <td><%= "<a href='#' class='reveal_backtrace'>Show Backtrace</a>" if query.has_backtrace? %></td>
29
+ </tr>
30
+ <% if query.has_backtrace? %>
31
+ <tr style="display:none">
32
+ <td></td>
33
+ <td colspan="2">
34
+ <ul>
35
+ <% query.filtered_backtrace.each do |line| %>
36
+ <li><%=h line %></li>
37
+ <% end %>
38
+ </ul>
39
+ </td>
40
+ </tr>
41
+ <% end %>
42
+ <% i += 1 %>
43
+ <% end %>
44
+ </tbody>
45
+ </table>
46
+ <% end %>
@@ -0,0 +1,25 @@
1
+ <% ["GET", "POST", "Session", "Cookies", "SERVER VARIABLES", "Rack ENV"].each do |header|
2
+ next unless sections.has_key?(header)
3
+ %>
4
+ <h3><%=header%></h3>
5
+ <table id="request_variables">
6
+ <thead>
7
+ <tr>
8
+ <th>Variable</th>
9
+ <th>Value</th>
10
+ </tr>
11
+ </thead>
12
+ <tbody>
13
+ <% i = 1 %>
14
+ <% sections[header].each do |key, val| %>
15
+ <tr class="<%= i % 2 == 0 ? "even" : "odd" %>">
16
+ <td><%=h key %></td>
17
+ <td class="code"><div>
18
+ <%=h val%>
19
+ </div></td>
20
+ </tr>
21
+ <% i += 1 %>
22
+ <% end %>
23
+ </tbody>
24
+ </table>
25
+ <% end %>
@@ -0,0 +1,10 @@
1
+ <div class="traceblock">
2
+ <%=operation['label']%> - <%=range['duration']%>ms (self: <%=self_time%>ms)
3
+ <% unless children.empty? %>
4
+ <ul>
5
+ <% children.each do |child|%>
6
+ <li><%=child.to_html%></li>
7
+ <%end%>
8
+ </ul>
9
+ <% end %>
10
+ </div>
@@ -0,0 +1,12 @@
1
+ <a href='<%=url%>'>Raw JSON</a>
2
+ <dl>
3
+ <dt>Name</dt><dd><%=frameStack['label']%></dd>
4
+ <dt>Began</dt><dd><%=frameStack['range']['start']%></dd>
5
+ <dt>Duration</dt><dd><%=frameStack['range']['duration']%></dd>
6
+ <dt>Children</dt>
7
+ <dd><ul>
8
+ <% frameStack['children'].each do |child| %>
9
+ <li><%= child.to_html %></li>
10
+ <%end%>
11
+ </ul></dd>
12
+ </dl>
@@ -0,0 +1,18 @@
1
+ <h3>Trace</h3>
2
+ <h4>Process: <%= Process.pid %> (<%= Process.ppid %>)</h4>
3
+ <% unless advice.empty? %>
4
+ <p>Warning:</p>
5
+ <ul>
6
+ <% advice.each do |item| %>
7
+ <li><%= item %></li>
8
+ <% end %>
9
+ </ul>
10
+ <% end %>
11
+ <dl>
12
+ <% if trace.nil? %>
13
+ <dt>Problem</dt><dd>Trace is nil</dd>
14
+ <% else %>
15
+ <dt><%= trace.uuid %> - <%= trace.start.strftime("%H:%M:%S") %></dt>
16
+ <dd><%= trace.to_html %></dd>
17
+ <% end %>
18
+ </dl>
@@ -0,0 +1,43 @@
1
+ <h3>SQL Queries</h3>
2
+ <table class="sortable">
3
+ <thead>
4
+ <tr>
5
+ <th class="time">Time&nbsp;(ms)</th>
6
+ <th class="query">Query</th>
7
+ <th class="backtrace"></th>
8
+ <th class="actions"></th>
9
+ </tr>
10
+ </thead>
11
+ <tbody>
12
+ <% i = 1 %>
13
+ <% queries.each do |query| %>
14
+ <tr class="<%= i % 2 == 0 ? "even" : "odd" %>">
15
+ <td><%= query.human_time %></td>
16
+ <td class="syntax"><%= query.sql %></td>
17
+ <td>
18
+ <% if query.has_backtrace? %>
19
+ <a href="#" class="reveal_backtrace">Show Backtrace</a>
20
+ <% end %>
21
+ </td>
22
+ <td>
23
+ <% if query.inspectable? %>
24
+ <a href="/__insight__/sql/execute?<%= signed_params("query" => query.sql, "time" => query.time) %>" class="remote_call">SELECT</a> |
25
+ <a href="/__insight__/sql/explain?<%= signed_params("query" => query.sql, "time" => query.time) %>" class="remote_call">EXPLAIN</a> |
26
+ <a href="/__insight__/sql/profile?<%= signed_params("query" => query.sql, "time" => query.time) %>" class="remote_call">Profile</a>
27
+ <% end %>
28
+ </td>
29
+ </tr>
30
+ <tr style="display:none">
31
+ <td></td>
32
+ <td colspan="3">
33
+ <ul>
34
+ <% query.filtered_backtrace.each do |line| %>
35
+ <li><%=h line %></li>
36
+ <% end %>
37
+ </ul>
38
+ </td>
39
+ </tr>
40
+ <% i += 1 %>
41
+ <% end %>
42
+ </tbody>
43
+ </table>
@@ -0,0 +1,6 @@
1
+ <h3>Templates</h3>
2
+ <ul>
3
+ <% root_rendering.children.each do |child| %>
4
+ <%= child.html %>
5
+ <% end %>
6
+ </ul>
@@ -0,0 +1,19 @@
1
+ <h3>Resource Usage</h3>
2
+ <table class="sortable">
3
+ <thead>
4
+ <tr>
5
+ <th>Key</th>
6
+ <th>Value</th>
7
+ </tr>
8
+ </thead>
9
+ <tbody>
10
+ <% i = 1 %>
11
+ <% measurements.each do |key, val| %>
12
+ <tr class="<%= i % 2 == 0 ? "even" : "odd" %>">
13
+ <td><%=h key %></td>
14
+ <td><%=h val %></td>
15
+ </tr>
16
+ <% i += 1 %>
17
+ <% end %>
18
+ </tbody>
19
+ </table>
@@ -0,0 +1,19 @@
1
+ <a class="back" href="">&laquo;&nbsp;Back</a>
2
+
3
+ <h3>Cache Read</h3>
4
+
5
+ <dl>
6
+ <dt>Key</dt>
7
+ <dd><pre><%=h key %></pre></dd>
8
+
9
+ <dt>Time</dt>
10
+ <dd><%=h "%.2f" % (0.0 * 1_000) %>ms</dd>
11
+ </dl>
12
+
13
+ <p>
14
+ <% if value.is_a?(String )%>
15
+ <%=h value %>
16
+ <% else %>
17
+ <%=h value.inspect %>
18
+ <% end %>
19
+ </p>
@@ -0,0 +1,16 @@
1
+ <html>
2
+ <head>
3
+ </head>
4
+ <body>
5
+ <h1>Redirect</h1>
6
+
7
+ <p>Location: <a href="<%= redirect_to %>"><%= redirect_to %></a></p>
8
+
9
+ <p class="notice">
10
+ Insight has intercepted a redirect to the above URL for debug viewing
11
+ purposes. You can click the above link to continue with the redirect as
12
+ normal. If you'd like to disable this feature, set the Insight
13
+ <code>internal_redirects</code> option to <code>false</code>.
14
+ </p>
15
+ </body>
16
+ </html>
@@ -0,0 +1,25 @@
1
+ <div id="request_<%=request_id%>">
2
+ <% panels.each do |panel| %>
3
+ <% if panel.has_content? %>
4
+ <div class="panel_content" id="<%= panel.name %>">
5
+ <div class="panel_controls">
6
+ <form action="#">
7
+ <select id="request_id_menu" name="current_request">
8
+ <% requests.sort{|l,r| r[:id] <=> l[:id]}.each do |request| %>
9
+ <option value="<%= request[:id] %>" <%= request[:id] == request_id ? "selected" : "" %>>
10
+ <%= request[:id] %>: <%= request[:method] %> <%= request[:path] %>
11
+ </option>
12
+ <% end %>
13
+ </select>
14
+ </form>
15
+ <a href="" class="insight_close">Close</a>
16
+ </div>
17
+ <% begin %>
18
+ <%= panel.content_for_request(request_id) %>
19
+ <% rescue Object => ex %>
20
+ <%= "Error #{ex.class.name}: #{ex.message} <!-- #{ex.backtrace[0..5]} -->" %>
21
+ <% end %>
22
+ </div>
23
+ <% end %>
24
+ <% end %>
25
+ </div>
@@ -0,0 +1,29 @@
1
+ <script type="text/javascript" charset="utf-8">
2
+ if (typeof jQuery == 'undefined') {
3
+ var jquery_url = '/__insight__/jquery-1.3.2.js';
4
+ document.write(unescape('%3Cscript src="' + jquery_url + '" type="text/javascript"%3E%3C/script%3E'));
5
+ }
6
+ </script>
7
+ <script type="text/javascript" src="/__insight__/jquery.tablesorter.min.js"></script>
8
+ <script type="text/javascript" src="/__insight__/bookmarklet.js"></script>
9
+ <script type="text/javascript" src="/__insight__/insight.js"></script>
10
+ <style type="text/css" media="screen">
11
+ @import url(/__insight__/insight.css);
12
+ </style>
13
+ <script>
14
+ $(function($) {
15
+ $.insight.request_id = <%= request_id %>
16
+ })
17
+ </script>
18
+
19
+ <div id="insight" class="insight_top">
20
+ <div id="insight_toolbar">
21
+ <ul class="panels">
22
+ <%= headers_fragment %>
23
+ </ul>
24
+ </div>
25
+
26
+ <%= request_fragment %>
27
+
28
+ <div id="insight_debug_window" class="panel_content"></div>
29
+ </div>
@@ -0,0 +1 @@
1
+ require 'insight'
@@ -0,0 +1,31 @@
1
+ module CustomMatchers
2
+ extend RSpec::Matchers::DSL
3
+
4
+ define :have_row do |container, key, value|
5
+ match do |response|
6
+ if value
7
+ response.should have_selector("#{container} tr", :content => key) do |row|
8
+ row.should contain(value)
9
+ end
10
+ else
11
+ response.should have_selector("#{container} tr", :content => key)
12
+ end
13
+ end
14
+
15
+ failure_message_for_should do |response|
16
+ "Expected: \n#{response.body}\nto have a row matching #{key}"
17
+ end
18
+ end
19
+
20
+ define :have_heading do |text|
21
+ match do |response|
22
+ response.should have_selector("#insight_toolbar li") do |heading|
23
+ heading.should contain(text)
24
+ end
25
+ end
26
+
27
+ failure_message_for_should do |response|
28
+ "Expected: \n#{response.body}\nto have heading #{text}"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,8 @@
1
+ require "rubygems"
2
+
3
+ $LOAD_PATH.unshift File.dirname(__FILE__)
4
+ require "sample_app"
5
+
6
+ #Example usage, but moved inside sample app for easier testing
7
+ #use Rack::Bug, :password => "secret"
8
+ run SampleApp
@@ -0,0 +1,2 @@
1
+ class DummyPanel < Insight::Panel
2
+ end
@@ -0,0 +1,72 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
2
+ require "sinatra/base"
3
+ require 'logger'
4
+
5
+ RAILS_ENV = "development" unless defined?(RAILS_ENV)
6
+ log_to = RAILS_ENV == "test" ? StringIO.new : STDOUT
7
+ LOGGER = Logger.new(log_to)
8
+
9
+ class SampleApp < Sinatra::Base
10
+ class OneLastThing
11
+ def initialize(app)
12
+ @app = app
13
+ end
14
+
15
+ def call(env)
16
+ st,hd,bd = @app.call(env)
17
+ unless SampleApp.before_returning.nil?
18
+ SampleApp.before_returning.call
19
+ SampleApp.before_returning = nil
20
+ end
21
+ return st,hd,bd
22
+ end
23
+ end
24
+
25
+ class << self
26
+ attr_accessor :insight_app
27
+ attr_accessor :before_returning
28
+ def before_return(&block)
29
+ self.before_returning = block
30
+ end
31
+ end
32
+
33
+
34
+
35
+ use Insight::App, :log_path => "insight-test.log", :on_initialize => proc {|app|
36
+ self.insight_app = app
37
+ }
38
+ use OneLastThing
39
+
40
+ set :environment, 'test'
41
+
42
+ configure :test do
43
+ set :raise_errors, true
44
+ end
45
+
46
+ get "/redirect" do
47
+ redirect "/"
48
+ end
49
+
50
+ get "/error" do
51
+ raise "Error!"
52
+ end
53
+
54
+ get "/" do
55
+ if params[:content_type]
56
+ headers["Content-Type"] = params[:content_type]
57
+ end
58
+ LOGGER.error "I am a log message"
59
+ <<-HTML
60
+ <html>
61
+ <head>
62
+ </head>
63
+ <body>
64
+ <p>Hello</p>
65
+ <p><a href="__insight__/bookmarklet.html">Page with bookmarklet for enabling Insight</a></p>
66
+ <p><a href="/error">Page with an error to check insight not rescuing errors</a></p>
67
+ </body>
68
+ </html>
69
+ HTML
70
+ end
71
+
72
+ end