scout_apm 2.3.5 → 2.4.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.markdown +0 -23
- data/lib/scout_apm.rb +21 -10
- data/lib/scout_apm/agent.rb +98 -336
- data/lib/scout_apm/agent/exit_handler.rb +64 -0
- data/lib/scout_apm/agent/preconditions.rb +69 -0
- data/lib/scout_apm/agent_context.rb +226 -0
- data/lib/scout_apm/app_server_load.rb +20 -18
- data/lib/scout_apm/background_job_integrations/resque.rb +7 -8
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +2 -8
- data/lib/scout_apm/background_recorder.rb +8 -3
- data/lib/scout_apm/background_worker.rb +14 -7
- data/lib/scout_apm/config.rb +35 -29
- data/lib/scout_apm/context.rb +11 -4
- data/lib/scout_apm/db_query_metric_set.rb +17 -5
- data/lib/scout_apm/debug.rb +1 -1
- data/lib/scout_apm/environment.rb +10 -14
- data/lib/scout_apm/framework_integrations/sinatra.rb +1 -1
- data/lib/scout_apm/git_revision.rb +13 -8
- data/lib/scout_apm/histogram.rb +1 -1
- data/lib/scout_apm/instant/middleware.rb +7 -7
- data/lib/scout_apm/instant_reporting.rb +7 -7
- data/lib/scout_apm/instrument_manager.rb +87 -0
- data/lib/scout_apm/instruments/action_controller_rails_2.rb +12 -7
- data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +16 -11
- data/lib/scout_apm/instruments/action_view.rb +11 -7
- data/lib/scout_apm/instruments/active_record.rb +28 -51
- data/lib/scout_apm/instruments/elasticsearch.rb +10 -6
- data/lib/scout_apm/instruments/grape.rb +12 -8
- data/lib/scout_apm/instruments/http_client.rb +11 -10
- data/lib/scout_apm/instruments/influxdb.rb +10 -6
- data/lib/scout_apm/instruments/middleware_detailed.rb +11 -5
- data/lib/scout_apm/instruments/middleware_summary.rb +11 -5
- data/lib/scout_apm/instruments/mongoid.rb +10 -5
- data/lib/scout_apm/instruments/moped.rb +11 -6
- data/lib/scout_apm/instruments/net_http.rb +11 -9
- data/lib/scout_apm/instruments/percentile_sampler.rb +8 -6
- data/lib/scout_apm/instruments/process/process_cpu.rb +8 -4
- data/lib/scout_apm/instruments/process/process_memory.rb +15 -10
- data/lib/scout_apm/instruments/rails_router.rb +12 -6
- data/lib/scout_apm/instruments/redis.rb +10 -6
- data/lib/scout_apm/instruments/samplers.rb +11 -0
- data/lib/scout_apm/instruments/sinatra.rb +5 -4
- data/lib/scout_apm/layaway.rb +26 -39
- data/lib/scout_apm/layaway_file.rb +8 -3
- data/lib/scout_apm/layer.rb +1 -1
- data/lib/scout_apm/layer_converters/converter_base.rb +4 -2
- data/lib/scout_apm/layer_converters/database_converter.rb +1 -1
- data/lib/scout_apm/layer_converters/histograms.rb +2 -2
- data/lib/scout_apm/layer_converters/slow_job_converter.rb +4 -3
- data/lib/scout_apm/layer_converters/slow_request_converter.rb +5 -4
- data/lib/scout_apm/logger.rb +143 -0
- data/lib/scout_apm/middleware.rb +7 -9
- data/lib/scout_apm/periodic_work.rb +28 -0
- data/lib/scout_apm/remote/server.rb +0 -2
- data/lib/scout_apm/reporter.rb +14 -8
- data/lib/scout_apm/reporting.rb +135 -0
- data/lib/scout_apm/request_manager.rb +4 -7
- data/lib/scout_apm/serializers/payload_serializer.rb +1 -1
- data/lib/scout_apm/slow_job_policy.rb +6 -2
- data/lib/scout_apm/slow_job_record.rb +5 -5
- data/lib/scout_apm/slow_request_policy.rb +6 -2
- data/lib/scout_apm/slow_transaction.rb +5 -5
- data/lib/scout_apm/store.rb +22 -16
- data/lib/scout_apm/synchronous_recorder.rb +7 -3
- data/lib/scout_apm/tasks/doctor.rb +75 -0
- data/lib/scout_apm/tasks/support.rb +22 -0
- data/lib/scout_apm/tracer.rb +5 -5
- data/lib/scout_apm/tracked_request.rb +23 -35
- data/lib/scout_apm/utils/backtrace_parser.rb +1 -1
- data/lib/scout_apm/utils/installed_gems.rb +7 -3
- data/lib/scout_apm/utils/klass_helper.rb +8 -2
- data/lib/scout_apm/utils/scm.rb +1 -1
- data/lib/scout_apm/utils/sql_sanitizer.rb +4 -6
- data/lib/scout_apm/version.rb +1 -1
- data/lib/tasks/doctor.rake +11 -0
- data/test/test_helper.rb +15 -2
- data/test/unit/agent_test.rb +1 -54
- data/test/unit/config_test.rb +9 -5
- data/test/unit/context_test.rb +4 -4
- data/test/unit/db_query_metric_set_test.rb +11 -4
- data/test/unit/fake_store_test.rb +1 -1
- data/test/unit/git_revision_test.rb +3 -3
- data/test/unit/instruments/net_http_test.rb +2 -1
- data/test/unit/instruments/percentile_sampler_test.rb +5 -9
- data/test/unit/layaway_test.rb +10 -5
- data/test/unit/layer_converters/metric_converter_test.rb +2 -2
- data/test/unit/slow_request_policy_test.rb +7 -3
- data/test/unit/sql_sanitizer_test.rb +0 -6
- data/test/unit/store_test.rb +11 -8
- metadata +15 -7
- data/lib/scout_apm/agent/logging.rb +0 -74
- data/lib/scout_apm/agent/reporting.rb +0 -129
- data/lib/scout_apm/utils/null_logger.rb +0 -13
data/lib/scout_apm/histogram.rb
CHANGED
@@ -171,7 +171,7 @@ module ScoutApm
|
|
171
171
|
bins.slice!(minDeltaIndex - 1, 2)
|
172
172
|
bins.insert(minDeltaIndex - 1, mergedBin)
|
173
173
|
rescue => e
|
174
|
-
ScoutApm::Agent.instance.logger.info("Error in NumericHistogram#trim_one. #{e.message}, #{e.backtrace}, #{self.inspect}")
|
174
|
+
ScoutApm::Agent.instance.context.logger.info("Error in NumericHistogram#trim_one. #{e.message}, #{e.backtrace}, #{self.inspect}")
|
175
175
|
raise
|
176
176
|
end
|
177
177
|
end
|
@@ -55,7 +55,7 @@ module ScoutApm
|
|
55
55
|
DevTraceResponseManipulator.new(env, rack_response).call
|
56
56
|
rescue Exception => e
|
57
57
|
# If anything went wrong at all, just bail out and return the unmodified response.
|
58
|
-
ScoutApm::Agent.instance.logger.debug("DevTrace: Raised an exception: #{e.message}, #{e.backtrace}")
|
58
|
+
ScoutApm::Agent.instance.context.logger.debug("DevTrace: Raised an exception: #{e.message}, #{e.backtrace}")
|
59
59
|
rack_response
|
60
60
|
end
|
61
61
|
end
|
@@ -79,7 +79,7 @@ module ScoutApm
|
|
79
79
|
return rack_response unless preconditions_met?
|
80
80
|
|
81
81
|
if ajax_request?
|
82
|
-
ScoutApm::Agent.instance.logger.debug("DevTrace: in middleware, dev_trace is active, and response has a body. This is either AJAX or JSON. Path=#{path}; ContentType=#{content_type}")
|
82
|
+
ScoutApm::Agent.instance.context.logger.debug("DevTrace: in middleware, dev_trace is active, and response has a body. This is either AJAX or JSON. Path=#{path}; ContentType=#{content_type}")
|
83
83
|
adjust_ajax_header
|
84
84
|
else
|
85
85
|
adjust_html_response
|
@@ -116,7 +116,7 @@ module ScoutApm
|
|
116
116
|
end
|
117
117
|
|
118
118
|
def dev_trace_disabled?
|
119
|
-
! ScoutApm::Agent.instance.config.value('dev_trace')
|
119
|
+
! ScoutApm::Agent.instance.context.config.value('dev_trace')
|
120
120
|
end
|
121
121
|
|
122
122
|
########################
|
@@ -212,7 +212,7 @@ module ScoutApm
|
|
212
212
|
##############################
|
213
213
|
|
214
214
|
def logger
|
215
|
-
ScoutApm::Agent.instance.logger
|
215
|
+
ScoutApm::Agent.instance.context.logger
|
216
216
|
end
|
217
217
|
|
218
218
|
def tracked_request
|
@@ -220,14 +220,14 @@ module ScoutApm
|
|
220
220
|
end
|
221
221
|
|
222
222
|
def apm_host
|
223
|
-
ScoutApm::Agent.instance.config.value("direct_host")
|
223
|
+
ScoutApm::Agent.instance.context.config.value("direct_host")
|
224
224
|
end
|
225
225
|
|
226
226
|
def trace
|
227
227
|
@trace ||=
|
228
228
|
begin
|
229
229
|
layer_finder = LayerConverters::FindLayerByType.new(tracked_request)
|
230
|
-
converter = LayerConverters::SlowRequestConverter.new(tracked_request, layer_finder, ScoutApm::FakeStore.new)
|
230
|
+
converter = LayerConverters::SlowRequestConverter.new(ScoutApm::Agent.instance.context, tracked_request, layer_finder, ScoutApm::FakeStore.new)
|
231
231
|
converter.call
|
232
232
|
end
|
233
233
|
end
|
@@ -236,7 +236,7 @@ module ScoutApm
|
|
236
236
|
@payload ||=
|
237
237
|
begin
|
238
238
|
metadata = {
|
239
|
-
:app_root => ScoutApm::
|
239
|
+
:app_root => ScoutApm::Agent.instance.context.environment.root.to_s,
|
240
240
|
:unique_id => env['action_dispatch.request_id'], # note, this is a different unique_id than what "normal" payloads use
|
241
241
|
:agent_version => ScoutApm::VERSION,
|
242
242
|
:platform => "ruby",
|
@@ -15,12 +15,12 @@ module ScoutApm
|
|
15
15
|
# Serialize that trace. We reuse the PayloadSerializer, but only provide the metadata and traces.
|
16
16
|
# In this case, the traces array will always have just one element.
|
17
17
|
metadata = {
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
:app_root => ScoutApm::Agent.instance.context.environment.root.to_s,
|
19
|
+
:unique_id => ScoutApm::Utils::UniqueId.simple,
|
20
|
+
:agent_version => ScoutApm::VERSION,
|
21
|
+
:agent_time => Time.now.iso8601,
|
22
|
+
:agent_pid => Process.pid,
|
23
|
+
:platform => "ruby",
|
24
24
|
}
|
25
25
|
|
26
26
|
metrics = []
|
@@ -31,7 +31,7 @@ module ScoutApm
|
|
31
31
|
payload = ScoutApm::Serializers::PayloadSerializer.serialize(metadata, metrics, traces, jobs, slow_jobs)
|
32
32
|
|
33
33
|
# Hand it off to the reporter for POST to our servers
|
34
|
-
reporter = Reporter.new(:instant_trace,
|
34
|
+
reporter = Reporter.new(context, :instant_trace, @instant_key)
|
35
35
|
reporter.report(payload, {'Content-Type' => 'application/json'} )
|
36
36
|
end
|
37
37
|
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
class InstrumentManager
|
3
|
+
attr_reader :context
|
4
|
+
|
5
|
+
attr_reader :installed_instruments
|
6
|
+
|
7
|
+
def initialize(context)
|
8
|
+
@context = context
|
9
|
+
@installed_instruments = []
|
10
|
+
end
|
11
|
+
|
12
|
+
# Loads the instrumention logic.
|
13
|
+
def install!
|
14
|
+
case framework
|
15
|
+
when :rails then
|
16
|
+
install_instrument(ScoutApm::Instruments::ActionControllerRails2)
|
17
|
+
when :rails3_or_4 then
|
18
|
+
install_instrument(ScoutApm::Instruments::ActionControllerRails3Rails4)
|
19
|
+
install_instrument(ScoutApm::Instruments::RailsRouter)
|
20
|
+
|
21
|
+
if config.value("detailed_middleware")
|
22
|
+
install_instrument(ScoutApm::Instruments::MiddlewareDetailed)
|
23
|
+
else
|
24
|
+
install_instrument(ScoutApm::Instruments::MiddlewareSummary)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
install_instrument(ScoutApm::Instruments::ActionView)
|
29
|
+
install_instrument(ScoutApm::Instruments::ActiveRecord)
|
30
|
+
install_instrument(ScoutApm::Instruments::Moped)
|
31
|
+
install_instrument(ScoutApm::Instruments::Mongoid)
|
32
|
+
install_instrument(ScoutApm::Instruments::NetHttp)
|
33
|
+
install_instrument(ScoutApm::Instruments::HttpClient)
|
34
|
+
install_instrument(ScoutApm::Instruments::Redis)
|
35
|
+
install_instrument(ScoutApm::Instruments::InfluxDB)
|
36
|
+
install_instrument(ScoutApm::Instruments::Elasticsearch)
|
37
|
+
install_instrument(ScoutApm::Instruments::Grape)
|
38
|
+
rescue
|
39
|
+
logger.warn "Exception loading instruments:"
|
40
|
+
logger.warn $!.message
|
41
|
+
logger.warn $!.backtrace
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def install_instrument(instrument_klass)
|
47
|
+
return if already_installed?(instrument_klass)
|
48
|
+
|
49
|
+
if skip_instrument?(instrument_klass)
|
50
|
+
logger.info "Skipping Disabled Instrument: #{instrument_short_name} - To re-enable, change `disabled_instruments` key in scout_apm.yml"
|
51
|
+
return
|
52
|
+
end
|
53
|
+
|
54
|
+
instance = instrument_klass.new(context)
|
55
|
+
@installed_instruments << instance
|
56
|
+
instance.install
|
57
|
+
end
|
58
|
+
|
59
|
+
# Allows users to skip individual instruments via the config file
|
60
|
+
def skip_instrument?(instrument_klass)
|
61
|
+
instrument_short_name = instrument_klass.name.split("::").last
|
62
|
+
(config.value("disabled_instruments") || []).include?(instrument_short_name)
|
63
|
+
end
|
64
|
+
|
65
|
+
def already_installed?(instrument_klass)
|
66
|
+
@installed_instruments.any? do |already_installed_instrument|
|
67
|
+
instrument_klass === already_installed_instrument
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
###################
|
72
|
+
# Lookup Helpers #
|
73
|
+
###################
|
74
|
+
|
75
|
+
def logger
|
76
|
+
context.logger
|
77
|
+
end
|
78
|
+
|
79
|
+
def config
|
80
|
+
context.config
|
81
|
+
end
|
82
|
+
|
83
|
+
def framework
|
84
|
+
context.environment.framework
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -1,27 +1,31 @@
|
|
1
1
|
module ScoutApm
|
2
2
|
module Instruments
|
3
3
|
class ActionControllerRails2
|
4
|
-
attr_reader :
|
4
|
+
attr_reader :context
|
5
5
|
|
6
|
-
def
|
7
|
-
@
|
6
|
+
def initialize(context)
|
7
|
+
@context = context
|
8
8
|
@installed = false
|
9
9
|
end
|
10
10
|
|
11
|
+
def logger
|
12
|
+
context.logger
|
13
|
+
end
|
14
|
+
|
11
15
|
def installed?
|
12
16
|
@installed
|
13
17
|
end
|
14
18
|
|
15
19
|
def install
|
16
|
-
@installed = true
|
17
|
-
|
18
20
|
if defined?(::ActionController) && defined?(::ActionController::Base)
|
21
|
+
@installed = true
|
22
|
+
|
19
23
|
::ActionController::Base.class_eval do
|
20
24
|
include ScoutApm::Tracer
|
21
25
|
include ::ScoutApm::Instruments::ActionControllerRails2Instruments
|
22
26
|
end
|
23
27
|
|
24
|
-
|
28
|
+
logger.info "Instrumenting ActionView::Template"
|
25
29
|
::ActionView::Template.class_eval do
|
26
30
|
include ::ScoutApm::Tracer
|
27
31
|
instrument_method :render, :type => "View", :name => '#{path[%r{^(/.*/)?(.*)$},2]}/Rendering', :scope => true
|
@@ -33,7 +37,8 @@ module ScoutApm
|
|
33
37
|
|
34
38
|
module ActionControllerRails2Instruments
|
35
39
|
def self.included(instrumented_class)
|
36
|
-
|
40
|
+
# XXX: Don't lookup context by global
|
41
|
+
ScoutApm::Agent.instance.context.logger.info "Instrumenting #{instrumented_class.inspect}"
|
37
42
|
instrumented_class.class_eval do
|
38
43
|
unless instrumented_class.method_defined?(:perform_action_without_scout_instruments)
|
39
44
|
alias_method :perform_action_without_scout_instruments, :perform_action
|
@@ -2,27 +2,31 @@ module ScoutApm
|
|
2
2
|
module Instruments
|
3
3
|
# instrumentation for Rails 3 and Rails 4 is the same.
|
4
4
|
class ActionControllerRails3Rails4
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :context
|
6
6
|
|
7
|
-
def
|
8
|
-
@
|
7
|
+
def initialize(context)
|
8
|
+
@context = context
|
9
9
|
@installed = false
|
10
10
|
end
|
11
11
|
|
12
|
+
def logger
|
13
|
+
context.logger
|
14
|
+
end
|
15
|
+
|
12
16
|
def installed?
|
13
17
|
@installed
|
14
18
|
end
|
15
19
|
|
16
20
|
def install
|
17
|
-
@installed = true
|
18
|
-
|
19
21
|
# We previously instrumented ActionController::Metal, which missed
|
20
22
|
# before and after filter timing. Instrumenting Base includes those
|
21
23
|
# filters, at the expense of missing out on controllers that don't use
|
22
24
|
# the full Rails stack.
|
23
25
|
if defined?(::ActionController)
|
26
|
+
@installed = true
|
27
|
+
|
24
28
|
if defined?(::ActionController::Base)
|
25
|
-
|
29
|
+
logger.info "Instrumenting ActionController::Base"
|
26
30
|
::ActionController::Base.class_eval do
|
27
31
|
# include ScoutApm::Tracer
|
28
32
|
include ScoutApm::Instruments::ActionControllerBaseInstruments
|
@@ -30,14 +34,14 @@ module ScoutApm
|
|
30
34
|
end
|
31
35
|
|
32
36
|
if defined?(::ActionController::Metal)
|
33
|
-
|
37
|
+
logger.info "Instrumenting ActionController::Metal"
|
34
38
|
::ActionController::Metal.class_eval do
|
35
39
|
include ScoutApm::Instruments::ActionControllerMetalInstruments
|
36
40
|
end
|
37
41
|
end
|
38
42
|
|
39
43
|
if defined?(::ActionController::API)
|
40
|
-
|
44
|
+
logger.info "Instrumenting ActionController::Api"
|
41
45
|
::ActionController::API.class_eval do
|
42
46
|
include ScoutApm::Instruments::ActionControllerAPIInstruments
|
43
47
|
end
|
@@ -59,7 +63,7 @@ module ScoutApm
|
|
59
63
|
|
60
64
|
# Check if this this request is to be reported instantly
|
61
65
|
if instant_key = request.cookies['scoutapminstant']
|
62
|
-
Agent.instance.logger.info "Instant trace request with key=#{instant_key} for path=#{path}"
|
66
|
+
ScoutApm::Agent.instance.context.logger.info "Instant trace request with key=#{instant_key} for path=#{path}"
|
63
67
|
req.instant_key = instant_key
|
64
68
|
end
|
65
69
|
|
@@ -91,8 +95,9 @@ module ScoutApm
|
|
91
95
|
end
|
92
96
|
|
93
97
|
# Given an +ActionDispatch::Request+, formats the uri based on config settings.
|
94
|
-
|
95
|
-
|
98
|
+
# XXX: Don't lookup context like this - find a way to pass it through
|
99
|
+
def self.scout_transaction_uri(request, config=ScoutApm::Agent.instance.context.config)
|
100
|
+
case config.value("uri_reporting")
|
96
101
|
when 'path'
|
97
102
|
request.path # strips off the query string for more security
|
98
103
|
else # default handles filtered params
|
@@ -2,22 +2,26 @@ module ScoutApm
|
|
2
2
|
module Instruments
|
3
3
|
# instrumentation for Rails 3 and Rails 4 is the same.
|
4
4
|
class ActionView
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :context
|
6
6
|
|
7
|
-
def
|
8
|
-
@
|
7
|
+
def initialize(context)
|
8
|
+
@context = context
|
9
9
|
@installed = false
|
10
10
|
end
|
11
11
|
|
12
|
+
def logger
|
13
|
+
context.logger
|
14
|
+
end
|
15
|
+
|
12
16
|
def installed?
|
13
17
|
@installed
|
14
18
|
end
|
15
19
|
|
16
20
|
def install
|
17
|
-
@installed = true
|
18
|
-
|
19
21
|
if defined?(::ActionView) && defined?(::ActionView::PartialRenderer)
|
20
|
-
|
22
|
+
@installed = true
|
23
|
+
|
24
|
+
logger.info "Instrumenting ActionView::PartialRenderer"
|
21
25
|
::ActionView::PartialRenderer.class_eval do
|
22
26
|
include ScoutApm::Tracer
|
23
27
|
|
@@ -32,7 +36,7 @@ module ScoutApm
|
|
32
36
|
:scope => true
|
33
37
|
end
|
34
38
|
|
35
|
-
|
39
|
+
logger.info "Instrumenting ActionView::TemplateRenderer"
|
36
40
|
::ActionView::TemplateRenderer.class_eval do
|
37
41
|
include ScoutApm::Tracer
|
38
42
|
instrument_method :render_template,
|
@@ -1,55 +1,25 @@
|
|
1
1
|
require 'scout_apm/utils/sql_sanitizer'
|
2
2
|
|
3
3
|
module ScoutApm
|
4
|
-
class SqlList
|
5
|
-
attr_reader :sqls
|
6
|
-
|
7
|
-
def initialize(sql=nil)
|
8
|
-
@sqls = []
|
9
|
-
|
10
|
-
if !sql.nil?
|
11
|
-
push(sql)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def <<(sql)
|
16
|
-
push(sql)
|
17
|
-
end
|
18
|
-
|
19
|
-
def push(sql)
|
20
|
-
if !(Utils::SqlSanitizer === sql)
|
21
|
-
sql = Utils::SqlSanitizer.new(sql)
|
22
|
-
end
|
23
|
-
@sqls << sql
|
24
|
-
end
|
25
|
-
|
26
|
-
# All of this one, then all of the other.
|
27
|
-
def merge(other)
|
28
|
-
@sqls += other.sqls
|
29
|
-
end
|
30
|
-
|
31
|
-
def to_s
|
32
|
-
@sqls.map{|s| s.to_s }.join(";\n")
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
4
|
module Instruments
|
37
5
|
class ActiveRecord
|
38
|
-
attr_reader :
|
6
|
+
attr_reader :context
|
39
7
|
|
40
|
-
def
|
41
|
-
@
|
8
|
+
def initialize(context)
|
9
|
+
@context = context
|
42
10
|
@installed = false
|
43
11
|
end
|
44
12
|
|
13
|
+
def logger
|
14
|
+
context.logger
|
15
|
+
end
|
16
|
+
|
45
17
|
def installed?
|
46
18
|
@installed
|
47
19
|
end
|
48
20
|
|
49
21
|
def install
|
50
|
-
|
51
|
-
|
52
|
-
if defined?(::Rails) && ::Rails::VERSION::MAJOR.to_i == 3 && ::Rails.respond_to?(:configuration)
|
22
|
+
if install_via_after_initialize?
|
53
23
|
Rails.configuration.after_initialize do
|
54
24
|
add_instruments
|
55
25
|
end
|
@@ -58,9 +28,21 @@ module ScoutApm
|
|
58
28
|
end
|
59
29
|
end
|
60
30
|
|
31
|
+
# If we have the right version of rails, we should use the hooks provided
|
32
|
+
# to install these instruments
|
33
|
+
def install_via_after_initialize?
|
34
|
+
defined?(::Rails) &&
|
35
|
+
defined?(::Rails::VERSION) &&
|
36
|
+
defined?(::Rails::VERSION::MAJOR) &&
|
37
|
+
::Rails::VERSION::MAJOR.to_i == 3 &&
|
38
|
+
::Rails.respond_to?(:configuration)
|
39
|
+
end
|
40
|
+
|
61
41
|
def add_instruments
|
62
42
|
# Setup Tracer on AR::Base
|
63
43
|
if Utils::KlassHelper.defined?("ActiveRecord::Base")
|
44
|
+
@installed = true
|
45
|
+
|
64
46
|
::ActiveRecord::Base.class_eval do
|
65
47
|
include ::ScoutApm::Tracer
|
66
48
|
end
|
@@ -112,14 +94,14 @@ module ScoutApm
|
|
112
94
|
if layer && layer.type == "ActiveRecord"
|
113
95
|
layer.annotate_layer(payload)
|
114
96
|
elsif layer
|
115
|
-
|
97
|
+
logger.debug("Expected layer type: ActiveRecord, got #{layer && layer.type}")
|
116
98
|
else
|
117
99
|
# noop, no layer at all. We're probably ignoring this req.
|
118
100
|
end
|
119
101
|
end
|
120
102
|
end
|
121
103
|
rescue
|
122
|
-
|
104
|
+
logger.warn "ActiveRecord instrumentation exception: #{$!.message}"
|
123
105
|
end
|
124
106
|
end
|
125
107
|
|
@@ -134,7 +116,7 @@ module ScoutApm
|
|
134
116
|
################################################################################
|
135
117
|
module ActiveRecordInstruments
|
136
118
|
def self.included(instrumented_class)
|
137
|
-
ScoutApm::Agent.instance.logger.info "Instrumenting #{instrumented_class.inspect}"
|
119
|
+
ScoutApm::Agent.instance.context.logger.info "Instrumenting #{instrumented_class.inspect}"
|
138
120
|
instrumented_class.class_eval do
|
139
121
|
unless instrumented_class.method_defined?(:log_without_scout_instruments)
|
140
122
|
alias_method :log_without_scout_instruments, :log
|
@@ -147,12 +129,13 @@ module ScoutApm
|
|
147
129
|
# Extract data from the arguments
|
148
130
|
sql, name = args
|
149
131
|
metric_name = Utils::ActiveRecordMetricName.new(sql, name)
|
150
|
-
desc =
|
132
|
+
desc = Utils::SqlSanitizer.new(sql)
|
151
133
|
|
152
134
|
# Get current ScoutApm context
|
153
135
|
req = ScoutApm::RequestManager.lookup
|
154
136
|
current_layer = req.current_layer
|
155
137
|
|
138
|
+
|
156
139
|
# If we call #log, we have a real query to run, and we've already
|
157
140
|
# gotten through the cache gatekeeper. Since we want to only trace real
|
158
141
|
# queries, and not repeated identical queries that just hit cache, we
|
@@ -167,13 +150,9 @@ module ScoutApm
|
|
167
150
|
# TODO: Get rid of call .to_s, need to find this without forcing a previous run of the name logic
|
168
151
|
if current_layer.name.to_s == Utils::ActiveRecordMetricName::DEFAULT_METRIC
|
169
152
|
current_layer.name = metric_name
|
153
|
+
current_layer.desc = desc
|
170
154
|
end
|
171
155
|
|
172
|
-
if current_layer.desc.nil?
|
173
|
-
current_layer.desc = SqlList.new
|
174
|
-
end
|
175
|
-
current_layer.desc.merge(desc)
|
176
|
-
|
177
156
|
log_without_scout_instruments(*args, &block)
|
178
157
|
|
179
158
|
# OR: Start a new layer, we didn't pick up instrumentation earlier in the stack.
|
@@ -211,7 +190,7 @@ module ScoutApm
|
|
211
190
|
|
212
191
|
module ActiveRecordQueryingInstruments
|
213
192
|
def self.included(instrumented_class)
|
214
|
-
ScoutApm::Agent.instance.logger.info "Instrumenting ActiveRecord::Querying - #{instrumented_class.inspect}"
|
193
|
+
ScoutApm::Agent.instance.context.logger.info "Instrumenting ActiveRecord::Querying - #{instrumented_class.inspect}"
|
215
194
|
instrumented_class.class_eval do
|
216
195
|
unless instrumented_class.method_defined?(:find_by_sql_without_scout_instruments)
|
217
196
|
alias_method :find_by_sql_without_scout_instruments, :find_by_sql
|
@@ -237,7 +216,7 @@ module ScoutApm
|
|
237
216
|
|
238
217
|
module ActiveRecordFinderMethodsInstruments
|
239
218
|
def self.included(instrumented_class)
|
240
|
-
ScoutApm::Agent.instance.logger.info "Instrumenting ActiveRecord::FinderMethods - #{instrumented_class.inspect}"
|
219
|
+
ScoutApm::Agent.instance.context.logger.info "Instrumenting ActiveRecord::FinderMethods - #{instrumented_class.inspect}"
|
241
220
|
instrumented_class.class_eval do
|
242
221
|
unless instrumented_class.method_defined?(:find_with_associations_without_scout_instruments)
|
243
222
|
alias_method :find_with_associations_without_scout_instruments, :find_with_associations
|
@@ -250,7 +229,6 @@ module ScoutApm
|
|
250
229
|
req = ScoutApm::RequestManager.lookup
|
251
230
|
layer = ScoutApm::Layer.new("ActiveRecord", Utils::ActiveRecordMetricName::DEFAULT_METRIC)
|
252
231
|
layer.annotate_layer(:ignorable => true)
|
253
|
-
layer.desc = SqlList.new
|
254
232
|
req.start_layer(layer)
|
255
233
|
req.ignore_children!
|
256
234
|
begin
|
@@ -269,7 +247,6 @@ module ScoutApm
|
|
269
247
|
|
270
248
|
req = ScoutApm::RequestManager.lookup
|
271
249
|
layer = ScoutApm::Layer.new("ActiveRecord", Utils::ActiveRecordMetricName.new("", "#{model} #{operation}"))
|
272
|
-
layer.desc = SqlList.new
|
273
250
|
req.start_layer(layer)
|
274
251
|
req.ignore_children!
|
275
252
|
begin
|