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.
- data/History.txt +45 -0
- data/MIT-LICENSE.txt +19 -0
- data/README.md +123 -0
- data/Rakefile +24 -0
- data/Thorfile +113 -0
- data/lib/insight.rb +17 -0
- data/lib/insight/app.rb +189 -0
- data/lib/insight/database.rb +186 -0
- data/lib/insight/enable-button.rb +43 -0
- data/lib/insight/filtered_backtrace.rb +45 -0
- data/lib/insight/instrumentation.rb +9 -0
- data/lib/insight/instrumentation/backstage.rb +10 -0
- data/lib/insight/instrumentation/client.rb +20 -0
- data/lib/insight/instrumentation/instrument.rb +109 -0
- data/lib/insight/instrumentation/package-definition.rb +58 -0
- data/lib/insight/instrumentation/probe-definition.rb +20 -0
- data/lib/insight/instrumentation/probe.rb +199 -0
- data/lib/insight/instrumentation/setup.rb +32 -0
- data/lib/insight/logger.rb +55 -0
- data/lib/insight/options.rb +102 -0
- data/lib/insight/panel.rb +119 -0
- data/lib/insight/panel_app.rb +31 -0
- data/lib/insight/panels-content.rb +22 -0
- data/lib/insight/panels-header.rb +18 -0
- data/lib/insight/panels/active_record_panel.rb +46 -0
- data/lib/insight/panels/cache_panel.rb +69 -0
- data/lib/insight/panels/cache_panel/panel_app.rb +46 -0
- data/lib/insight/panels/cache_panel/stats.rb +98 -0
- data/lib/insight/panels/log_panel.rb +54 -0
- data/lib/insight/panels/memory_panel.rb +32 -0
- data/lib/insight/panels/rails_info_panel.rb +19 -0
- data/lib/insight/panels/redis_panel.rb +42 -0
- data/lib/insight/panels/redis_panel/redis_extension.rb +23 -0
- data/lib/insight/panels/redis_panel/stats.rb +50 -0
- data/lib/insight/panels/request_variables_panel.rb +70 -0
- data/lib/insight/panels/speedtracer_panel.rb +89 -0
- data/lib/insight/panels/speedtracer_panel/trace-app.rb +52 -0
- data/lib/insight/panels/speedtracer_panel/tracer.rb +212 -0
- data/lib/insight/panels/sql_panel.rb +53 -0
- data/lib/insight/panels/sql_panel/panel_app.rb +37 -0
- data/lib/insight/panels/sql_panel/query.rb +94 -0
- data/lib/insight/panels/templates_panel.rb +58 -0
- data/lib/insight/panels/templates_panel/rendering.rb +81 -0
- data/lib/insight/panels/timer_panel.rb +40 -0
- data/lib/insight/params_signature.rb +61 -0
- data/lib/insight/public/__insight__/bookmarklet.html +10 -0
- data/lib/insight/public/__insight__/bookmarklet.js +223 -0
- data/lib/insight/public/__insight__/insight.css +235 -0
- data/lib/insight/public/__insight__/insight.js +123 -0
- data/lib/insight/public/__insight__/jquery-1.3.2.js +4376 -0
- data/lib/insight/public/__insight__/jquery.tablesorter.min.js +1 -0
- data/lib/insight/public/__insight__/spinner.gif +0 -0
- data/lib/insight/rack_static_bug_avoider.rb +16 -0
- data/lib/insight/redirect_interceptor.rb +25 -0
- data/lib/insight/render.rb +72 -0
- data/lib/insight/request-recorder.rb +23 -0
- data/lib/insight/toolbar.rb +63 -0
- data/lib/insight/views/enable-button.html.erb +1 -0
- data/lib/insight/views/error.html.erb +17 -0
- data/lib/insight/views/headers_fragment.html.erb +20 -0
- data/lib/insight/views/panels/active_record.html.erb +17 -0
- data/lib/insight/views/panels/cache.html.erb +93 -0
- data/lib/insight/views/panels/execute_sql.html.erb +32 -0
- data/lib/insight/views/panels/explain_sql.html.erb +32 -0
- data/lib/insight/views/panels/log.html.erb +21 -0
- data/lib/insight/views/panels/profile_sql.html.erb +32 -0
- data/lib/insight/views/panels/rails_info.html.erb +19 -0
- data/lib/insight/views/panels/redis.html.erb +46 -0
- data/lib/insight/views/panels/request_variables.html.erb +25 -0
- data/lib/insight/views/panels/speedtracer/serverevent.html.erb +10 -0
- data/lib/insight/views/panels/speedtracer/servertrace.html.erb +12 -0
- data/lib/insight/views/panels/speedtracer/traces.html.erb +18 -0
- data/lib/insight/views/panels/sql.html.erb +43 -0
- data/lib/insight/views/panels/templates.html.erb +6 -0
- data/lib/insight/views/panels/timer.html.erb +19 -0
- data/lib/insight/views/panels/view_cache.html.erb +19 -0
- data/lib/insight/views/redirect.html.erb +16 -0
- data/lib/insight/views/request_fragment.html.erb +25 -0
- data/lib/insight/views/toolbar.html.erb +29 -0
- data/lib/logical-insight.rb +1 -0
- data/spec/custom_matchers.rb +31 -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/insight/panels/active_record_panel_spec.rb +42 -0
- data/spec/insight/panels/cache_panel_spec.rb +176 -0
- data/spec/insight/panels/log_panel_spec.rb +44 -0
- data/spec/insight/panels/memory_panel_spec.rb +19 -0
- data/spec/insight/panels/mongo_panel_spec_pending.rb +50 -0
- data/spec/insight/panels/rails_info_panel_spec.rb +27 -0
- data/spec/insight/panels/redis_panel_spec.rb +66 -0
- data/spec/insight/panels/sql_panel_spec.rb +145 -0
- data/spec/insight/panels/templates_panel_spec.rb +84 -0
- data/spec/insight/panels/timer_panel_spec.rb +36 -0
- data/spec/insight_spec.rb +141 -0
- data/spec/instrumentation_spec.rb +188 -0
- data/spec/rcov.opts +1 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +93 -0
- metadata +187 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
require 'insight'
|
|
2
|
+
require 'sqlite3'
|
|
3
|
+
require 'base64'
|
|
4
|
+
|
|
5
|
+
module Insight
|
|
6
|
+
class Database
|
|
7
|
+
module RequestDataClient
|
|
8
|
+
def key_sql_template(sql)
|
|
9
|
+
@key_sql_template = sql
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def table_setup(name, *keys)
|
|
13
|
+
@table = DataTable.new(name, *keys)
|
|
14
|
+
if keys.empty?
|
|
15
|
+
@key_sql_template = ""
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def store(env, *keys_and_value)
|
|
20
|
+
return if env.nil?
|
|
21
|
+
request_id = env["insight.request-id"]
|
|
22
|
+
return if request_id.nil?
|
|
23
|
+
|
|
24
|
+
value = keys_and_value[-1]
|
|
25
|
+
keys = keys_and_value[0...-1]
|
|
26
|
+
|
|
27
|
+
@table.store(request_id, value, @key_sql_template % keys)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def retrieve(request_id)
|
|
31
|
+
@table.for_request(request_id)
|
|
32
|
+
end
|
|
33
|
+
alias retreive retrieve #JDL cannot spell
|
|
34
|
+
|
|
35
|
+
def table_length
|
|
36
|
+
@table.length
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class << self
|
|
41
|
+
include Logging
|
|
42
|
+
def db
|
|
43
|
+
@db ||= open_database
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def reset
|
|
47
|
+
@db = nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def open_database
|
|
51
|
+
@db = SQLite3::Database.new("insight.sqlite")
|
|
52
|
+
@db.execute("pragma foreign_keys = on")
|
|
53
|
+
@db
|
|
54
|
+
rescue Object => ex
|
|
55
|
+
msg = "Issue while loading SQLite DB:" + [ex.class, ex.message, ex.backtrace[0..4]].inspect
|
|
56
|
+
logger.debug{ msg }
|
|
57
|
+
|
|
58
|
+
return {}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
if defined?(PhusionPassenger)
|
|
62
|
+
PhusionPassenger.on_event(:starting_worker_process) do |forked|
|
|
63
|
+
open_database if forked
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
class Table
|
|
69
|
+
include Logging
|
|
70
|
+
|
|
71
|
+
def db
|
|
72
|
+
Insight::Database.db
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def create_keys_clause
|
|
76
|
+
"#{@keys.map{|key| "#{key} varchar"}.join(", ")}"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def create_sql
|
|
80
|
+
"create table #@table_name ( id integer primary key, #{create_keys_clause} )"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def execute(*args)
|
|
84
|
+
logger.debug{ ins_args = args.inspect; "(#{[ins_args.length,120].min}/#{ins_args.length})" + ins_args[0..120] }
|
|
85
|
+
db.execute(*args)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def initialize(table_name, *keys)
|
|
89
|
+
@table_name = table_name
|
|
90
|
+
@keys = keys
|
|
91
|
+
if(execute("select * from sqlite_master where name = ?", table_name).empty?)
|
|
92
|
+
execute(create_sql)
|
|
93
|
+
|
|
94
|
+
logger.debug{ "Initializing a table called #{table_name}" }
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def select(which_sql, condition_sql)
|
|
99
|
+
execute("select #{which_sql} from #@table_name where #{condition_sql}")
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def fields_sql
|
|
103
|
+
"#{@keys.join(",")}"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def insert(values_sql)
|
|
107
|
+
execute("insert into #@table_name(#{fields_sql}) values (#{values_sql})")
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def keys(name)
|
|
111
|
+
execute("select #{name} from #@table_name").flatten
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def length(where = "1 = 1")
|
|
115
|
+
execute("select count(1) from #@table_name where #{where}").first.first
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def to_a
|
|
119
|
+
execute("select * from #@table_name")
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
class RequestTable < Table
|
|
124
|
+
def initialize()
|
|
125
|
+
super("requests", "method", "url", "date")
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def store(method, url)
|
|
129
|
+
result = insert("'#{method}', '#{url}', #{Time.now.to_i}")
|
|
130
|
+
db.last_insert_row_id
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def last_request_id
|
|
134
|
+
execute("select max(id) from #@table_name").first.first
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def sweep
|
|
138
|
+
execute("delete from #@table_name where date < #{Time.now.to_i - (60 * 60 * 12)}")
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
require 'yaml'
|
|
143
|
+
class DataTable < Table
|
|
144
|
+
def initialize(name, *keys)
|
|
145
|
+
super(name, *(%w{request_id} + keys + %w{value}))
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def create_keys_clause
|
|
149
|
+
non_request_keys = @keys - %w"request_id"
|
|
150
|
+
sql = non_request_keys.map{|key| "#{key} varchar"}.join(", ")
|
|
151
|
+
sql += ", request_id references requests(id) on delete cascade"
|
|
152
|
+
sql
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def store(request_id, value, keys_sql = "")
|
|
156
|
+
sql = "'#{encode_value(value)}'"
|
|
157
|
+
sql = keys_sql + ", " + sql unless keys_sql.empty?
|
|
158
|
+
sql = "#{request_id}, #{sql}"
|
|
159
|
+
insert(sql)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def encode_value(value)
|
|
163
|
+
Base64.encode64(YAML.dump(value))
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def decode_value(value)
|
|
167
|
+
YAML.load(Base64.decode64(value))
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def retrieve(key_sql)
|
|
171
|
+
select("value", key_sql).map{|value| decode_value(value.first)}
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def for_request(id)
|
|
175
|
+
retrieve("request_id = #{id}")
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def to_a
|
|
179
|
+
super.map do |row|
|
|
180
|
+
row[-1] = decode_value(row[-1])
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Insight
|
|
2
|
+
class EnableButton
|
|
3
|
+
include Render
|
|
4
|
+
|
|
5
|
+
MIME_TYPES = ["text/html", "application/xhtml+xml"]
|
|
6
|
+
|
|
7
|
+
def initialize(app, insight)
|
|
8
|
+
@app = app
|
|
9
|
+
@insight = insight
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def call(env)
|
|
13
|
+
@env = env
|
|
14
|
+
status, headers, body = @app.call(@env)
|
|
15
|
+
|
|
16
|
+
response = Rack::Response.new(body, status, headers)
|
|
17
|
+
|
|
18
|
+
inject_button(response) if okay_to_modify?(env, response)
|
|
19
|
+
|
|
20
|
+
return response.to_a
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def okay_to_modify?(env, response)
|
|
24
|
+
req = Rack::Request.new(env)
|
|
25
|
+
content_type, charset = response.content_type.split(";")
|
|
26
|
+
|
|
27
|
+
response.ok? && MIME_TYPES.include?(content_type) && !req.xhr?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def inject_button(response)
|
|
31
|
+
full_body = response.body.join
|
|
32
|
+
full_body.sub! /<\/body>/, render + "</body>"
|
|
33
|
+
|
|
34
|
+
response["Content-Length"] = full_body.size.to_s
|
|
35
|
+
|
|
36
|
+
response.body = [full_body]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def render
|
|
40
|
+
render_template("enable-button")
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module 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 Insight
|
|
2
|
+
module Instrumentation; end
|
|
3
|
+
end
|
|
4
|
+
require 'insight/instrumentation/instrument'
|
|
5
|
+
require 'insight/instrumentation/probe'
|
|
6
|
+
require 'insight/instrumentation/client'
|
|
7
|
+
require 'insight/instrumentation/setup'
|
|
8
|
+
require 'insight/instrumentation/package-definition'
|
|
9
|
+
require 'insight/instrumentation/probe-definition'
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'insight/instrumentation/package-definition'
|
|
2
|
+
module Insight::Instrumentation
|
|
3
|
+
module Client
|
|
4
|
+
def probe(collector, &block)
|
|
5
|
+
::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 'insight/instrumentation/backstage'
|
|
2
|
+
require 'insight/logger'
|
|
3
|
+
|
|
4
|
+
module 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 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
|