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.
- data/.gitignore +13 -0
- data/.rspec +1 -0
- data/.simplecov +4 -0
- data/.travis.yml +8 -0
- data/CHANGELOG +58 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +82 -0
- data/LICENSE +24 -0
- data/README.md +189 -0
- data/Rakefile +27 -0
- data/TODO +7 -0
- data/lib/rack-insight.rb +1 -0
- data/lib/rack/insight.rb +19 -0
- data/lib/rack/insight/app.rb +198 -0
- data/lib/rack/insight/config.rb +30 -0
- data/lib/rack/insight/database.rb +193 -0
- data/lib/rack/insight/enable-button.rb +43 -0
- data/lib/rack/insight/filtered_backtrace.rb +45 -0
- data/lib/rack/insight/instrumentation.rb +9 -0
- data/lib/rack/insight/instrumentation/backstage.rb +10 -0
- data/lib/rack/insight/instrumentation/client.rb +20 -0
- data/lib/rack/insight/instrumentation/instrument.rb +109 -0
- data/lib/rack/insight/instrumentation/package-definition.rb +58 -0
- data/lib/rack/insight/instrumentation/probe-definition.rb +20 -0
- data/lib/rack/insight/instrumentation/probe.rb +196 -0
- data/lib/rack/insight/instrumentation/setup.rb +32 -0
- data/lib/rack/insight/logger.rb +53 -0
- data/lib/rack/insight/options.rb +116 -0
- data/lib/rack/insight/panel.rb +135 -0
- data/lib/rack/insight/panel_app.rb +31 -0
- data/lib/rack/insight/panels-content.rb +22 -0
- data/lib/rack/insight/panels-header.rb +18 -0
- data/lib/rack/insight/panels/active_record_panel.rb +46 -0
- data/lib/rack/insight/panels/active_resource_panel.rb +48 -0
- data/lib/rack/insight/panels/active_resource_panel/query.rb +27 -0
- data/lib/rack/insight/panels/cache_panel.rb +68 -0
- data/lib/rack/insight/panels/cache_panel/panel_app.rb +46 -0
- data/lib/rack/insight/panels/cache_panel/stats.rb +90 -0
- data/lib/rack/insight/panels/log_panel.rb +53 -0
- data/lib/rack/insight/panels/memory_panel.rb +36 -0
- data/lib/rack/insight/panels/mongo_panel.rb +41 -0
- data/lib/rack/insight/panels/mongo_panel/mongo_extension.rb +24 -0
- data/lib/rack/insight/panels/mongo_panel/stats.rb +46 -0
- data/lib/rack/insight/panels/rails_info_panel.rb +19 -0
- data/lib/rack/insight/panels/redis_panel.rb +42 -0
- data/lib/rack/insight/panels/redis_panel/redis_extension.rb +23 -0
- data/lib/rack/insight/panels/redis_panel/stats.rb +50 -0
- data/lib/rack/insight/panels/request_variables_panel.rb +70 -0
- data/lib/rack/insight/panels/speedtracer_panel.rb +89 -0
- data/lib/rack/insight/panels/speedtracer_panel/profiling.rb +29 -0
- data/lib/rack/insight/panels/speedtracer_panel/trace-app.rb +52 -0
- data/lib/rack/insight/panels/speedtracer_panel/tracer.rb +213 -0
- data/lib/rack/insight/panels/sphinx_panel.rb +41 -0
- data/lib/rack/insight/panels/sphinx_panel/stats.rb +94 -0
- data/lib/rack/insight/panels/sql_panel.rb +53 -0
- data/lib/rack/insight/panels/sql_panel/panel_app.rb +37 -0
- data/lib/rack/insight/panels/sql_panel/query.rb +94 -0
- data/lib/rack/insight/panels/templates_panel.rb +58 -0
- data/lib/rack/insight/panels/templates_panel/rendering.rb +81 -0
- data/lib/rack/insight/panels/timer_panel.rb +40 -0
- data/lib/rack/insight/params_signature.rb +61 -0
- data/lib/rack/insight/path-filter.rb +23 -0
- data/lib/rack/insight/public/__insight__/bookmarklet.html +10 -0
- data/lib/rack/insight/public/__insight__/bookmarklet.js +223 -0
- data/lib/rack/insight/public/__insight__/insight.css +235 -0
- data/lib/rack/insight/public/__insight__/insight.js +127 -0
- data/lib/rack/insight/public/__insight__/jquery-1.3.2.js +4376 -0
- data/lib/rack/insight/public/__insight__/jquery.tablesorter.min.js +1 -0
- data/lib/rack/insight/public/__insight__/spinner.gif +0 -0
- data/lib/rack/insight/rack_static_bug_avoider.rb +16 -0
- data/lib/rack/insight/redirect_interceptor.rb +25 -0
- data/lib/rack/insight/render.rb +72 -0
- data/lib/rack/insight/request-recorder.rb +22 -0
- data/lib/rack/insight/rspec_matchers.rb +33 -0
- data/lib/rack/insight/toolbar.rb +69 -0
- data/lib/rack/insight/version.rb +7 -0
- data/lib/rack/insight/views/enable-button.html.erb +21 -0
- data/lib/rack/insight/views/error.html.erb +17 -0
- data/lib/rack/insight/views/headers_fragment.html.erb +20 -0
- data/lib/rack/insight/views/panels/active_record.html.erb +17 -0
- data/lib/rack/insight/views/panels/active_resource.html.erb +47 -0
- data/lib/rack/insight/views/panels/cache.html.erb +93 -0
- data/lib/rack/insight/views/panels/execute_sql.html.erb +32 -0
- data/lib/rack/insight/views/panels/explain_sql.html.erb +32 -0
- data/lib/rack/insight/views/panels/log.html.erb +21 -0
- data/lib/rack/insight/views/panels/mongo.html.erb +32 -0
- data/lib/rack/insight/views/panels/profile_sql.html.erb +32 -0
- data/lib/rack/insight/views/panels/rails_info.html.erb +19 -0
- data/lib/rack/insight/views/panels/redis.html.erb +46 -0
- data/lib/rack/insight/views/panels/request_variables.html.erb +25 -0
- data/lib/rack/insight/views/panels/speedtracer/serverevent.html.erb +10 -0
- data/lib/rack/insight/views/panels/speedtracer/servertrace.html.erb +12 -0
- data/lib/rack/insight/views/panels/speedtracer/traces.html.erb +18 -0
- data/lib/rack/insight/views/panels/sphinx.html.erb +32 -0
- data/lib/rack/insight/views/panels/sql.html.erb +43 -0
- data/lib/rack/insight/views/panels/templates.html.erb +6 -0
- data/lib/rack/insight/views/panels/timer.html.erb +19 -0
- data/lib/rack/insight/views/panels/view_cache.html.erb +19 -0
- data/lib/rack/insight/views/redirect.html.erb +16 -0
- data/lib/rack/insight/views/request_fragment.html.erb +25 -0
- data/lib/rack/insight/views/toolbar.html.erb +29 -0
- data/rack-insight.gemspec +40 -0
- data/spec/custom_matchers.rb +0 -0
- data/spec/fixtures/config.ru +8 -0
- data/spec/fixtures/dummy_panel.rb +2 -0
- data/spec/fixtures/sample_app.rb +72 -0
- data/spec/fixtures/star_trek_panel.rb +1 -0
- data/spec/insight_spec.rb +163 -0
- data/spec/instrumentation_spec.rb +188 -0
- data/spec/rack/insight/config_spec.rb +20 -0
- data/spec/rack/insight/panels/active_record_panel_spec.rb +43 -0
- data/spec/rack/insight/panels/active_resource_panel_spec.rb +40 -0
- data/spec/rack/insight/panels/cache_panel_spec.rb +178 -0
- data/spec/rack/insight/panels/log_panel_spec.rb +44 -0
- data/spec/rack/insight/panels/memory_panel_spec.rb +21 -0
- data/spec/rack/insight/panels/mongo_panel_spec_pending.rb +52 -0
- data/spec/rack/insight/panels/rails_info_panel_spec.rb +29 -0
- data/spec/rack/insight/panels/redis_panel_spec.rb +67 -0
- data/spec/rack/insight/panels/speedtracer_panel_spec.rb +86 -0
- data/spec/rack/insight/panels/sql_panel_spec.rb +146 -0
- data/spec/rack/insight/panels/templates_panel_spec.rb +86 -0
- data/spec/rack/insight/panels/timer_panel_spec.rb +38 -0
- data/spec/rcov.opts +1 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +111 -0
- metadata +380 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Rack::Insight::Instrumentation
|
|
2
|
+
class Setup
|
|
3
|
+
def initialize(app)
|
|
4
|
+
@app = app
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def setup(env)
|
|
8
|
+
instrument = Instrument.new
|
|
9
|
+
|
|
10
|
+
PackageDefinition.start
|
|
11
|
+
instrument.start(env)
|
|
12
|
+
|
|
13
|
+
env["rack-insight.instrument"] = instrument
|
|
14
|
+
Thread::current["rack-insight.instrument"] = instrument
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def teardown(env, status, headers, body)
|
|
18
|
+
instrument, env["rack-insight.instrument"] = env["rack-insight.instrument"], nil
|
|
19
|
+
instrument.finish(env, status, headers, body)
|
|
20
|
+
Thread::current["rack-insight.instrument"] = nil
|
|
21
|
+
|
|
22
|
+
env["rack-insight.duration"] = instrument.duration
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def call(env)
|
|
26
|
+
setup(env)
|
|
27
|
+
status, headers, body = @app.call(env)
|
|
28
|
+
teardown(env, status, headers, body)
|
|
29
|
+
return [status, headers, body]
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module Rack::Insight
|
|
2
|
+
class Logger
|
|
3
|
+
def initialize(level, path)
|
|
4
|
+
@level = level
|
|
5
|
+
@log_path = path
|
|
6
|
+
@logfile = nil
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
attr_accessor :level
|
|
10
|
+
|
|
11
|
+
DEBUG = 0
|
|
12
|
+
INFO = 1
|
|
13
|
+
WARN = 2
|
|
14
|
+
ERROR = 3
|
|
15
|
+
FATAL = 4
|
|
16
|
+
UNKNOWN = 5
|
|
17
|
+
|
|
18
|
+
def log(severity, message)
|
|
19
|
+
message = message.inspect unless String === message
|
|
20
|
+
return unless severity >= @level
|
|
21
|
+
|
|
22
|
+
if defined? Rails and Rails.respond_to?(:logger) and not Rails.logger.nil?
|
|
23
|
+
Rails.logger.add(severity, "[Rack::Insight]: " + message)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
logfile.puts(message)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def logfile
|
|
30
|
+
@logfile ||= File::open(@log_path, "a+")
|
|
31
|
+
rescue
|
|
32
|
+
$stderr
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def debug; log(DEBUG, yield) end
|
|
36
|
+
def info; log(INFO, yield) end
|
|
37
|
+
def warn; log(WARN, yield) end
|
|
38
|
+
def error; log(ERROR, yield) end
|
|
39
|
+
def fatal; log(FATAL, yield) end
|
|
40
|
+
def unknown; log(UNKNOWN, yield) end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
module Logging
|
|
44
|
+
def logger(env = nil)
|
|
45
|
+
if env.nil?
|
|
46
|
+
Thread.current['rack-insight.logger'] ||= Rack::Insight::Logger.new(Logger::DEBUG, "")
|
|
47
|
+
else
|
|
48
|
+
env["rack-insight.logger"] ||= Rack::Insight::Logger.new(Logger::DEBUG, "")
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
module_function :logger
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
require 'ipaddr'
|
|
2
|
+
|
|
3
|
+
module Rack::Insight
|
|
4
|
+
module Options
|
|
5
|
+
class << self
|
|
6
|
+
private
|
|
7
|
+
def option_accessor(key)
|
|
8
|
+
define_method(key) { || read_option(key) }
|
|
9
|
+
define_method("#{key}=") { |value| write_option(key, value) }
|
|
10
|
+
define_method("#{key}?") { || !! read_option(key) }
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
option_accessor :secret_key
|
|
15
|
+
option_accessor :ip_masks
|
|
16
|
+
option_accessor :password
|
|
17
|
+
option_accessor :panel_classes
|
|
18
|
+
option_accessor :intercept_redirects
|
|
19
|
+
option_accessor :database_path
|
|
20
|
+
|
|
21
|
+
# The underlying options Hash. During initialization (or outside of a
|
|
22
|
+
# request), this is a default values Hash. During a request, this is the
|
|
23
|
+
# Rack environment Hash. The default values Hash is merged in underneath
|
|
24
|
+
# the Rack environment before each request is processed.
|
|
25
|
+
def options
|
|
26
|
+
@env || @default_options
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Set multiple options.
|
|
30
|
+
def options=(hash={})
|
|
31
|
+
hash.each { |key,value| write_option(key, value) }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Set an option. When +option+ is a Symbol, it is set in the Rack
|
|
35
|
+
# Environment as "rack-cache.option". When +option+ is a String, it
|
|
36
|
+
# exactly as specified. The +option+ argument may also be a Hash in
|
|
37
|
+
# which case each key/value pair is merged into the environment as if
|
|
38
|
+
# the #set method were called on each.
|
|
39
|
+
def set(option, value=self, &block)
|
|
40
|
+
if block_given?
|
|
41
|
+
write_option option, block
|
|
42
|
+
elsif value == self
|
|
43
|
+
self.options = option.to_hash
|
|
44
|
+
else
|
|
45
|
+
write_option option, value
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def read_option(key)
|
|
52
|
+
key = option_name(key)
|
|
53
|
+
if @env and @env.has_key?(key)
|
|
54
|
+
@env[key]
|
|
55
|
+
else
|
|
56
|
+
@default_options[key]
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def write_option(key, value)
|
|
61
|
+
@default_options[option_name(key)] = value
|
|
62
|
+
if @env.respond_to? :[]
|
|
63
|
+
@env[option_name(key)] = value
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def option_name(key)
|
|
68
|
+
case key
|
|
69
|
+
when Symbol ; "rack-insight.#{key}"
|
|
70
|
+
when String ; key
|
|
71
|
+
else raise ArgumentError
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def process_options
|
|
76
|
+
if(file_list = read_option('rack-insight.panel_files'))
|
|
77
|
+
class_list = read_option('rack-insight.panel_classes') || []
|
|
78
|
+
file_list.each do |file|
|
|
79
|
+
class_list |= Rack::Insight::Panel.from_file(file)
|
|
80
|
+
end
|
|
81
|
+
write_option('rack-insight.panel_classes', class_list)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
Rack::Insight::Database.database_path = read_option('rack-insight.database_path')
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def initialize_options(options=nil)
|
|
88
|
+
@default_options = {
|
|
89
|
+
'rack-insight.ip_masks' => [IPAddr.new("127.0.0.1")],
|
|
90
|
+
'rack-insight.password' => nil,
|
|
91
|
+
'rack-insight.verbose' => nil,
|
|
92
|
+
'rack-insight.secret_key' => nil,
|
|
93
|
+
'rack-insight.intercept_redirects' => false,
|
|
94
|
+
'rack-insight.panels' => [],
|
|
95
|
+
'rack-insight.path_filters' => %w{/assets/},
|
|
96
|
+
'rack-insight.log_level' => Logger::INFO,
|
|
97
|
+
'rack-insight.log_path' => "log/rack-insight.log",
|
|
98
|
+
'rack-insight.database_path' => "rack-insight.sqlite",
|
|
99
|
+
'rack-insight.panel_files' => %w{
|
|
100
|
+
rails_info_panel
|
|
101
|
+
timer_panel
|
|
102
|
+
request_variables_panel
|
|
103
|
+
sql_panel
|
|
104
|
+
active_record_panel
|
|
105
|
+
cache_panel
|
|
106
|
+
templates_panel
|
|
107
|
+
log_panel
|
|
108
|
+
memory_panel
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
self.options = options || {}
|
|
112
|
+
process_options
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
require "erb"
|
|
2
|
+
require "rack/insight/logger"
|
|
3
|
+
require 'rack/insight/database'
|
|
4
|
+
require 'rack/insight/instrumentation'
|
|
5
|
+
require 'rack/insight/render'
|
|
6
|
+
|
|
7
|
+
module Rack::Insight
|
|
8
|
+
|
|
9
|
+
# Panels are also Rack middleware
|
|
10
|
+
class Panel
|
|
11
|
+
include ERB::Util
|
|
12
|
+
include Rack::Insight::Logging
|
|
13
|
+
include Rack::Insight::Render
|
|
14
|
+
include Rack::Insight::Database::RequestDataClient
|
|
15
|
+
include Rack::Insight::Instrumentation::Client
|
|
16
|
+
|
|
17
|
+
attr_reader :request
|
|
18
|
+
|
|
19
|
+
class << self
|
|
20
|
+
def file_index
|
|
21
|
+
return @file_index ||= Hash.new do |h,k|
|
|
22
|
+
h[k] = []
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def panel_exclusion
|
|
27
|
+
return @panel_exclusion ||= []
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def from_file(rel_path)
|
|
31
|
+
old_rel, Thread::current['rack-panel_file'] = Thread::current['rack-panel_file'], rel_path
|
|
32
|
+
Rack::Insight::Config.config[:panel_load_paths].each do |load_path|
|
|
33
|
+
begin
|
|
34
|
+
require File::join(load_path, rel_path)
|
|
35
|
+
rescue LoadError => e
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
return (file_index[rel_path] - panel_exclusion)
|
|
39
|
+
ensure
|
|
40
|
+
Thread::current['rack-panel_file'] = old_rel
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def current_panel_file
|
|
44
|
+
return Thread::current['rack-panel_file'] ||
|
|
45
|
+
begin
|
|
46
|
+
file_name = nil
|
|
47
|
+
matched_line = nil
|
|
48
|
+
caller.each do |line|
|
|
49
|
+
# First make sure we are not matching rack-insight's own panel class, which will be in the caller stack,
|
|
50
|
+
# and which may match some custom load path added (try adding 'rack' as a custom load path!)
|
|
51
|
+
next if line =~ /rack-insight.*\/lib\/rack\/insight\/panel.rb:/
|
|
52
|
+
Rack::Insight::Config.config[:panel_load_paths].each do |load_path|
|
|
53
|
+
regex = %r{^[^:]*#{load_path}/([^:]*)\.rb:}
|
|
54
|
+
md = regex.match line
|
|
55
|
+
file_name = md[1] unless md.nil?
|
|
56
|
+
matched_line = line unless file_name.nil?
|
|
57
|
+
break unless file_name.nil?
|
|
58
|
+
end
|
|
59
|
+
break unless file_name.nil?
|
|
60
|
+
end
|
|
61
|
+
file_name
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def inherited(sub)
|
|
66
|
+
if filename = current_panel_file
|
|
67
|
+
Panel::file_index[current_panel_file] << sub
|
|
68
|
+
else
|
|
69
|
+
warn "Rack::Insight::Panel inherited by #{sub.name} outside rack-insight's :panel_load_paths. Discarded. Configured panel load paths are: #{Rack::Insight::Config.config[:panel_load_paths].inspect}"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def excluded(klass = nil)
|
|
74
|
+
Panel::panel_exclusion << klass || self
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def initialize(app)
|
|
80
|
+
if panel_app
|
|
81
|
+
#XXX use mappings
|
|
82
|
+
@app = Rack::Cascade.new([panel_app, app])
|
|
83
|
+
else
|
|
84
|
+
@app = app
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def call(env)
|
|
89
|
+
@env = env
|
|
90
|
+
logger.debug{ "Before call: #{self.name}" }
|
|
91
|
+
before(env)
|
|
92
|
+
status, headers, body = @app.call(env)
|
|
93
|
+
@request = Rack::Request.new(env)
|
|
94
|
+
logger.debug{ "After call: #{self.name}" }
|
|
95
|
+
after(env, status, headers, body)
|
|
96
|
+
env["rack-insight.panels"] << self
|
|
97
|
+
return [status, headers, body]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def panel_app
|
|
101
|
+
nil
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def self.panel_mappings
|
|
105
|
+
{}
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def has_content?
|
|
109
|
+
true
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def name
|
|
113
|
+
"Unnamed panel: #{self.class.name}" #for shame
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def heading_for_request(number)
|
|
117
|
+
heading rescue "xxx" #XXX: no panel should need this
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def content_for_request(number)
|
|
121
|
+
content rescue "" #XXX: no panel should need this
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def before(env)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def after(env, status, headers, body)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def render(template)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Rack::Insight
|
|
2
|
+
|
|
3
|
+
class PanelApp
|
|
4
|
+
include Rack::Insight::Render
|
|
5
|
+
|
|
6
|
+
attr_reader :request
|
|
7
|
+
|
|
8
|
+
def call(env)
|
|
9
|
+
@request = Rack::Request.new(env)
|
|
10
|
+
dispatch
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def render_template(*args)
|
|
14
|
+
Rack::Response.new([super]).to_a
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def params
|
|
18
|
+
@request.GET
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def not_found(message="")
|
|
22
|
+
[404, {}, [message]]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def validate_params
|
|
26
|
+
ParamsSignature.new(request).validate!
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Rack::Insight
|
|
2
|
+
class PanelsContent < PanelApp
|
|
3
|
+
def initialize(insight_app)
|
|
4
|
+
@insight_app = insight_app
|
|
5
|
+
@request_table = Database::RequestTable.new
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def dispatch
|
|
9
|
+
return not_found("not get") unless @request.get?
|
|
10
|
+
return not_found("id nil") if params['request_id'].nil?
|
|
11
|
+
request = @request_table.select("*", "id = #{params['request_id']}").first
|
|
12
|
+
return not_found("id not found") if request.nil?
|
|
13
|
+
requests = @request_table.to_a.map do |row|
|
|
14
|
+
{ :id => row[0], :method => row[1], :path => row[2] }
|
|
15
|
+
end
|
|
16
|
+
render_template("request_fragment",
|
|
17
|
+
:request_id => params['request_id'].to_i,
|
|
18
|
+
:requests => requests,
|
|
19
|
+
:panels => @insight_app.panels)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Rack::Insight
|
|
2
|
+
class PanelsHeader < PanelApp
|
|
3
|
+
def initialize(insight_app)
|
|
4
|
+
@insight_app = insight_app
|
|
5
|
+
@request_table = Database::RequestTable.new
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def dispatch
|
|
9
|
+
return not_found("not get") unless @request.get?
|
|
10
|
+
return not_found("id nil") if params['request_id'].nil?
|
|
11
|
+
request = @request_table.select("*", "id = #{params['request_id']}").first
|
|
12
|
+
return not_found("id not found") if request.nil?
|
|
13
|
+
render_template("headers_fragment",
|
|
14
|
+
:request_id => params['request_id'].to_i,
|
|
15
|
+
:panels => @insight_app.panels)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Rack::Insight
|
|
2
|
+
class ActiveRecordPanel < Panel
|
|
3
|
+
def initialize(app)
|
|
4
|
+
super
|
|
5
|
+
|
|
6
|
+
table_setup("active_record")
|
|
7
|
+
|
|
8
|
+
probe(self) do
|
|
9
|
+
instrument "ActiveRecord::Base" do
|
|
10
|
+
class_probe :allocate
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def request_start(env, start)
|
|
16
|
+
@records = Hash.new{ 0 }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def after_detect(method_call, timing, results, args)
|
|
20
|
+
@records[method_call.object.base_class.name] += 1
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def request_finish(env, status, headers, body, timing)
|
|
24
|
+
store(env, @records)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def name
|
|
28
|
+
"active_record"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def heading_for_request(number)
|
|
32
|
+
record = retrieve(number).first
|
|
33
|
+
total = record.inject(0) do |memo, (key, value)|
|
|
34
|
+
memo + value
|
|
35
|
+
end
|
|
36
|
+
"#{total} AR Objects"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def content_for_request(number)
|
|
40
|
+
records = retrieve(number).first.to_a.sort_by { |key, value| value }.reverse
|
|
41
|
+
render_template "panels/active_record", :records => records
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|