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,45 @@
|
|
|
1
|
+
module Rack::Insight
|
|
2
|
+
module FilteredBacktrace
|
|
3
|
+
|
|
4
|
+
def backtrace
|
|
5
|
+
@backtrace
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def has_backtrace?
|
|
9
|
+
filtered_backtrace.any?
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def filtered_backtrace
|
|
13
|
+
@filtered_backtrace ||= @backtrace.grep(FilteredBacktrace.backtrace_regexp)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.backtrace_regexp
|
|
17
|
+
@backtrace_regexp ||=
|
|
18
|
+
begin
|
|
19
|
+
if true or (app_root = root_for_backtrace_filtering).nil?
|
|
20
|
+
/.*/
|
|
21
|
+
else
|
|
22
|
+
excludes = %w{vendor}
|
|
23
|
+
%r{^#{app_root}(?:#{::File::Separator}(?!#{excludes.join("|")}).+)$}
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.root_for_backtrace_filtering(sub_path = nil)
|
|
29
|
+
if defined?(Rails) && Rails.respond_to?(:root)
|
|
30
|
+
sub_path ? Rails.root.join(sub_path) : Rails.root
|
|
31
|
+
else
|
|
32
|
+
root = if defined?(RAILS_ROOT)
|
|
33
|
+
RAILS_ROOT
|
|
34
|
+
elsif defined?(ROOT)
|
|
35
|
+
ROOT
|
|
36
|
+
elsif defined?(Sinatra::Application)
|
|
37
|
+
Sinatra::Application.root
|
|
38
|
+
else
|
|
39
|
+
nil
|
|
40
|
+
end
|
|
41
|
+
sub_path ? ::File.join(root, sub_path) : root
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
module Rack::Insight
|
|
2
|
+
module Instrumentation; end
|
|
3
|
+
end
|
|
4
|
+
require 'rack/insight/instrumentation/instrument'
|
|
5
|
+
require 'rack/insight/instrumentation/probe'
|
|
6
|
+
require 'rack/insight/instrumentation/client'
|
|
7
|
+
require 'rack/insight/instrumentation/setup'
|
|
8
|
+
require 'rack/insight/instrumentation/package-definition'
|
|
9
|
+
require 'rack/insight/instrumentation/probe-definition'
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'rack/insight/instrumentation/package-definition'
|
|
2
|
+
module Rack::Insight::Instrumentation
|
|
3
|
+
module Client
|
|
4
|
+
def probe(collector, &block)
|
|
5
|
+
::Rack::Insight::Instrumentation::PackageDefinition::probe(collector, &block)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def request_start(env, start)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def before_detect(method_call, arguments)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def after_detect(method_call, timing, arguments, result)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def request_finish(env, status, headers, body, timing)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
require 'rack/insight/instrumentation/backstage'
|
|
2
|
+
require 'rack/insight/logger'
|
|
3
|
+
|
|
4
|
+
module Rack::Insight
|
|
5
|
+
module Instrumentation
|
|
6
|
+
class Instrument
|
|
7
|
+
MethodCall = Struct.new(:call_number, :backtrace, :file, :line, :object, :context, :kind, :method, :thread)
|
|
8
|
+
class Timing
|
|
9
|
+
def initialize(request_start, start, finish)
|
|
10
|
+
@request_start, @start, @finish = request_start, start, finish
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
attr_reader :request_start, :start, :finish
|
|
14
|
+
|
|
15
|
+
def duration
|
|
16
|
+
@duration ||= ((@finish - @start) * 1000).to_i
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def delta_t
|
|
20
|
+
@delta_t ||= ((@start - @request_start) * 1000).to_i
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
@@call_seq = 0
|
|
25
|
+
|
|
26
|
+
def self.seq_number
|
|
27
|
+
Thread.exclusive do
|
|
28
|
+
return @@call_seq += 1
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def initialize()
|
|
33
|
+
@start = Time.now
|
|
34
|
+
@collectors = nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
include Backstage
|
|
38
|
+
|
|
39
|
+
include Logging
|
|
40
|
+
|
|
41
|
+
def run(object, context="::", kind=:instance, called_at = caller[0], method = "<unknown>", args=[], &blk)
|
|
42
|
+
file, line, rest = called_at.split(':')
|
|
43
|
+
call_number = backstage{ self.class.seq_number }
|
|
44
|
+
method_call = backstage{ MethodCall.new(call_number, caller(1), file, line, object, context, kind, method, Thread::current) }
|
|
45
|
+
#$stderr.puts [method_call.context, method_call.method].inspect
|
|
46
|
+
start_time = Time.now
|
|
47
|
+
backstage do
|
|
48
|
+
start_event(method_call, args)
|
|
49
|
+
end
|
|
50
|
+
result = blk.call # execute the provided code block
|
|
51
|
+
backstage do
|
|
52
|
+
finish_event(method_call, args, start_time, result)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def collectors_for(method_call)
|
|
57
|
+
probe_chain = if method_call.kind == :instance
|
|
58
|
+
InstanceProbe.get_probe_chain(method_call.context)
|
|
59
|
+
else
|
|
60
|
+
ClassProbe.get_probe_chain(method_call.context)
|
|
61
|
+
end
|
|
62
|
+
collectors = probe_chain.inject([]) do |list, probe|
|
|
63
|
+
probe.collectors(method_call.method)
|
|
64
|
+
end
|
|
65
|
+
logger.debug do
|
|
66
|
+
"Probe chain for: #{method_call.context} #{method_call.kind} #{method_call.method}:\n #{collectors.map{|col| col.class.name}.join(", ")}"
|
|
67
|
+
end
|
|
68
|
+
collectors
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def start_event(method_call, arguments)
|
|
72
|
+
logger.debug{ "Starting event: #{method_call.context} #{method_call.kind} #{method_call.method}" }
|
|
73
|
+
|
|
74
|
+
collectors_for(method_call).each do |collector|
|
|
75
|
+
collector.before_detect(method_call, arguments)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def finish_event(method_call, arguments, start_time, result)
|
|
80
|
+
timing = Timing.new(@start, start_time, Time.now)
|
|
81
|
+
logger.debug{ "Finishing event: #{method_call.context} #{method_call.kind} #{method_call.method}" }
|
|
82
|
+
collectors_for(method_call).each do |collector|
|
|
83
|
+
collector.after_detect(method_call, timing, arguments, result)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def all_collectors
|
|
88
|
+
PackageDefinition.all_collectors
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def start(env)
|
|
92
|
+
all_collectors.each do |collector|
|
|
93
|
+
collector.request_start(env, @start)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def finish(env, status, headers, body)
|
|
98
|
+
@timing = Timing.new(@start, @start, Time.now)
|
|
99
|
+
all_collectors.each do |collector|
|
|
100
|
+
collector.request_finish(env, status, headers, body, @timing)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def duration
|
|
105
|
+
@timing.duration
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module Rack::Insight::Instrumentation
|
|
2
|
+
class PackageDefinition
|
|
3
|
+
class << self
|
|
4
|
+
def start
|
|
5
|
+
@started = begin
|
|
6
|
+
probes.each do |probe|
|
|
7
|
+
probe.fulfill_probe_orders
|
|
8
|
+
end
|
|
9
|
+
true
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def probes
|
|
14
|
+
InstanceProbe.all_probes + ClassProbe.all_probes
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def clear_collectors
|
|
18
|
+
all_collectors.clear
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def all_collectors
|
|
22
|
+
@all_collectors ||= []
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def add_collector(collector)
|
|
26
|
+
unless all_collectors.include?(collector)
|
|
27
|
+
all_collectors << collector
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def probe(collector, &block)
|
|
32
|
+
add_collector(collector)
|
|
33
|
+
definer = self.new(collector)
|
|
34
|
+
definer.instance_eval &block
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def get_class_probe(name)
|
|
39
|
+
ClassProbe.probe_for(name)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def get_instance_probe(name)
|
|
43
|
+
InstanceProbe.probe_for(name)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def initialize(collector)
|
|
47
|
+
@collector = collector
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
attr_reader :collector
|
|
51
|
+
|
|
52
|
+
def instrument(name, &block)
|
|
53
|
+
definer = ProbeDefinition.new(self, name)
|
|
54
|
+
definer.instance_eval(&block) unless block.nil?
|
|
55
|
+
return definer
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Rack::Insight::Instrumentation
|
|
2
|
+
class ProbeDefinition
|
|
3
|
+
def initialize(package, target_name)
|
|
4
|
+
@package = package
|
|
5
|
+
@target_name = target_name
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def instance_probe(*method_names)
|
|
9
|
+
if probes = @package.get_instance_probe(@target_name)
|
|
10
|
+
probes.probe(@package.collector, *method_names)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def class_probe(*method_names)
|
|
15
|
+
if probes = @package.get_class_probe(@target_name)
|
|
16
|
+
probes.probe(@package.collector, *method_names)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
module Rack::Insight
|
|
2
|
+
module Instrumentation
|
|
3
|
+
class Probe
|
|
4
|
+
module Interpose
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
@@class_list = nil
|
|
8
|
+
|
|
9
|
+
module ProbeRunner
|
|
10
|
+
include Backstage
|
|
11
|
+
include Logging
|
|
12
|
+
|
|
13
|
+
def probe_run(object, context = "::", kind=:instance, args=[], called_at=caller[1], method_name = nil)
|
|
14
|
+
if Thread.current['instrumented_backstage']
|
|
15
|
+
#warn "probe_run while backstage: #{context}, #{kind},
|
|
16
|
+
##{method_name}" unless method_name.to_sym == :add
|
|
17
|
+
return yield
|
|
18
|
+
end
|
|
19
|
+
instrument = Thread.current['rack-insight.instrument']
|
|
20
|
+
result = nil
|
|
21
|
+
if instrument.nil?
|
|
22
|
+
backstage do
|
|
23
|
+
result = yield
|
|
24
|
+
end
|
|
25
|
+
else
|
|
26
|
+
instrument.run(object, context, kind, called_at, method_name, args){ result = yield }
|
|
27
|
+
end
|
|
28
|
+
result
|
|
29
|
+
end
|
|
30
|
+
extend self
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class << self
|
|
34
|
+
include Logging
|
|
35
|
+
|
|
36
|
+
def class_list
|
|
37
|
+
@@class_list ||= begin
|
|
38
|
+
classes = []
|
|
39
|
+
ObjectSpace.each_object(Class) do |klass|
|
|
40
|
+
classes << klass
|
|
41
|
+
end
|
|
42
|
+
classes
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def get_probe_chain(name)
|
|
47
|
+
const = const_from_name(name)
|
|
48
|
+
chain = []
|
|
49
|
+
const.ancestors.each do |mod|
|
|
50
|
+
if probes.has_key?(mod.name)
|
|
51
|
+
chain << probes[mod.name]
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
chain
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def const_from_name(name)
|
|
58
|
+
parts = name.split("::")
|
|
59
|
+
const = parts.inject(Kernel) do |namespace, part|
|
|
60
|
+
namespace.const_get(part)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def probes
|
|
65
|
+
@probes ||= Hash.new do |h,k|
|
|
66
|
+
begin
|
|
67
|
+
h[k] = self.new(const_from_name(k))
|
|
68
|
+
rescue NameError
|
|
69
|
+
logger.warn{ "Cannot find constant: #{k}" }
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def all_probes
|
|
75
|
+
probes.values
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def probe_for(const)
|
|
79
|
+
probes[const]
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def initialize(const)
|
|
84
|
+
@const = const
|
|
85
|
+
@probed = {}
|
|
86
|
+
@collectors = Hash.new{|h,k| h[k] = []}
|
|
87
|
+
@probe_orders = []
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def collectors(key)
|
|
91
|
+
@collectors[key.to_sym]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def all_collectors
|
|
95
|
+
@collectors.values
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def clear_collectors
|
|
99
|
+
@collectors.clear
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def probe(collector, *methods)
|
|
103
|
+
methods.each do |name|
|
|
104
|
+
unless @collectors[name.to_sym].include?(collector)
|
|
105
|
+
@collectors[name.to_sym] << collector
|
|
106
|
+
end
|
|
107
|
+
@probe_orders << name
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def descendants
|
|
112
|
+
@descendants ||= self.class.class_list.find_all do |klass|
|
|
113
|
+
klass.ancestors.include?(@const)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def local_method_defs(klass)
|
|
118
|
+
klass.instance_methods(false)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def descendants_that_define(method_name)
|
|
122
|
+
log{{ :descendants => descendants }}
|
|
123
|
+
descendants.find_all do |klass|
|
|
124
|
+
(@const != klass and local_method_defs(klass).include?(method_name))
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
include Logging
|
|
129
|
+
def log &block
|
|
130
|
+
logger.debug &block
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def fulfill_probe_orders
|
|
134
|
+
log{{:probes_for => @const.name, :type => self.class}}
|
|
135
|
+
@probe_orders.each do |method_name|
|
|
136
|
+
log{{ :method => method_name }}
|
|
137
|
+
build_tracing_wrappers(@const, method_name)
|
|
138
|
+
descendants_that_define(method_name).each do |klass|
|
|
139
|
+
log{{ :subclass => klass.name }}
|
|
140
|
+
build_tracing_wrappers(klass, method_name)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
@probe_orders.clear
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def get_method(klass, method_name)
|
|
147
|
+
klass.instance_method(method_name)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def define_trace_method(target, method)
|
|
151
|
+
target.class_exec() do
|
|
152
|
+
define_method(method.name) do |*args, &block|
|
|
153
|
+
ProbeRunner::probe_run(self, method.owner.name, :instance, args, caller(0)[0], method.name) do
|
|
154
|
+
method.bind(self).call(*args, &block)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def build_tracing_wrappers(target, method_name)
|
|
161
|
+
return if @probed.has_key?([target,method_name])
|
|
162
|
+
@probed[[target,method_name]] = true
|
|
163
|
+
|
|
164
|
+
meth = get_method(target, method_name)
|
|
165
|
+
|
|
166
|
+
log{ {:tracing => meth } }
|
|
167
|
+
define_trace_method(target, meth)
|
|
168
|
+
rescue NameError => ne
|
|
169
|
+
log{ {:not_tracing => NameError } }
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
class ClassProbe < Probe
|
|
174
|
+
def local_method_defs(klass)
|
|
175
|
+
klass.singleton_methods(false)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def get_method(klass, method_name)
|
|
179
|
+
(class << klass; self; end).instance_method(method_name)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def define_trace_method(target, method)
|
|
183
|
+
(class << target; self; end).class_exec() do
|
|
184
|
+
define_method(method.name) do |*args, &block|
|
|
185
|
+
ProbeRunner::probe_run(self, target.name, :class, args, caller(0)[0], method.name) do
|
|
186
|
+
method.bind(self).call(*args, &block)
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
class InstanceProbe < Probe
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|