scout_apm 1.1.0.pre1 → 1.2.0.pre1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.markdown +6 -0
- data/lib/scout_apm/agent/reporting.rb +67 -77
- data/lib/scout_apm/agent.rb +56 -9
- data/lib/scout_apm/background_job_integrations/delayed_job.rb +19 -0
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +60 -0
- data/lib/scout_apm/bucket_name_splitter.rb +2 -2
- data/lib/scout_apm/capacity.rb +2 -1
- data/lib/scout_apm/context.rb +1 -5
- data/lib/scout_apm/environment.rb +16 -1
- data/lib/scout_apm/instruments/action_controller_rails_2.rb +13 -3
- data/lib/scout_apm/instruments/action_controller_rails_3.rb +20 -20
- data/lib/scout_apm/instruments/active_record.rb +5 -8
- data/lib/scout_apm/instruments/delayed_job.rb +56 -0
- data/lib/scout_apm/instruments/middleware.rb +44 -0
- data/lib/scout_apm/instruments/mongoid.rb +1 -1
- data/lib/scout_apm/instruments/moped.rb +2 -2
- data/lib/scout_apm/instruments/net_http.rb +1 -2
- data/lib/scout_apm/instruments/process/process_cpu.rb +5 -1
- data/lib/scout_apm/instruments/process/process_memory.rb +5 -1
- data/lib/scout_apm/instruments/sinatra.rb +14 -2
- data/lib/scout_apm/layaway.rb +33 -79
- data/lib/scout_apm/layaway_file.rb +2 -1
- data/lib/scout_apm/layer.rb +115 -0
- data/lib/scout_apm/layer_converter.rb +196 -0
- data/lib/scout_apm/metric_meta.rb +24 -4
- data/lib/scout_apm/metric_stats.rb +14 -4
- data/lib/scout_apm/request_manager.rb +26 -0
- data/lib/scout_apm/request_queue_time.rb +54 -0
- data/lib/scout_apm/serializers/payload_serializer.rb +8 -1
- data/lib/scout_apm/serializers/payload_serializer_to_json.rb +1 -0
- data/lib/scout_apm/slow_transaction.rb +3 -0
- data/lib/scout_apm/store.rb +122 -190
- data/lib/scout_apm/tracer.rb +54 -83
- data/lib/scout_apm/tracked_request.rb +168 -0
- data/lib/scout_apm/version.rb +1 -1
- data/lib/scout_apm.rb +18 -5
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 908063c42f604e0073f59f50d2fab04966553a20
|
4
|
+
data.tar.gz: 0bc50d1533419d27d62ca3692472d08e764536f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f72beb94361832f4cd64faf3e618a83bef3989232ee68deb16472508ec82ef58b2cfea0973f95225d57b68c995a0724ded878acfa424c0c30b90f4b2d3cb63c0
|
7
|
+
data.tar.gz: 4dca8b6565dac5f29abe8deafa353da9512a5508981098e096b7cafb47585391cd77f8cb58a1f5c8a7e04250ff339e82d9c34d726af91d195b17bd2b11325ea0
|
data/CHANGELOG.markdown
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# 1.2.0
|
2
|
+
|
3
|
+
* Middleware tracing - Track time in the Rack middleware that Rails sets up
|
4
|
+
* Queue Time tracking - Track how much time is spent in the load balancer
|
5
|
+
* Major refactor of internals to allow more flexibility for future features
|
6
|
+
|
1
7
|
# 1.0.0
|
2
8
|
|
3
9
|
* General Availability
|
@@ -6,76 +6,80 @@ module ScoutApm
|
|
6
6
|
@reporter ||= ScoutApm::Reporter.new(:checkin, config, logger)
|
7
7
|
end
|
8
8
|
|
9
|
-
#
|
10
|
-
#
|
9
|
+
# The data moves through a treadmill of reporting, coordinating several Rails processes by using an external file.
|
10
|
+
# * During the minute it is being recorded by the instruments, it gets
|
11
|
+
# recorded into the ram of each process (in the Store class).
|
12
|
+
# * The minute after, each process writes its own metrics to a shared LayawayFile
|
13
|
+
# * The minute after that, the first process to wake up pushes the combined
|
14
|
+
# data to the server, and wipes it. Next processes don't have anything to do.
|
15
|
+
#
|
16
|
+
# At any given point, there is data in each of those steps, moving its way through the process
|
11
17
|
def process_metrics
|
12
|
-
|
13
|
-
|
14
|
-
capacity.process
|
15
|
-
payload = layaway.deposit_and_deliver
|
18
|
+
# First we write the previous minute's data to the shared-across-process layaway file.
|
19
|
+
store.write_to_layaway(layaway)
|
16
20
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
logger.warn "Metric Size is at Limit, truncating" if metrics.size == ScoutApm::Store::MAX_SIZE
|
24
|
-
|
25
|
-
# for debugging, count the total number of requests
|
26
|
-
total_request_count = 0
|
27
|
-
|
28
|
-
metrics.each do |meta,stats|
|
29
|
-
if meta.metric_name =~ /\AController/
|
30
|
-
total_request_count += stats.call_count
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
metadata = {
|
35
|
-
:app_root => ScoutApm::Environment.instance.root.to_s,
|
36
|
-
:unique_id => ScoutApm::Utils::UniqueId.simple,
|
37
|
-
:agent_version => ScoutApm::VERSION,
|
38
|
-
}
|
39
|
-
|
40
|
-
logger.debug("Metrics: #{metrics}")
|
41
|
-
logger.debug("SlowTrans: #{slow_transactions}")
|
42
|
-
logger.debug("Metadata: #{metadata.inspect}")
|
43
|
-
|
44
|
-
|
45
|
-
payload = ScoutApm::Serializers::PayloadSerializer.serialize(metadata, metrics, slow_transactions)
|
46
|
-
slow_transactions_kb = Marshal.dump(slow_transactions).size/1024 # just for performance debugging
|
47
|
-
|
48
|
-
logger.info "Delivering #{metrics.length} Metrics for #{total_request_count} requests and #{slow_transactions.length} Slow Transaction Traces"
|
21
|
+
# Then attempt to send 2 minutes ago's data up to the server. This
|
22
|
+
# only acctually occurs if this process is the first to wake up this
|
23
|
+
# minute.
|
24
|
+
report_to_server
|
25
|
+
end
|
49
26
|
|
50
|
-
|
27
|
+
# In a running app, one process will get one period ready for delivery, the others will see 0.
|
28
|
+
def report_to_server
|
29
|
+
reporting_periods = layaway.periods_ready_for_delivery
|
30
|
+
reporting_periods.each do |rp|
|
31
|
+
deliver_period(rp)
|
32
|
+
end
|
33
|
+
end
|
51
34
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
35
|
+
def deliver_period(reporting_period)
|
36
|
+
metrics = reporting_period.metrics_payload
|
37
|
+
slow_transactions = reporting_period.slow_transactions_payload
|
38
|
+
metadata = {
|
39
|
+
:app_root => ScoutApm::Environment.instance.root.to_s,
|
40
|
+
:unique_id => ScoutApm::Utils::UniqueId.simple,
|
41
|
+
:agent_version => ScoutApm::VERSION,
|
42
|
+
:agent_time => reporting_period.timestamp.to_s,
|
43
|
+
}
|
44
|
+
|
45
|
+
log_deliver(metrics, slow_transactions, metadata)
|
46
|
+
|
47
|
+
payload = ScoutApm::Serializers::PayloadSerializer.serialize(metadata, metrics, slow_transactions)
|
48
|
+
response = reporter.report(payload, headers)
|
49
|
+
unless response && response.is_a?(Net::HTTPSuccess)
|
50
|
+
logger.warn "Error on checkin to #{reporter.uri.to_s}: #{response.inspect}"
|
51
|
+
end
|
52
|
+
rescue => e
|
53
|
+
logger.warn "Error on checkin to #{reporter.uri.to_s}"
|
54
|
+
logger.info e.message
|
55
|
+
logger.debug e.backtrace
|
56
|
+
end
|
57
57
|
|
58
|
-
|
58
|
+
def log_deliver(metrics, slow_transactions, metadata)
|
59
|
+
total_request_count = metrics.
|
60
|
+
select { |meta,stats| meta.metric_name =~ /\AController/ }.
|
61
|
+
inject(0) {|sum, (_, stat)| sum + stat.call_count }
|
59
62
|
|
60
|
-
|
61
|
-
|
63
|
+
logger.info "Delivering #{metrics.length} Metrics for #{total_request_count} requests and #{slow_transactions.length} Slow Transaction Traces"
|
64
|
+
logger.debug("Metrics: #{metrics.pretty_inspect}\nSlowTrans: #{slow_transactions.pretty_inspect}\nMetadata: #{metadata.inspect.pretty_inspect}")
|
65
|
+
end
|
62
66
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
elsif response
|
70
|
-
logger.warn "Error on checkin to #{reporter.uri.to_s}: #{response.inspect}"
|
71
|
-
end
|
67
|
+
# TODO: Move this into PayloadSerializer?
|
68
|
+
def headers
|
69
|
+
if ScoutApm::Agent.instance.config.value("report_format") == 'json'
|
70
|
+
headers = {'Content-Type' => 'application/json'}
|
71
|
+
else
|
72
|
+
headers = {}
|
72
73
|
end
|
73
|
-
rescue
|
74
|
-
logger.warn "Error on checkin to #{reporter.uri.to_s}"
|
75
|
-
logger.info $!.message
|
76
|
-
logger.debug $!.backtrace
|
77
74
|
end
|
78
75
|
|
76
|
+
# def process_metrics
|
77
|
+
# rescue
|
78
|
+
# logger.warn "Error on checkin to #{reporter.uri.to_s}"
|
79
|
+
# logger.info $!.message
|
80
|
+
# logger.debug $!.backtrace
|
81
|
+
# end
|
82
|
+
|
79
83
|
# Before reporting, lookup metric_id for each MetricMeta. This speeds up
|
80
84
|
# reporting on the server-side.
|
81
85
|
def add_metric_ids(metrics)
|
@@ -85,21 +89,7 @@ module ScoutApm
|
|
85
89
|
end
|
86
90
|
end
|
87
91
|
end
|
88
|
-
|
89
|
-
# Called from #process_metrics, which is run via the background worker.
|
90
|
-
def run_samplers
|
91
|
-
@samplers.each do |sampler|
|
92
|
-
begin
|
93
|
-
result = sampler.run
|
94
|
-
store.track!(sampler.metric_name, result, {:scope => nil}) if result
|
95
|
-
rescue => e
|
96
|
-
logger.info "Error reading #{sampler.human_name}"
|
97
|
-
logger.debug e.message
|
98
|
-
logger.debug e.backtrace.join("\n")
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end # module Reporting
|
92
|
+
end
|
103
93
|
include Reporting
|
104
|
-
end
|
105
|
-
end
|
94
|
+
end
|
95
|
+
end
|
data/lib/scout_apm/agent.rb
CHANGED
@@ -58,8 +58,8 @@ module ScoutApm
|
|
58
58
|
return false
|
59
59
|
end
|
60
60
|
|
61
|
-
if
|
62
|
-
logger.warn "Couldn't find a supported app server. Not starting agent."
|
61
|
+
if app_server_missing?(options) && background_job_missing?
|
62
|
+
logger.warn "Couldn't find a supported app server or background job framework. Not starting agent."
|
63
63
|
return false
|
64
64
|
end
|
65
65
|
|
@@ -90,9 +90,15 @@ module ScoutApm
|
|
90
90
|
|
91
91
|
return false unless preconditions_met?(options)
|
92
92
|
|
93
|
+
|
93
94
|
@started = true
|
94
95
|
|
95
|
-
logger.info "Starting monitoring for [#{environment.application_name}]. Framework [#{environment.framework}] App Server [#{environment.app_server}]."
|
96
|
+
logger.info "Starting monitoring for [#{environment.application_name}]. Framework [#{environment.framework}] App Server [#{environment.app_server}] Background Job Framework [#{environment.background_job_name}]."
|
97
|
+
|
98
|
+
# We need agent initialized to do this, so do it here instead.
|
99
|
+
# Clean up any old data in the layaway file, allows us to change the file
|
100
|
+
# structure / contents without worrying.
|
101
|
+
layaway.verify_layaway_file_contents
|
96
102
|
|
97
103
|
load_instruments if should_load_instruments?(options)
|
98
104
|
|
@@ -110,6 +116,9 @@ module ScoutApm
|
|
110
116
|
start_background_worker
|
111
117
|
handle_exit
|
112
118
|
logger.info "Scout Agent [#{ScoutApm::VERSION}] Initialized"
|
119
|
+
elsif environment.background_job_integration
|
120
|
+
environment.background_job_integration.install
|
121
|
+
logger.info "Scout Agent [#{ScoutApm::VERSION}] loaded in [#{environment.background_job_name}] master process. Monitoring will start after background job framework forks its workers."
|
113
122
|
else
|
114
123
|
environment.app_server_integration.install
|
115
124
|
logger.info "Scout Agent [#{ScoutApm::VERSION}] loaded in [#{environment.app_server}] master process. Monitoring will start after server forks its workers."
|
@@ -173,22 +182,38 @@ module ScoutApm
|
|
173
182
|
logger.info "Initializing worker thread."
|
174
183
|
@background_worker = ScoutApm::BackgroundWorker.new
|
175
184
|
@background_worker_thread = Thread.new do
|
176
|
-
@background_worker.start {
|
185
|
+
@background_worker.start {
|
186
|
+
# First, run periodic samplers. These should run once a minute,
|
187
|
+
# rather than per-request. "CPU Load" and similar.
|
188
|
+
run_samplers
|
189
|
+
capacity.process
|
190
|
+
|
191
|
+
ScoutApm::Agent.instance.process_metrics
|
192
|
+
}
|
177
193
|
end
|
178
194
|
end
|
179
195
|
|
180
196
|
# If we want to skip the app_server_check, then we must load it.
|
181
197
|
def should_load_instruments?(options={})
|
182
198
|
return true if options[:skip_app_server_check]
|
183
|
-
environment.app_server_integration.found?
|
199
|
+
environment.app_server_integration.found? || !background_job_missing?
|
184
200
|
end
|
185
201
|
|
186
202
|
# Loads the instrumention logic.
|
187
203
|
def load_instruments
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
204
|
+
if !background_job_missing?
|
205
|
+
case environment.background_job_name
|
206
|
+
when :delayed_job
|
207
|
+
install_instrument(ScoutApm::Instruments::DelayedJob)
|
208
|
+
end
|
209
|
+
else
|
210
|
+
case environment.framework
|
211
|
+
when :rails then install_instrument(ScoutApm::Instruments::ActionControllerRails2)
|
212
|
+
when :rails3_or_4 then
|
213
|
+
install_instrument(ScoutApm::Instruments::ActionControllerRails3)
|
214
|
+
install_instrument(ScoutApm::Instruments::Middleware)
|
215
|
+
when :sinatra then install_instrument(ScoutApm::Instruments::Sinatra)
|
216
|
+
end
|
192
217
|
end
|
193
218
|
|
194
219
|
install_instrument(ScoutApm::Instruments::ActiveRecord)
|
@@ -216,5 +241,27 @@ module ScoutApm
|
|
216
241
|
def deploy_integration
|
217
242
|
environment.deploy_integration
|
218
243
|
end
|
244
|
+
|
245
|
+
# TODO: Extract a proper class / registery for these. They don't really belong here
|
246
|
+
def run_samplers
|
247
|
+
@samplers.each do |sampler|
|
248
|
+
begin
|
249
|
+
result = sampler.run
|
250
|
+
store.track_one!(sampler.metric_type, sampler.metric_name, result) if result
|
251
|
+
rescue => e
|
252
|
+
logger.info "Error reading #{sampler.human_name}"
|
253
|
+
logger.debug e.message
|
254
|
+
logger.debug e.backtrace.join("\n")
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
def app_server_missing?(options)
|
260
|
+
!environment.app_server_integration(true).found? && !options[:skip_app_server_check]
|
261
|
+
end
|
262
|
+
|
263
|
+
def background_job_missing?
|
264
|
+
environment.background_job_integration.nil?
|
265
|
+
end
|
219
266
|
end
|
220
267
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module BackgroundJobIntegrations
|
3
|
+
class DelayedJob
|
4
|
+
attr_reader :logger
|
5
|
+
|
6
|
+
def name
|
7
|
+
:delayed_job
|
8
|
+
end
|
9
|
+
|
10
|
+
def present?
|
11
|
+
defined?(::Delayed::Job) && (File.basename($0) =~ /\Adelayed_job/)
|
12
|
+
end
|
13
|
+
|
14
|
+
def forking?
|
15
|
+
false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module BackgroundJobIntegrations
|
3
|
+
class Sidekiq
|
4
|
+
attr_reader :logger
|
5
|
+
|
6
|
+
def name
|
7
|
+
:sidekiq
|
8
|
+
end
|
9
|
+
|
10
|
+
def present?
|
11
|
+
defined?(::Sidekiq) && (File.basename($0) =~ /\Asidekiq/)
|
12
|
+
end
|
13
|
+
|
14
|
+
def forking?
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
def install
|
19
|
+
# ScoutApm::Tracer is not available when this class is defined
|
20
|
+
SidekiqMiddleware.class_eval do
|
21
|
+
include ScoutApm::Tracer
|
22
|
+
end
|
23
|
+
::Sidekiq.configure_server do |config|
|
24
|
+
config.server_middleware do |chain|
|
25
|
+
chain.add SidekiqMiddleware
|
26
|
+
end
|
27
|
+
end
|
28
|
+
require 'sidekiq/processor' # sidekiq v4 has not loaded this file by this point
|
29
|
+
::Sidekiq::Processor.class_eval do
|
30
|
+
old = instance_method(:initialize)
|
31
|
+
define_method(:initialize) do |boss|
|
32
|
+
ScoutApm::Agent.instance.start_background_worker
|
33
|
+
old.bind(self).call(boss)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class SidekiqMiddleware
|
40
|
+
def call(worker, msg, queue)
|
41
|
+
msg_args = msg["args"].first
|
42
|
+
job_class = msg_args["job_class"]
|
43
|
+
latency = (Time.now.to_f - (msg['enqueued_at'] || msg['created_at'])) * 1000
|
44
|
+
|
45
|
+
ScoutApm::Agent.instance.store.track_one!("Queue", queue, 0, {:extra_metrics => {:latency => latency}})
|
46
|
+
req = ScoutApm::RequestManager.lookup
|
47
|
+
req.start_layer( ScoutApm::Layer.new("Job", job_class) )
|
48
|
+
|
49
|
+
begin
|
50
|
+
yield
|
51
|
+
rescue
|
52
|
+
req.error!
|
53
|
+
raise
|
54
|
+
ensure
|
55
|
+
req.stop_layer
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/scout_apm/capacity.rb
CHANGED
@@ -48,7 +48,8 @@ module ScoutApm
|
|
48
48
|
window = 1.0 if window <= 0.0 # prevent divide-by-zero if clock adjusted.
|
49
49
|
capacity = time_spent / window
|
50
50
|
ScoutApm::Agent.instance.logger.debug "Instance/Capacity: #{capacity}"
|
51
|
-
ScoutApm::Agent.instance.store.
|
51
|
+
ScoutApm::Agent.instance.store.track_one!("Instance", "Capacity", capacity)
|
52
|
+
|
52
53
|
@processing_start_time = process_time
|
53
54
|
end
|
54
55
|
end
|
data/lib/scout_apm/context.rb
CHANGED
@@ -23,6 +23,11 @@ module ScoutApm
|
|
23
23
|
ScoutApm::ServerIntegrations::Null.new(STDOUT_LOGGER), # must be last
|
24
24
|
]
|
25
25
|
|
26
|
+
BACKGROUND_JOB_INTEGRATIONS = [
|
27
|
+
ScoutApm::BackgroundJobIntegrations::Sidekiq.new,
|
28
|
+
ScoutApm::BackgroundJobIntegrations::DelayedJob.new
|
29
|
+
]
|
30
|
+
|
26
31
|
FRAMEWORK_INTEGRATIONS = [
|
27
32
|
ScoutApm::FrameworkIntegrations::Rails2.new,
|
28
33
|
ScoutApm::FrameworkIntegrations::Rails3Or4.new,
|
@@ -120,7 +125,17 @@ module ScoutApm
|
|
120
125
|
# If forking, don't start worker thread in the master process. Since it's
|
121
126
|
# started as a Thread, it won't survive the fork.
|
122
127
|
def forking?
|
123
|
-
app_server_integration.forking?
|
128
|
+
app_server_integration.forking? || (background_job_integration && background_job_integration.forking?)
|
129
|
+
end
|
130
|
+
|
131
|
+
def background_job_integration
|
132
|
+
@background_job_integration ||= BACKGROUND_JOB_INTEGRATIONS.detect {|integration| integration.present?}
|
133
|
+
#### Temporary Disable
|
134
|
+
nil
|
135
|
+
end
|
136
|
+
|
137
|
+
def background_job_name
|
138
|
+
background_job_integration && background_job_integration.name
|
124
139
|
end
|
125
140
|
|
126
141
|
def deploy_integration
|
@@ -34,7 +34,7 @@ module ScoutApm
|
|
34
34
|
ScoutApm::Agent.instance.logger.info "Instrumenting ActionView::Template"
|
35
35
|
::ActionView::Template.class_eval do
|
36
36
|
include ::ScoutApm::Tracer
|
37
|
-
instrument_method :render, :
|
37
|
+
instrument_method :render, :type => "View", :name => '#{path[%r{^(/.*/)?(.*)$},2]}/Rendering', :scope => true
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -57,9 +57,19 @@ module ScoutApm
|
|
57
57
|
# applied to metrics recorded during this transaction. This lets us associate ActiveRecord calls with
|
58
58
|
# specific controller actions.
|
59
59
|
def perform_action_with_scout_instruments(*args, &block)
|
60
|
-
|
61
|
-
|
60
|
+
req = ScoutApm::RequestManager.lookup
|
61
|
+
req.annotate_request(:uri => request.fullpath)
|
62
|
+
req.context.add_user(:ip => request.remote_ip)
|
63
|
+
req.set_headers(request.headers)
|
64
|
+
req.start_layer( ScoutApm::Layer.new("Controller", "#{controller_path}/#{action_name}") )
|
65
|
+
|
66
|
+
begin
|
62
67
|
perform_action_without_scout_instruments(*args, &block)
|
68
|
+
rescue
|
69
|
+
req.error!
|
70
|
+
raise
|
71
|
+
ensure
|
72
|
+
req.stop_layer
|
63
73
|
end
|
64
74
|
end
|
65
75
|
end
|
@@ -20,7 +20,7 @@ module ScoutApm
|
|
20
20
|
if defined?(::ActionController) && defined?(::ActionController::Metal)
|
21
21
|
ScoutApm::Agent.instance.logger.info "Instrumenting ActionController::Metal"
|
22
22
|
::ActionController::Metal.class_eval do
|
23
|
-
include ScoutApm::Tracer
|
23
|
+
# include ScoutApm::Tracer
|
24
24
|
include ScoutApm::Instruments::ActionControllerRails3Instruments
|
25
25
|
end
|
26
26
|
end
|
@@ -29,12 +29,15 @@ module ScoutApm
|
|
29
29
|
ScoutApm::Agent.instance.logger.info "Instrumenting ActionView::PartialRenderer"
|
30
30
|
::ActionView::PartialRenderer.class_eval do
|
31
31
|
include ScoutApm::Tracer
|
32
|
+
|
32
33
|
instrument_method :render_partial,
|
33
|
-
:
|
34
|
+
:type => "View",
|
35
|
+
:name => '#{@template.virtual_path rescue "Unknown Partial"}/Rendering',
|
34
36
|
:scope => true
|
35
37
|
|
36
38
|
instrument_method :collection_with_template,
|
37
|
-
:
|
39
|
+
:type => "View",
|
40
|
+
:name => '#{@template.virtual_path rescue "Unknown Collection"}/Rendering',
|
38
41
|
:scope => true
|
39
42
|
end
|
40
43
|
|
@@ -42,7 +45,8 @@ module ScoutApm
|
|
42
45
|
::ActionView::TemplateRenderer.class_eval do
|
43
46
|
include ScoutApm::Tracer
|
44
47
|
instrument_method :render_template,
|
45
|
-
:
|
48
|
+
:type => "View",
|
49
|
+
:name => '#{args[0].virtual_path rescue "Unknown"}/Rendering',
|
46
50
|
:scope => true
|
47
51
|
end
|
48
52
|
end
|
@@ -50,24 +54,20 @@ module ScoutApm
|
|
50
54
|
end
|
51
55
|
|
52
56
|
module ActionControllerRails3Instruments
|
53
|
-
# Instruments the action and tracks errors.
|
54
57
|
def process_action(*args)
|
55
|
-
|
58
|
+
req = ScoutApm::RequestManager.lookup
|
59
|
+
req.annotate_request(:uri => request.fullpath)
|
60
|
+
req.context.add_user(:ip => request.remote_ip)
|
61
|
+
req.set_headers(request.headers)
|
56
62
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
raise
|
66
|
-
ensure
|
67
|
-
Thread::current[:scout_apm_scope_name] = nil
|
68
|
-
StackProf.stop
|
69
|
-
Thread::current[:scout_apm_prof] = StackProf.results
|
70
|
-
end
|
63
|
+
req.start_layer( ScoutApm::Layer.new("Controller", "#{controller_path}/#{action_name}") )
|
64
|
+
begin
|
65
|
+
super
|
66
|
+
rescue
|
67
|
+
req.error!
|
68
|
+
raise
|
69
|
+
ensure
|
70
|
+
req.stop_layer
|
71
71
|
end
|
72
72
|
end
|
73
73
|
end
|
@@ -58,12 +58,12 @@ module ScoutApm
|
|
58
58
|
|
59
59
|
def log_with_scout_instruments(*args, &block)
|
60
60
|
sql, name = args
|
61
|
-
self.class.instrument(scout_ar_metric_name(sql,name), :desc => Utils::SqlSanitizer.new(sql).to_s) do
|
61
|
+
self.class.instrument("ActiveRecord", scout_ar_metric_name(sql,name), :desc => Utils::SqlSanitizer.new(sql).to_s ) do
|
62
62
|
log_without_scout_instruments(sql, name, &block)
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
-
def scout_ar_metric_name(sql,name)
|
66
|
+
def scout_ar_metric_name(sql, name)
|
67
67
|
# sql: SELECT "places".* FROM "places" ORDER BY "places"."position" ASC
|
68
68
|
# name: Place Load
|
69
69
|
if name && (parts = name.split " ") && parts.size == 2
|
@@ -79,16 +79,13 @@ module ScoutApm
|
|
79
79
|
operation
|
80
80
|
end
|
81
81
|
end
|
82
|
-
metric = "
|
83
|
-
metric = "
|
82
|
+
metric = "#{model}/#{metric_name}" if metric_name
|
83
|
+
metric = "SQL/other" if metric.nil?
|
84
84
|
else
|
85
|
-
metric = "
|
85
|
+
metric = "SQL/Unknown"
|
86
86
|
end
|
87
87
|
metric
|
88
88
|
end
|
89
89
|
end # module ActiveRecordInstruments
|
90
90
|
end
|
91
91
|
end
|
92
|
-
|
93
|
-
|
94
|
-
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module Instruments
|
3
|
+
class DelayedJob
|
4
|
+
attr_reader :logger
|
5
|
+
|
6
|
+
def initialize(logger=ScoutApm::Agent.instance.logger)
|
7
|
+
@logger = logger
|
8
|
+
@installed = false
|
9
|
+
end
|
10
|
+
|
11
|
+
def installed?
|
12
|
+
@installed
|
13
|
+
end
|
14
|
+
|
15
|
+
def install
|
16
|
+
@installed = true
|
17
|
+
if defined?(::Delayed::Worker)
|
18
|
+
::Delayed::Worker.class_eval do
|
19
|
+
include ScoutApm::Tracer
|
20
|
+
include ScoutApm::Instruments::DelayedJobInstruments
|
21
|
+
alias run_without_scout_instruments run
|
22
|
+
alias run run_with_scout_instruments
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module DelayedJobInstruments
|
29
|
+
def run_with_scout_instruments(job)
|
30
|
+
scout_method_name = method_from_handler(job.handler)
|
31
|
+
queue = job.queue
|
32
|
+
latency = (Time.now.to_f - job.created_at.to_f) * 1000
|
33
|
+
|
34
|
+
ScoutApm::Agent.instance.store.track_one!("Queue", queue, 0, {:extra_metrics => {:latency => latency}})
|
35
|
+
req = ScoutApm::RequestManager.lookup
|
36
|
+
req.start_layer( ScoutApm::Layer.new("Job", scout_method_name) )
|
37
|
+
|
38
|
+
begin
|
39
|
+
run_without_scout_instruments(job)
|
40
|
+
rescue
|
41
|
+
req.error!
|
42
|
+
raise
|
43
|
+
ensure
|
44
|
+
req.stop_layer
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def method_from_handler(handler)
|
49
|
+
job_handler = YAML.load(handler)
|
50
|
+
klass = job_handler.object.name
|
51
|
+
method = job_handler.method_name
|
52
|
+
"#{klass}##{method}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|