scout_apm 2.6.6 → 4.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +49 -0
- data/.rubocop.yml +2 -5
- data/.travis.yml +3 -7
- data/CHANGELOG.markdown +51 -0
- data/Gemfile +1 -8
- data/gems/rails6.gemfile +1 -1
- data/lib/scout_apm.rb +23 -1
- data/lib/scout_apm/agent.rb +22 -0
- data/lib/scout_apm/agent_context.rb +14 -2
- data/lib/scout_apm/background_job_integrations/delayed_job.rb +1 -1
- data/lib/scout_apm/background_job_integrations/faktory.rb +103 -0
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +2 -2
- data/lib/scout_apm/config.rb +17 -2
- data/lib/scout_apm/detailed_trace.rb +2 -1
- data/lib/scout_apm/environment.rb +17 -1
- data/lib/scout_apm/error.rb +27 -0
- data/lib/scout_apm/error_service.rb +32 -0
- data/lib/scout_apm/error_service/error_buffer.rb +39 -0
- data/lib/scout_apm/error_service/error_record.rb +211 -0
- data/lib/scout_apm/error_service/ignored_exceptions.rb +66 -0
- data/lib/scout_apm/error_service/middleware.rb +32 -0
- data/lib/scout_apm/error_service/notifier.rb +33 -0
- data/lib/scout_apm/error_service/payload.rb +47 -0
- data/lib/scout_apm/error_service/periodic_work.rb +17 -0
- data/lib/scout_apm/error_service/railtie.rb +11 -0
- data/lib/scout_apm/error_service/sidekiq.rb +80 -0
- data/lib/scout_apm/extensions/transaction_callback_payload.rb +1 -1
- data/lib/scout_apm/instrument_manager.rb +1 -0
- data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +47 -26
- data/lib/scout_apm/instruments/action_view.rb +21 -8
- data/lib/scout_apm/instruments/active_record.rb +17 -28
- data/lib/scout_apm/instruments/typhoeus.rb +88 -0
- data/lib/scout_apm/layer.rb +1 -1
- data/lib/scout_apm/middleware.rb +1 -1
- data/lib/scout_apm/remote/server.rb +13 -1
- data/lib/scout_apm/reporter.rb +8 -3
- data/lib/scout_apm/serializers/payload_serializer_to_json.rb +6 -2
- data/lib/scout_apm/slow_policy/age_policy.rb +33 -0
- data/lib/scout_apm/slow_policy/percent_policy.rb +22 -0
- data/lib/scout_apm/slow_policy/percentile_policy.rb +24 -0
- data/lib/scout_apm/slow_policy/policy.rb +21 -0
- data/lib/scout_apm/slow_policy/speed_policy.rb +16 -0
- data/lib/scout_apm/slow_request_policy.rb +18 -77
- data/lib/scout_apm/tracer.rb +2 -2
- data/lib/scout_apm/utils/sql_sanitizer.rb +1 -0
- data/lib/scout_apm/utils/sql_sanitizer_regex.rb +3 -3
- data/lib/scout_apm/utils/sql_sanitizer_regex_1_8_7.rb +1 -0
- data/lib/scout_apm/version.rb +1 -1
- data/scout_apm.gemspec +6 -6
- data/test/unit/agent_context_test.rb +29 -0
- data/test/unit/environment_test.rb +2 -2
- data/test/unit/error_service/error_buffer_test.rb +25 -0
- data/test/unit/error_service/ignored_exceptions_test.rb +49 -0
- data/test/unit/serializers/payload_serializer_test.rb +36 -0
- data/test/unit/slow_request_policy_test.rb +41 -13
- data/test/unit/sql_sanitizer_test.rb +38 -0
- data/test/unit/tracer_test.rb +25 -0
- metadata +27 -61
- data/lib/scout_apm/slow_job_policy.rb +0 -111
- data/test/unit/slow_job_policy_test.rb +0 -6
@@ -0,0 +1,33 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module ErrorService
|
3
|
+
class Notifier
|
4
|
+
attr_reader :context
|
5
|
+
attr_reader :reporter
|
6
|
+
|
7
|
+
def initialize(context)
|
8
|
+
@context = context
|
9
|
+
@reporter = ScoutApm::Reporter.new(context, :errors)
|
10
|
+
end
|
11
|
+
|
12
|
+
def ship
|
13
|
+
error_records = context.error_buffer.get_and_reset_error_records
|
14
|
+
if error_records.any?
|
15
|
+
payload = ScoutApm::ErrorService::Payload.new(context, error_records)
|
16
|
+
reporter.report(
|
17
|
+
payload.serialize,
|
18
|
+
default_headers.merge("X-Error-Count" => error_records.length.to_s)
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def default_headers
|
26
|
+
{
|
27
|
+
"Content-Type" => "application/json",
|
28
|
+
"Accept" => "application/json"
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module ErrorService
|
3
|
+
class Payload
|
4
|
+
attr_reader :context
|
5
|
+
attr_reader :errors
|
6
|
+
|
7
|
+
def initialize(context, errors)
|
8
|
+
@context = context
|
9
|
+
@errors = errors
|
10
|
+
end
|
11
|
+
|
12
|
+
# TODO: Don't use to_json since it isn't supported in Ruby 1.8.7
|
13
|
+
def serialize
|
14
|
+
payload = as_json.to_json
|
15
|
+
context.logger.info(payload)
|
16
|
+
payload
|
17
|
+
end
|
18
|
+
|
19
|
+
def as_json
|
20
|
+
serialized_errors = errors.map do |error_record|
|
21
|
+
serialize_error_record(error_record)
|
22
|
+
end
|
23
|
+
|
24
|
+
{
|
25
|
+
:notifier => "scout_apm_ruby",
|
26
|
+
:environment => context.environment.env,
|
27
|
+
:root => context.environment.root,
|
28
|
+
:problems => serialized_errors,
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def serialize_error_record(error_record)
|
33
|
+
{
|
34
|
+
:exception_class => error_record.exception_class,
|
35
|
+
:message => error_record.message,
|
36
|
+
:request_uri => error_record.request_uri,
|
37
|
+
:request_params => error_record.request_params,
|
38
|
+
:request_session => error_record.request_session,
|
39
|
+
:environment => error_record.environment,
|
40
|
+
:trace => error_record.trace,
|
41
|
+
:request_components => error_record.request_components,
|
42
|
+
:context => error_record.context,
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module ErrorService
|
3
|
+
class PeriodicWork
|
4
|
+
attr_reader :context
|
5
|
+
|
6
|
+
def initialize(context)
|
7
|
+
@context = context
|
8
|
+
@notifier = ScoutApm::ErrorService::Notifier.new(context)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Expected to be called many times over the life of the agent
|
12
|
+
def run
|
13
|
+
@notifier.ship
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module ErrorService
|
3
|
+
class Railtie < Rails::Railtie
|
4
|
+
initializer "scoutapm_error_service.middleware" do |app|
|
5
|
+
next if ScoutApm::Agent.instance.config.value("error_service")
|
6
|
+
|
7
|
+
app.config.middleware.insert_after ActionDispatch::DebugExceptions, ScoutApm::ErrorService::Rack
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module ErrorService
|
3
|
+
class Sidekiq
|
4
|
+
def initialize
|
5
|
+
@context = ScoutApm::Agent.instance.context
|
6
|
+
end
|
7
|
+
|
8
|
+
def install
|
9
|
+
return false unless defined?(::Sidekiq)
|
10
|
+
|
11
|
+
if ::Sidekiq::VERSION < "3"
|
12
|
+
install_sidekiq_with_middleware
|
13
|
+
else
|
14
|
+
install_sidekiq_with_error_handler
|
15
|
+
end
|
16
|
+
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
def install_sidekiq_with_middleware
|
21
|
+
# old behavior
|
22
|
+
::Sidekiq.configure_server do |config|
|
23
|
+
config.server_middleware do |chain|
|
24
|
+
chain.add ScoutApm::ErrorService::Sidekiq::SidekiqExceptionMiddleware
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def install_sidekiq_with_error_handler
|
30
|
+
::Sidekiq.configure_server do |config|
|
31
|
+
config.error_handlers << proc { |exception, job_info|
|
32
|
+
context = ScoutApm::Agent.instance.context
|
33
|
+
|
34
|
+
# Bail out early, and reraise if the error is not interesting.
|
35
|
+
if context.ignored_exceptions.ignored?(exception)
|
36
|
+
raise
|
37
|
+
end
|
38
|
+
|
39
|
+
job_class =
|
40
|
+
begin
|
41
|
+
job_class = job_info[:job]["class"]
|
42
|
+
job_class = job_info[:job]["args"][0]["job_class"] if job_class == "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
|
43
|
+
job_class
|
44
|
+
rescue
|
45
|
+
"UnknownJob"
|
46
|
+
end
|
47
|
+
|
48
|
+
# Capture the error for further processing and shipping
|
49
|
+
context.error_buffer.capture(exception, job_info.merge(:custom_controller => job_class))
|
50
|
+
}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class SidekiqExceptionMiddleware
|
55
|
+
def call(worker, msg, queue)
|
56
|
+
yield
|
57
|
+
rescue => exception
|
58
|
+
context = ScoutApm::Agent.instance.context
|
59
|
+
|
60
|
+
# Bail out early, and reraise if the error is not interesting.
|
61
|
+
if context.ignored_exceptions.ignored?(exception)
|
62
|
+
raise
|
63
|
+
end
|
64
|
+
|
65
|
+
# Capture the error for further processing and shipping
|
66
|
+
context.error_buffer.capture(
|
67
|
+
exception,
|
68
|
+
{
|
69
|
+
:custom_params => msg,
|
70
|
+
:custom_controller => msg["class"]
|
71
|
+
}
|
72
|
+
)
|
73
|
+
|
74
|
+
# Finally, reraise
|
75
|
+
raise exception
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -26,7 +26,7 @@ module ScoutApm
|
|
26
26
|
# The time in queue of the transaction in ms. If not present, +nil+ is returned as this is unknown.
|
27
27
|
def queue_time_ms
|
28
28
|
# Controller logic
|
29
|
-
if converter_results[:queue_time] && converter_results[:
|
29
|
+
if converter_results[:queue_time] && converter_results[:queue_time].any?
|
30
30
|
converter_results[:queue_time].values.first.total_call_time*1000 # ms
|
31
31
|
# Job logic
|
32
32
|
elsif converter_results[:job]
|
@@ -30,6 +30,7 @@ module ScoutApm
|
|
30
30
|
install_instrument(ScoutApm::Instruments::Moped)
|
31
31
|
install_instrument(ScoutApm::Instruments::Mongoid)
|
32
32
|
install_instrument(ScoutApm::Instruments::NetHttp)
|
33
|
+
install_instrument(ScoutApm::Instruments::Typhoeus)
|
33
34
|
install_instrument(ScoutApm::Instruments::HttpClient)
|
34
35
|
install_instrument(ScoutApm::Instruments::Memcached)
|
35
36
|
install_instrument(ScoutApm::Instruments::Redis)
|
@@ -17,46 +17,73 @@ module ScoutApm
|
|
17
17
|
@installed
|
18
18
|
end
|
19
19
|
|
20
|
+
def installed!
|
21
|
+
@installed = true
|
22
|
+
end
|
23
|
+
|
20
24
|
def install
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
if !defined?(::ActiveSupport)
|
26
|
+
return
|
27
|
+
end
|
28
|
+
|
29
|
+
# The block below runs with `self` equal to the ActionController::Base or ::API module, not this class we're in now. By saving an instance of ourselves into the `this` variable, we can continue accessing what we need.
|
30
|
+
this = self
|
27
31
|
|
32
|
+
ActiveSupport.on_load(:action_controller) do
|
33
|
+
if this.installed?
|
34
|
+
this.logger.info("Skipping ActionController - Already Ran")
|
35
|
+
next
|
36
|
+
else
|
37
|
+
this.logger.info("Instrumenting ActionController (on_load)")
|
38
|
+
this.installed!
|
39
|
+
end
|
40
|
+
|
41
|
+
# We previously instrumented ActionController::Metal, which missed
|
42
|
+
# before and after filter timing. Instrumenting Base includes those
|
43
|
+
# filters, at the expense of missing out on controllers that don't use
|
44
|
+
# the full Rails stack.
|
28
45
|
if defined?(::ActionController::Base)
|
29
|
-
logger.info "Instrumenting ActionController::Base"
|
46
|
+
this.logger.info "Instrumenting ActionController::Base"
|
30
47
|
::ActionController::Base.class_eval do
|
31
|
-
# include ScoutApm::Tracer
|
32
48
|
include ScoutApm::Instruments::ActionControllerBaseInstruments
|
33
49
|
end
|
34
50
|
end
|
35
51
|
|
36
52
|
if defined?(::ActionController::Metal)
|
37
|
-
logger.info "Instrumenting ActionController::Metal"
|
53
|
+
this.logger.info "Instrumenting ActionController::Metal"
|
38
54
|
::ActionController::Metal.class_eval do
|
39
55
|
include ScoutApm::Instruments::ActionControllerMetalInstruments
|
40
56
|
end
|
41
57
|
end
|
42
58
|
|
43
59
|
if defined?(::ActionController::API)
|
44
|
-
logger.info "Instrumenting ActionController::Api"
|
60
|
+
this.logger.info "Instrumenting ActionController::Api"
|
45
61
|
::ActionController::API.class_eval do
|
46
62
|
include ScoutApm::Instruments::ActionControllerAPIInstruments
|
47
63
|
end
|
48
64
|
end
|
49
65
|
end
|
50
66
|
|
51
|
-
|
52
|
-
# we can insert this multiple times into the ancestors
|
53
|
-
# stack. Otherwise it only exists the first time you include it
|
54
|
-
# (under Metal, instead of under API) and we miss instrumenting
|
55
|
-
# before_action callbacks
|
67
|
+
ScoutApm::Agent.instance.context.logger.info("Instrumenting ActionController (hook installed)")
|
56
68
|
end
|
57
69
|
|
70
|
+
# Returns a new anonymous module each time it is called. So
|
71
|
+
# we can insert this multiple times into the ancestors
|
72
|
+
# stack. Otherwise it only exists the first time you include it
|
73
|
+
# (under Metal, instead of under API) and we miss instrumenting
|
74
|
+
# before_action callbacks
|
58
75
|
def self.build_instrument_module
|
59
76
|
Module.new do
|
77
|
+
# Determine the URI of this request to capture. Overridable by users in their controller.
|
78
|
+
def scout_transaction_uri(config=ScoutApm::Agent.instance.context.config)
|
79
|
+
case config.value("uri_reporting")
|
80
|
+
when 'path'
|
81
|
+
request.path # strips off the query string for more security
|
82
|
+
else # default handles filtered params
|
83
|
+
request.filtered_path
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
60
87
|
def process_action(*args)
|
61
88
|
req = ScoutApm::RequestManager.lookup
|
62
89
|
current_layer = req.current_layer
|
@@ -72,7 +99,11 @@ module ScoutApm
|
|
72
99
|
# Don't start a new layer if ActionController::API or ActionController::Base handled it already.
|
73
100
|
super
|
74
101
|
else
|
75
|
-
|
102
|
+
begin
|
103
|
+
uri = scout_transaction_uri
|
104
|
+
req.annotate_request(:uri => uri)
|
105
|
+
rescue
|
106
|
+
end
|
76
107
|
|
77
108
|
# IP Spoofing Protection can throw an exception, just move on w/o remote ip
|
78
109
|
if agent_context.config.value('collect_remote_ip')
|
@@ -95,16 +126,6 @@ module ScoutApm
|
|
95
126
|
end
|
96
127
|
end
|
97
128
|
|
98
|
-
# Given an +ActionDispatch::Request+, formats the uri based on config settings.
|
99
|
-
# XXX: Don't lookup context like this - find a way to pass it through
|
100
|
-
def self.scout_transaction_uri(request, config=ScoutApm::Agent.instance.context.config)
|
101
|
-
case config.value("uri_reporting")
|
102
|
-
when 'path'
|
103
|
-
request.path # strips off the query string for more security
|
104
|
-
else # default handles filtered params
|
105
|
-
request.filtered_path
|
106
|
-
end
|
107
|
-
end
|
108
129
|
end
|
109
130
|
|
110
131
|
module ActionControllerMetalInstruments
|
@@ -75,25 +75,34 @@ module ScoutApm
|
|
75
75
|
end
|
76
76
|
|
77
77
|
module ActionViewPartialRendererInstruments
|
78
|
-
|
78
|
+
# In Rails 6, the signature changed to pass the view & template args directly, as opposed to through the instance var
|
79
|
+
# New signature is: def render_partial(view, template)
|
80
|
+
def render_partial(*args, **kwargs)
|
79
81
|
req = ScoutApm::RequestManager.lookup
|
80
82
|
|
81
|
-
|
83
|
+
maybe_template = args[1]
|
84
|
+
|
85
|
+
template_name = @template.virtual_path rescue nil # Works on Rails 3.2 -> end of Rails 5 series
|
86
|
+
template_name ||= maybe_template.virtual_path rescue nil # Works on Rails 6 -> 6.0.3
|
82
87
|
template_name ||= "Unknown Partial"
|
83
|
-
layer_name = template_name + "/Rendering"
|
84
88
|
|
89
|
+
layer_name = template_name + "/Rendering"
|
85
90
|
layer = ScoutApm::Layer.new("View", layer_name)
|
86
91
|
layer.subscopable!
|
87
92
|
|
88
93
|
begin
|
89
94
|
req.start_layer(layer)
|
90
|
-
|
95
|
+
if ScoutApm::Agent.instance.context.environment.supports_kwarg_delegation?
|
96
|
+
super(*args, **kwargs)
|
97
|
+
else
|
98
|
+
super(*args)
|
99
|
+
end
|
91
100
|
ensure
|
92
101
|
req.stop_layer
|
93
102
|
end
|
94
103
|
end
|
95
104
|
|
96
|
-
def collection_with_template(*args)
|
105
|
+
def collection_with_template(*args, **kwargs)
|
97
106
|
req = ScoutApm::RequestManager.lookup
|
98
107
|
|
99
108
|
template_name = @template.virtual_path rescue "Unknown Collection"
|
@@ -105,7 +114,11 @@ module ScoutApm
|
|
105
114
|
|
106
115
|
begin
|
107
116
|
req.start_layer(layer)
|
108
|
-
|
117
|
+
if ScoutApm::Agent.instance.context.environment.supports_kwarg_delegation?
|
118
|
+
super(*args, **kwargs)
|
119
|
+
else
|
120
|
+
super(*args)
|
121
|
+
end
|
109
122
|
ensure
|
110
123
|
req.stop_layer
|
111
124
|
end
|
@@ -113,7 +126,7 @@ module ScoutApm
|
|
113
126
|
end
|
114
127
|
|
115
128
|
module ActionViewTemplateRendererInstruments
|
116
|
-
def render_template(*args)
|
129
|
+
def render_template(*args, **kwargs)
|
117
130
|
req = ScoutApm::RequestManager.lookup
|
118
131
|
|
119
132
|
template_name = args[0].virtual_path rescue "Unknown"
|
@@ -125,7 +138,7 @@ module ScoutApm
|
|
125
138
|
|
126
139
|
begin
|
127
140
|
req.start_layer(layer)
|
128
|
-
super(*args)
|
141
|
+
super(*args, **kwargs)
|
129
142
|
ensure
|
130
143
|
req.stop_layer
|
131
144
|
end
|
@@ -82,15 +82,8 @@ module ScoutApm
|
|
82
82
|
|
83
83
|
# Install #log tracing
|
84
84
|
if Utils::KlassHelper.defined?("ActiveRecord::ConnectionAdapters::AbstractAdapter")
|
85
|
-
|
86
|
-
|
87
|
-
::ActiveRecord::ConnectionAdapters::AbstractAdapter.include(Tracer)
|
88
|
-
else
|
89
|
-
::ActiveRecord::ConnectionAdapters::AbstractAdapter.module_eval do
|
90
|
-
include ::ScoutApm::Instruments::ActiveRecordAliasMethodInstruments
|
91
|
-
include ::ScoutApm::Tracer
|
92
|
-
end
|
93
|
-
end
|
85
|
+
::ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(ActiveRecordInstruments)
|
86
|
+
::ActiveRecord::ConnectionAdapters::AbstractAdapter.include(Tracer)
|
94
87
|
end
|
95
88
|
|
96
89
|
if Utils::KlassHelper.defined?("ActiveRecord::Base")
|
@@ -172,20 +165,12 @@ module ScoutApm
|
|
172
165
|
# to the real SQL, and an AR generated "name" for the Query
|
173
166
|
#
|
174
167
|
################################################################################
|
175
|
-
|
176
|
-
|
177
|
-
module ActiveRecordAliasMethodInstruments
|
178
|
-
def self.included(instrumented_class)
|
168
|
+
module ActiveRecordInstruments
|
169
|
+
def self.prepended(instrumented_class)
|
179
170
|
ScoutApm::Agent.instance.context.logger.info "Instrumenting #{instrumented_class.inspect}"
|
180
|
-
instrumented_class.class_eval do
|
181
|
-
unless instrumented_class.method_defined?(:log_without_scout_instruments)
|
182
|
-
alias_method :log_without_scout_instruments, :log
|
183
|
-
alias_method :log, :log_with_scout_instruments
|
184
|
-
end
|
185
|
-
end
|
186
171
|
end
|
187
172
|
|
188
|
-
def
|
173
|
+
def log(*args, &block)
|
189
174
|
# Extract data from the arguments
|
190
175
|
sql, name = args
|
191
176
|
metric_name = Utils::ActiveRecordMetricName.new(sql, name)
|
@@ -216,7 +201,7 @@ module ScoutApm
|
|
216
201
|
end
|
217
202
|
current_layer.desc.merge(desc)
|
218
203
|
|
219
|
-
|
204
|
+
super(*args, &block)
|
220
205
|
|
221
206
|
# OR: Start a new layer, we didn't pick up instrumentation earlier in the stack.
|
222
207
|
else
|
@@ -224,7 +209,7 @@ module ScoutApm
|
|
224
209
|
layer.desc = desc
|
225
210
|
req.start_layer(layer)
|
226
211
|
begin
|
227
|
-
|
212
|
+
super(*args, &block)
|
228
213
|
ensure
|
229
214
|
req.stop_layer
|
230
215
|
end
|
@@ -323,14 +308,18 @@ module ScoutApm
|
|
323
308
|
end
|
324
309
|
end
|
325
310
|
|
326
|
-
def find_by_sql_with_scout_instruments(*args, &block)
|
311
|
+
def find_by_sql_with_scout_instruments(*args, **kwargs, &block)
|
327
312
|
req = ScoutApm::RequestManager.lookup
|
328
313
|
layer = ScoutApm::Layer.new("ActiveRecord", Utils::ActiveRecordMetricName::DEFAULT_METRIC)
|
329
314
|
layer.annotate_layer(:ignorable => true)
|
330
315
|
req.start_layer(layer)
|
331
316
|
req.ignore_children!
|
332
317
|
begin
|
333
|
-
|
318
|
+
if ScoutApm::Agent.instance.context.environment.supports_kwarg_delegation?
|
319
|
+
find_by_sql_without_scout_instruments(*args, **kwargs, &block)
|
320
|
+
else
|
321
|
+
find_by_sql_without_scout_instruments(*args, &block)
|
322
|
+
end
|
334
323
|
ensure
|
335
324
|
req.acknowledge_children!
|
336
325
|
req.stop_layer
|
@@ -408,7 +397,7 @@ module ScoutApm
|
|
408
397
|
end
|
409
398
|
|
410
399
|
module ActiveRecordUpdateInstruments
|
411
|
-
def save(*args, &block)
|
400
|
+
def save(*args, **options, &block)
|
412
401
|
model = self.class.name
|
413
402
|
operation = self.persisted? ? "Update" : "Create"
|
414
403
|
|
@@ -418,14 +407,14 @@ module ScoutApm
|
|
418
407
|
req.start_layer(layer)
|
419
408
|
req.ignore_children!
|
420
409
|
begin
|
421
|
-
super(*args, &block)
|
410
|
+
super(*args, **options, &block)
|
422
411
|
ensure
|
423
412
|
req.acknowledge_children!
|
424
413
|
req.stop_layer
|
425
414
|
end
|
426
415
|
end
|
427
416
|
|
428
|
-
def save!(*args, &block)
|
417
|
+
def save!(*args, **options, &block)
|
429
418
|
model = self.class.name
|
430
419
|
operation = self.persisted? ? "Update" : "Create"
|
431
420
|
|
@@ -434,7 +423,7 @@ module ScoutApm
|
|
434
423
|
req.start_layer(layer)
|
435
424
|
req.ignore_children!
|
436
425
|
begin
|
437
|
-
super(*args, &block)
|
426
|
+
super(*args, **options, &block)
|
438
427
|
ensure
|
439
428
|
req.acknowledge_children!
|
440
429
|
req.stop_layer
|