scout_apm 5.7.1 → 6.0.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.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +2 -0
- data/CHANGELOG.markdown +21 -1
- data/README.markdown +20 -8
- data/gems/instruments.gemfile +1 -0
- data/lib/scout_apm/auto_instrument/instruction_sequence.rb +2 -1
- data/lib/scout_apm/auto_instrument/parser.rb +150 -2
- data/lib/scout_apm/auto_instrument/prism.rb +357 -0
- data/lib/scout_apm/auto_instrument/rails.rb +9 -155
- data/lib/scout_apm/auto_instrument/requirements.rb +11 -0
- data/lib/scout_apm/background_job_integrations/delayed_job.rb +25 -1
- data/lib/scout_apm/background_job_integrations/faktory.rb +7 -1
- data/lib/scout_apm/background_job_integrations/good_job.rb +7 -1
- data/lib/scout_apm/background_job_integrations/legacy_sneakers.rb +7 -1
- data/lib/scout_apm/background_job_integrations/que.rb +7 -1
- data/lib/scout_apm/background_job_integrations/shoryuken.rb +7 -1
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +89 -1
- data/lib/scout_apm/background_job_integrations/sneakers.rb +7 -1
- data/lib/scout_apm/background_job_integrations/solid_queue.rb +19 -1
- data/lib/scout_apm/config.rb +32 -7
- data/lib/scout_apm/context.rb +3 -1
- data/lib/scout_apm/error_service/error_record.rb +5 -1
- data/lib/scout_apm/instrument_manager.rb +2 -0
- data/lib/scout_apm/instruments/http_client.rb +10 -0
- data/lib/scout_apm/instruments/httpx.rb +119 -0
- data/lib/scout_apm/instruments/opensearch.rb +131 -0
- data/lib/scout_apm/limited_layer.rb +5 -2
- data/lib/scout_apm/logger.rb +1 -1
- data/lib/scout_apm/sampling.rb +25 -13
- data/lib/scout_apm/server_integrations/puma.rb +21 -4
- data/lib/scout_apm/version.rb +1 -1
- data/lib/scout_apm.rb +9 -4
- data/test/unit/auto_instrument/controller-ast.prism.txt +1015 -0
- data/test/unit/auto_instrument/controller-instrumented.rb +36 -11
- data/test/unit/auto_instrument/controller.rb +25 -0
- data/test/unit/auto_instrument/hash_shorthand_controller-instrumented.rb +28 -10
- data/test/unit/auto_instrument/hash_shorthand_controller.rb +19 -1
- data/test/unit/auto_instrument_test.rb +7 -1
- data/test/unit/background_job_integrations/faktory_test.rb +109 -0
- data/test/unit/background_job_integrations/shoryuken_test.rb +81 -0
- data/test/unit/background_job_integrations/sidekiq_test.rb +38 -0
- data/test/unit/config_test.rb +14 -0
- data/test/unit/error_service/error_buffer_test.rb +32 -0
- data/test/unit/error_test.rb +3 -3
- data/test/unit/ignored_uris_test.rb +7 -0
- data/test/unit/instruments/http_client_test.rb +0 -2
- data/test/unit/instruments/httpx_test.rb +78 -0
- data/test/unit/limited_layer_test.rb +4 -4
- data/test/unit/sampling_test.rb +10 -10
- metadata +10 -3
- data/lib/scout_apm/utils/time.rb +0 -12
- /data/test/unit/auto_instrument/{controller-ast.txt → controller-ast.parser.txt} +0 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
module ScoutApm
|
|
2
|
+
module Instruments
|
|
3
|
+
class HTTPX
|
|
4
|
+
attr_reader :context
|
|
5
|
+
|
|
6
|
+
def initialize(context)
|
|
7
|
+
@context = context
|
|
8
|
+
@installed = false
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def logger
|
|
12
|
+
context.logger
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def installed?
|
|
16
|
+
@installed
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def install(prepend:)
|
|
20
|
+
if defined?(::HTTPX) && defined?(::HTTPX::Session)
|
|
21
|
+
@installed = true
|
|
22
|
+
|
|
23
|
+
logger.info "Instrumenting HTTPX"
|
|
24
|
+
|
|
25
|
+
::HTTPX::Session.send(:prepend, HTTPXInstrumentationPrepend)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
module HTTPXInstrumentationPrepend
|
|
30
|
+
def request(*args, **params)
|
|
31
|
+
verb, desc = determine_verb_and_desc(*args, **params)
|
|
32
|
+
|
|
33
|
+
layer = ScoutApm::Layer.new("HTTP", verb)
|
|
34
|
+
layer.desc = desc
|
|
35
|
+
|
|
36
|
+
req = ScoutApm::RequestManager.lookup
|
|
37
|
+
req.start_layer(layer)
|
|
38
|
+
|
|
39
|
+
begin
|
|
40
|
+
super(*args, **params)
|
|
41
|
+
ensure
|
|
42
|
+
req.stop_layer
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
# See the following for various argument patterns:
|
|
49
|
+
# https://gitlab.com/os85/httpx/-/blob/v1.6.3/lib/httpx/session.rb?ref_type=tags#L87
|
|
50
|
+
def determine_verb_and_desc(*args, **params)
|
|
51
|
+
# Pattern 1: session.request(req1) or session.request(req1, req2, ...)
|
|
52
|
+
if args.first.is_a?(::HTTPX::Request)
|
|
53
|
+
if args.length > 1
|
|
54
|
+
return args.first.verb.to_s.upcase, "#{args.length} requests"
|
|
55
|
+
else
|
|
56
|
+
return args.first.verb.to_s.upcase, scout_url_desc(args.first.uri)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Pattern 2: session.request("GET", "https://server.org/a")
|
|
61
|
+
# Pattern 3: session.request("GET", ["https://server.org/a", "https://server.org/b"])
|
|
62
|
+
# Pattern 4: session.request("POST", ["https://server.org/a"], form: { ... })
|
|
63
|
+
# Pattern 5: session.request("GET", ["https://..."], headers: { ... })
|
|
64
|
+
if args.first.is_a?(String) || args.first.is_a?(Symbol)
|
|
65
|
+
verb = args.first.to_s.upcase
|
|
66
|
+
|
|
67
|
+
if args[1].is_a?(String)
|
|
68
|
+
return verb, scout_url_desc(args[1])
|
|
69
|
+
elsif args[1].is_a?(Array)
|
|
70
|
+
return verb, scout_url_desc(args[1][0]) unless args[1].length > 1
|
|
71
|
+
return verb, "#{args[1].length} requests"
|
|
72
|
+
else
|
|
73
|
+
return verb, ""
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Pattern 6: session.request(["GET", "https://..."], ["GET", "https://..."])
|
|
78
|
+
# Pattern 7: session.request(["POST", "https://...", form: {...}], ["GET", "https://..."])
|
|
79
|
+
if args.first.is_a?(Array)
|
|
80
|
+
if args.length > 1
|
|
81
|
+
verb = args.first[0].to_s.upcase rescue "REQUEST"
|
|
82
|
+
return verb, "#{args.length} requests"
|
|
83
|
+
elsif args.first.length >= 2
|
|
84
|
+
verb = args.first[0].to_s.upcase rescue "REQUEST"
|
|
85
|
+
url = args.first[1]
|
|
86
|
+
return verb, scout_url_desc(url)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
return "REQUEST", ""
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def scout_url_desc(uri)
|
|
94
|
+
max_length = ScoutApm::Agent.instance.context.config.value('instrument_http_url_length')
|
|
95
|
+
uri_str = uri.to_s
|
|
96
|
+
|
|
97
|
+
# URI object
|
|
98
|
+
if uri.respond_to?(:host) && uri.respond_to?(:path)
|
|
99
|
+
path = uri.path.to_s
|
|
100
|
+
path = "/" if path.empty?
|
|
101
|
+
result = "#{uri.host}#{path.split('?').first}"
|
|
102
|
+
# String URL
|
|
103
|
+
elsif uri_str =~ %r{^https?://([^/]+)(/[^?]*)?}
|
|
104
|
+
host = $1
|
|
105
|
+
path = $2 || "/"
|
|
106
|
+
result = "#{host}#{path}"
|
|
107
|
+
else
|
|
108
|
+
# Fallback
|
|
109
|
+
result = uri_str.split('?').first
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
result[0..(max_length - 1)]
|
|
113
|
+
rescue => e
|
|
114
|
+
""
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen_string_literal: false
|
|
2
|
+
|
|
3
|
+
module ScoutApm
|
|
4
|
+
module Instruments
|
|
5
|
+
class OpenSearch
|
|
6
|
+
attr_reader :context
|
|
7
|
+
|
|
8
|
+
def initialize(context)
|
|
9
|
+
@context = context
|
|
10
|
+
@installed = false
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def logger
|
|
14
|
+
context.logger
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def installed?
|
|
18
|
+
@installed
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def install(prepend:)
|
|
22
|
+
if defined?(::OpenSearch) &&
|
|
23
|
+
defined?(::OpenSearch::Transport) &&
|
|
24
|
+
defined?(::OpenSearch::Transport::Client)
|
|
25
|
+
|
|
26
|
+
@installed = true
|
|
27
|
+
|
|
28
|
+
logger.info "Instrumenting OpenSearch. Prepend: #{prepend}"
|
|
29
|
+
|
|
30
|
+
if prepend
|
|
31
|
+
::OpenSearch::Transport::Client.send(:include, ScoutApm::Tracer)
|
|
32
|
+
::OpenSearch::Transport::Client.send(:prepend, OpenSearchTransportClientInstrumentationPrepend)
|
|
33
|
+
else
|
|
34
|
+
::OpenSearch::Transport::Client.class_eval do
|
|
35
|
+
include ScoutApm::Tracer
|
|
36
|
+
|
|
37
|
+
def perform_request_with_scout_instruments(*args, &block)
|
|
38
|
+
name = _sanitize_name(args[1])
|
|
39
|
+
|
|
40
|
+
self.class.instrument("OpenSearch", name, :ignore_children => true) do
|
|
41
|
+
perform_request_without_scout_instruments(*args, &block)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
alias_method :perform_request_without_scout_instruments, :perform_request
|
|
46
|
+
alias_method :perform_request, :perform_request_with_scout_instruments
|
|
47
|
+
|
|
48
|
+
def _sanitize_name(path)
|
|
49
|
+
name = path.split("/").last.gsub(/^_/, '')
|
|
50
|
+
allowed_names = ["bench",
|
|
51
|
+
"bulk",
|
|
52
|
+
"count",
|
|
53
|
+
"exists",
|
|
54
|
+
"explain",
|
|
55
|
+
"field_stats",
|
|
56
|
+
"health",
|
|
57
|
+
"mget",
|
|
58
|
+
"mlt",
|
|
59
|
+
"mpercolate",
|
|
60
|
+
"msearch",
|
|
61
|
+
"mtermvectors",
|
|
62
|
+
"percolate",
|
|
63
|
+
"query",
|
|
64
|
+
"scroll",
|
|
65
|
+
"search_shards",
|
|
66
|
+
"source",
|
|
67
|
+
"suggest",
|
|
68
|
+
"template",
|
|
69
|
+
"termvectors",
|
|
70
|
+
"update",
|
|
71
|
+
"search", ]
|
|
72
|
+
|
|
73
|
+
if allowed_names.include?(name)
|
|
74
|
+
name
|
|
75
|
+
else
|
|
76
|
+
"Unknown"
|
|
77
|
+
end
|
|
78
|
+
rescue
|
|
79
|
+
"Unknown"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
module OpenSearchTransportClientInstrumentationPrepend
|
|
88
|
+
def perform_request(*args, &block)
|
|
89
|
+
name = _sanitize_name(args[1])
|
|
90
|
+
|
|
91
|
+
self.class.instrument("OpenSearch", name, :ignore_children => true) do
|
|
92
|
+
super(*args, &block)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def _sanitize_name(path)
|
|
97
|
+
name = path.split("/").last.gsub(/^_/, '')
|
|
98
|
+
allowed_names = ["bench",
|
|
99
|
+
"bulk",
|
|
100
|
+
"count",
|
|
101
|
+
"exists",
|
|
102
|
+
"explain",
|
|
103
|
+
"field_stats",
|
|
104
|
+
"health",
|
|
105
|
+
"mget",
|
|
106
|
+
"mlt",
|
|
107
|
+
"mpercolate",
|
|
108
|
+
"msearch",
|
|
109
|
+
"mtermvectors",
|
|
110
|
+
"percolate",
|
|
111
|
+
"query",
|
|
112
|
+
"scroll",
|
|
113
|
+
"search_shards",
|
|
114
|
+
"source",
|
|
115
|
+
"suggest",
|
|
116
|
+
"template",
|
|
117
|
+
"termvectors",
|
|
118
|
+
"update",
|
|
119
|
+
"search", ]
|
|
120
|
+
|
|
121
|
+
if allowed_names.include?(name)
|
|
122
|
+
name
|
|
123
|
+
else
|
|
124
|
+
"Unknown"
|
|
125
|
+
end
|
|
126
|
+
rescue
|
|
127
|
+
"Unknown"
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -21,10 +21,13 @@ module ScoutApm
|
|
|
21
21
|
@total_layers += 1
|
|
22
22
|
|
|
23
23
|
@total_call_time += layer.total_call_time
|
|
24
|
-
|
|
24
|
+
# For limited layers, exclusive time should equal total time since limited layers
|
|
25
|
+
# report no children. As such, we need to consider all absorbed time as exclusive.
|
|
26
|
+
@total_exclusive_time += layer.total_call_time
|
|
25
27
|
|
|
26
28
|
@total_allocations += layer.total_allocations
|
|
27
|
-
|
|
29
|
+
# Same logic applies to allocations
|
|
30
|
+
@total_exclusive_allocations += layer.total_allocations
|
|
28
31
|
end
|
|
29
32
|
|
|
30
33
|
def total_call_time
|
data/lib/scout_apm/logger.rb
CHANGED
|
@@ -145,7 +145,7 @@ module ScoutApm
|
|
|
145
145
|
def call(severity, time, progname, msg)
|
|
146
146
|
# since STDOUT isn't exclusive like the scout_apm.log file, apply a prefix.
|
|
147
147
|
# XXX: Pass in context to the formatter
|
|
148
|
-
"[#{
|
|
148
|
+
"[#{time.strftime("%m/%d/%y %H:%M:%S %z")} #{ScoutApm::Agent.instance.context.environment.hostname} (#{$$})] #{severity} : #{msg}\n"
|
|
149
149
|
end
|
|
150
150
|
end
|
|
151
151
|
|
data/lib/scout_apm/sampling.rb
CHANGED
|
@@ -8,7 +8,8 @@ module ScoutApm
|
|
|
8
8
|
# jobs matched explicitly by name
|
|
9
9
|
|
|
10
10
|
# for now still support old config key ('ignore') for backwards compatibility
|
|
11
|
-
|
|
11
|
+
raw_ignore = config.value_present?('ignore') ? config.value('ignore') : config.value('ignore_endpoints')
|
|
12
|
+
@ignore_endpoints = IgnoredUris.new(raw_ignore) unless raw_ignore.blank?
|
|
12
13
|
@sample_endpoints = individual_sample_to_hash(config.value('sample_endpoints'))
|
|
13
14
|
@endpoint_sample_rate = config.value('endpoint_sample_rate')
|
|
14
15
|
|
|
@@ -34,20 +35,20 @@ module ScoutApm
|
|
|
34
35
|
if transaction.job?
|
|
35
36
|
job_name = transaction.layer_finder.job.name
|
|
36
37
|
rate = job_sample_rate(job_name)
|
|
37
|
-
return
|
|
38
|
+
return downsample?(rate) unless rate.nil?
|
|
38
39
|
return true if ignore_job?(job_name)
|
|
39
|
-
return
|
|
40
|
+
return downsample?(@job_sample_rate) unless @job_sample_rate.nil?
|
|
40
41
|
elsif transaction.web?
|
|
41
42
|
uri = transaction.annotations[:uri]
|
|
42
43
|
rate = web_sample_rate(uri)
|
|
43
|
-
return
|
|
44
|
+
return downsample?(rate) unless rate.nil?
|
|
44
45
|
return true if ignore_uri?(uri)
|
|
45
|
-
return
|
|
46
|
+
return downsample?(@endpoint_sample_rate) unless @endpoint_sample_rate.nil?
|
|
46
47
|
end
|
|
47
48
|
|
|
48
49
|
# global sample check
|
|
49
50
|
if @global_sample_rate
|
|
50
|
-
return
|
|
51
|
+
return downsample?(@global_sample_rate)
|
|
51
52
|
end
|
|
52
53
|
|
|
53
54
|
false # don't drop the request
|
|
@@ -59,17 +60,14 @@ module ScoutApm
|
|
|
59
60
|
sample_hash = {}
|
|
60
61
|
sampling_config.each do |sample|
|
|
61
62
|
path, _, rate = sample.rpartition(':')
|
|
62
|
-
sample_hash[path] = rate
|
|
63
|
+
sample_hash[path] = coerce_to_rate(rate)
|
|
63
64
|
end
|
|
64
65
|
sample_hash
|
|
65
66
|
end
|
|
66
67
|
|
|
67
68
|
def ignore_uri?(uri)
|
|
68
69
|
return false if @ignore_endpoints.blank?
|
|
69
|
-
@ignore_endpoints.
|
|
70
|
-
return true if uri.start_with?(prefix)
|
|
71
|
-
end
|
|
72
|
-
false
|
|
70
|
+
@ignore_endpoints.ignore?(uri)
|
|
73
71
|
end
|
|
74
72
|
|
|
75
73
|
def web_sample_rate(uri)
|
|
@@ -90,8 +88,9 @@ module ScoutApm
|
|
|
90
88
|
@sample_jobs.fetch(job_name, nil)
|
|
91
89
|
end
|
|
92
90
|
|
|
93
|
-
def
|
|
94
|
-
|
|
91
|
+
def downsample?(rate)
|
|
92
|
+
# Should we drop this request based on the sample rate?
|
|
93
|
+
rand > rate
|
|
95
94
|
end
|
|
96
95
|
|
|
97
96
|
private
|
|
@@ -100,5 +99,18 @@ module ScoutApm
|
|
|
100
99
|
ScoutApm::Agent.instance.logger
|
|
101
100
|
end
|
|
102
101
|
|
|
102
|
+
def coerce_to_rate(val)
|
|
103
|
+
# Analogous to Config::SampleRateCoercion
|
|
104
|
+
v = val.to_f
|
|
105
|
+
# Anything above 1 is assumed a percentage for backwards compat, so convert to a decimal
|
|
106
|
+
if v > 1
|
|
107
|
+
v = v / 100
|
|
108
|
+
end
|
|
109
|
+
if v < 0 || v > 1
|
|
110
|
+
logger.warn("Sample rates must be between 0 and 1. You passed in #{val.inspect}, which we interpreted as #{v}. Clamping.")
|
|
111
|
+
v = v.clamp(0, 1)
|
|
112
|
+
end
|
|
113
|
+
v
|
|
114
|
+
end
|
|
103
115
|
end
|
|
104
116
|
end
|
|
@@ -53,11 +53,28 @@ module ScoutApm
|
|
|
53
53
|
#
|
|
54
54
|
def install
|
|
55
55
|
old = ::Puma.cli_config.options.user_options[:before_worker_boot] || []
|
|
56
|
-
new = Array(old) + [Proc.new do
|
|
57
|
-
logger.info "Installing Puma worker loop."
|
|
58
|
-
ScoutApm::Agent.instance.start_background_worker
|
|
59
|
-
end]
|
|
60
56
|
|
|
57
|
+
hook =
|
|
58
|
+
if Gem::Version.new(::Puma::Const::PUMA_VERSION) < Gem::Version.new("7.0.0")
|
|
59
|
+
# Puma < 7 uses a raw block
|
|
60
|
+
Proc.new do
|
|
61
|
+
logger.info "Installing Puma worker loop."
|
|
62
|
+
ScoutApm::Agent.instance.start_background_worker
|
|
63
|
+
end
|
|
64
|
+
else
|
|
65
|
+
# Puma >= 7 uses the structured hook format:
|
|
66
|
+
# https://github.com/puma/puma/commit/b16790f7a3c1bfc1847225a58897c9fbd19981f8
|
|
67
|
+
{
|
|
68
|
+
block: Proc.new {
|
|
69
|
+
logger.info "Installing Puma worker loop."
|
|
70
|
+
ScoutApm::Agent.instance.start_background_worker
|
|
71
|
+
},
|
|
72
|
+
id: nil,
|
|
73
|
+
cluster_only: false
|
|
74
|
+
}
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
new = Array.new(old) + [hook]
|
|
61
78
|
::Puma.cli_config.options[:before_worker_boot] = new
|
|
62
79
|
rescue
|
|
63
80
|
logger.warn "Unable to install Puma worker loop: #{$!.message}"
|
data/lib/scout_apm/version.rb
CHANGED
data/lib/scout_apm.rb
CHANGED
|
@@ -84,6 +84,7 @@ require 'scout_apm/histogram'
|
|
|
84
84
|
require 'scout_apm/instruments/net_http'
|
|
85
85
|
require 'scout_apm/instruments/http_client'
|
|
86
86
|
require 'scout_apm/instruments/http'
|
|
87
|
+
require 'scout_apm/instruments/httpx'
|
|
87
88
|
require 'scout_apm/instruments/typhoeus'
|
|
88
89
|
require 'scout_apm/instruments/moped'
|
|
89
90
|
require 'scout_apm/instruments/mongoid'
|
|
@@ -92,6 +93,7 @@ require 'scout_apm/instruments/redis'
|
|
|
92
93
|
require 'scout_apm/instruments/redis5'
|
|
93
94
|
require 'scout_apm/instruments/influxdb'
|
|
94
95
|
require 'scout_apm/instruments/elasticsearch'
|
|
96
|
+
require 'scout_apm/instruments/opensearch'
|
|
95
97
|
require 'scout_apm/instruments/active_record'
|
|
96
98
|
require 'scout_apm/instruments/action_controller_rails_2'
|
|
97
99
|
require 'scout_apm/instruments/action_controller_rails_3_rails4'
|
|
@@ -118,7 +120,6 @@ require 'scout_apm/utils/installed_gems'
|
|
|
118
120
|
require 'scout_apm/utils/klass_helper'
|
|
119
121
|
require 'scout_apm/utils/scm'
|
|
120
122
|
require 'scout_apm/utils/sql_sanitizer'
|
|
121
|
-
require 'scout_apm/utils/time'
|
|
122
123
|
require 'scout_apm/utils/unique_id'
|
|
123
124
|
require 'scout_apm/utils/numbers'
|
|
124
125
|
require 'scout_apm/utils/gzip_helper'
|
|
@@ -226,11 +227,15 @@ if defined?(Rails) && defined?(Rails::VERSION) && defined?(Rails::VERSION::MAJOR
|
|
|
226
227
|
# Attempt to start right away, this will work best for preloading apps, Unicorn & Puma & similar
|
|
227
228
|
ScoutApm::Agent.instance.install
|
|
228
229
|
|
|
229
|
-
if ScoutApm::Agent.instance.context.config.value("auto_instruments")
|
|
230
|
-
|
|
230
|
+
if ScoutApm::Agent.instance.context.config.value("auto_instruments") &&
|
|
231
|
+
ScoutApm::Agent.instance.should_load_instruments?
|
|
232
|
+
require 'scout_apm/auto_instrument/requirements'
|
|
233
|
+
if defined?(Prism) || defined?(Parser::TreeRewriter)
|
|
231
234
|
ScoutApm::Agent.instance.context.logger.debug("AutoInstruments is enabled.")
|
|
232
235
|
require 'scout_apm/auto_instrument'
|
|
233
|
-
else
|
|
236
|
+
else
|
|
237
|
+
# AutoInstruments is turned on, but we don't have the prerequisites to use it
|
|
238
|
+
# Prism should be available for Ruby >= 3.3.0
|
|
234
239
|
ScoutApm::Agent.instance.context.logger.debug("AutoInstruments is enabled, but Parser::TreeRewriter is missing. Update 'parser' gem to >= 2.5.0.")
|
|
235
240
|
end
|
|
236
241
|
else
|