newrelic_rpm 8.6.0 → 8.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +83 -3
- data/README.md +1 -1
- data/Rakefile +1 -1
- data/docker-compose.yml +1 -1
- data/lib/new_relic/agent/agent.rb +5 -2
- data/lib/new_relic/agent/autostart.rb +13 -10
- data/lib/new_relic/agent/configuration/default_source.rb +144 -42
- data/lib/new_relic/agent/configuration/environment_source.rb +2 -0
- data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +2 -2
- data/lib/new_relic/agent/instrumentation/active_merchant.rb +14 -0
- data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +10 -0
- data/lib/new_relic/agent/instrumentation/authlogic.rb +10 -0
- data/lib/new_relic/agent/instrumentation/data_mapper.rb +12 -0
- data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +19 -0
- data/lib/new_relic/agent/instrumentation/rack/helpers.rb +2 -0
- data/lib/new_relic/agent/instrumentation/rainbows_instrumentation.rb +11 -0
- data/lib/new_relic/agent/instrumentation/sidekiq.rb +15 -0
- data/lib/new_relic/agent/instrumentation/sinatra.rb +21 -11
- data/lib/new_relic/agent/instrumentation/sunspot.rb +10 -0
- data/lib/new_relic/agent/instrumentation/thread/chain.rb +24 -0
- data/lib/new_relic/agent/instrumentation/thread/instrumentation.rb +27 -0
- data/lib/new_relic/agent/instrumentation/thread/prepend.rb +22 -0
- data/lib/new_relic/agent/instrumentation/thread.rb +20 -0
- data/lib/new_relic/agent/pipe_service.rb +1 -2
- data/lib/new_relic/agent/stats.rb +48 -23
- data/lib/new_relic/agent/tracer.rb +14 -1
- data/lib/new_relic/agent/transaction/abstract_segment.rb +2 -1
- data/lib/new_relic/agent/transaction/tracing.rb +8 -3
- data/lib/new_relic/agent/transaction.rb +24 -4
- data/lib/new_relic/agent/transaction_error_primitive.rb +2 -0
- data/lib/new_relic/agent/transaction_metrics.rb +5 -4
- data/lib/new_relic/agent/vm/mri_vm.rb +13 -1
- data/lib/new_relic/control/instrumentation.rb +31 -0
- data/lib/new_relic/dependency_detection.rb +1 -1
- data/lib/new_relic/language_support.rb +17 -0
- data/lib/new_relic/local_environment.rb +2 -0
- data/lib/new_relic/supportability_helper.rb +1 -0
- data/lib/new_relic/traced_thread.rb +36 -0
- data/lib/new_relic/version.rb +1 -1
- data/lib/tasks/config.rake +11 -3
- data/newrelic.yml +12 -1
- data/newrelic_rpm.gemspec +5 -2
- metadata +12 -3
@@ -13,6 +13,16 @@ DependencyDetection.defer do
|
|
13
13
|
|
14
14
|
executes do
|
15
15
|
::NewRelic::Agent.logger.info 'Installing Authlogic instrumentation'
|
16
|
+
deprecation_msg = 'The instrumentation for Authlogic is deprecated. ' \
|
17
|
+
'It will be removed in version 9.0.0.' \
|
18
|
+
|
19
|
+
::NewRelic::Agent.logger.log_once(
|
20
|
+
:warn,
|
21
|
+
:deprecated_authlogic,
|
22
|
+
deprecation_msg
|
23
|
+
)
|
24
|
+
|
25
|
+
::NewRelic::Agent.record_metric("Supportability/Deprecated/Authlogic", 1)
|
16
26
|
end
|
17
27
|
|
18
28
|
executes do
|
@@ -15,6 +15,18 @@ DependencyDetection.defer do
|
|
15
15
|
executes do
|
16
16
|
::NewRelic::Agent.logger.info 'Installing DataMapper instrumentation'
|
17
17
|
require 'new_relic/agent/datastores/metric_helper'
|
18
|
+
|
19
|
+
deprecation_msg = 'The instrumentation for DataMapper is deprecated. ' \
|
20
|
+
'It will be removed in version 9.0.0.' \
|
21
|
+
'Visit https://docs.newrelic.com/docs/apm/agents/ruby-agent/getting-started/ruby-agent-requirements-supported-frameworks ' \
|
22
|
+
'to learn about supported gems.'
|
23
|
+
|
24
|
+
::NewRelic::Agent.logger.log_once(
|
25
|
+
:warn,
|
26
|
+
:deprecated_datamapper,
|
27
|
+
deprecation_msg
|
28
|
+
)
|
29
|
+
::NewRelic::Agent.record_metric("Supportability/Deprecated/DataMapper", 1)
|
18
30
|
end
|
19
31
|
|
20
32
|
executes do
|
@@ -93,4 +93,23 @@ DependencyDetection.defer do
|
|
93
93
|
chain_instrument ::NewRelic::Agent::Instrumentation::DelayedJob::Chain
|
94
94
|
end
|
95
95
|
end
|
96
|
+
|
97
|
+
executes do
|
98
|
+
next unless delayed_job_version < Gem::Version.new('4.1.0')
|
99
|
+
deprecation_msg = 'Instrumentation for DelayedJob versions below 4.1.0 is deprecated.' \
|
100
|
+
'It will stop being monitored in version 9.0.0. ' \
|
101
|
+
'Please upgrade your DelayedJob version to continue receiving full support. ' \
|
102
|
+
|
103
|
+
::NewRelic::Agent.logger.log_once(
|
104
|
+
:warn,
|
105
|
+
:deprecated_delayed_job_version,
|
106
|
+
deprecation_msg
|
107
|
+
)
|
108
|
+
|
109
|
+
::NewRelic::Agent.record_metric("Supportability/Deprecated/DelayedJob", 1)
|
110
|
+
end
|
111
|
+
|
112
|
+
def delayed_job_version
|
113
|
+
Gem.loaded_specs['delayed_job'].version if Gem.loaded_specs['delayed_job']
|
114
|
+
end
|
96
115
|
end
|
@@ -20,6 +20,8 @@ module NewRelic::Agent::Instrumentation
|
|
20
20
|
return false unless defined? ::Puma::Const::PUMA_VERSION
|
21
21
|
|
22
22
|
version = Gem::Version.new(::Puma::Const::PUMA_VERSION)
|
23
|
+
# TODO: MAJOR VERSION - update min_version to 3.9.0
|
24
|
+
# min_version = Gem::Version.new('3.9.0')
|
23
25
|
min_version = Gem::Version.new('2.12.0')
|
24
26
|
version >= min_version
|
25
27
|
end
|
@@ -12,6 +12,17 @@ DependencyDetection.defer do
|
|
12
12
|
executes do
|
13
13
|
::NewRelic::Agent.logger.info 'Installing Rainbows instrumentation'
|
14
14
|
::NewRelic::Agent.logger.info 'Detected Rainbows, please see additional documentation: https://newrelic.com/docs/troubleshooting/im-using-unicorn-and-i-dont-see-any-data'
|
15
|
+
|
16
|
+
deprecation_msg = 'The dispatcher rainbows is deprecated. It will be removed ' \
|
17
|
+
'in version 9.0.0. Please use a supported dispatcher instead. ' \
|
18
|
+
'Visit https://docs.newrelic.com/docs/apm/agents/ruby-agent/getting-started/ruby-agent-requirements-supported-frameworks for options.'
|
19
|
+
|
20
|
+
::NewRelic::Agent.logger.log_once(
|
21
|
+
:warn,
|
22
|
+
:deprecated_rainbows_dispatcher,
|
23
|
+
deprecation_msg
|
24
|
+
)
|
25
|
+
::NewRelic::Agent.record_metric("Supportability/Deprecated/Rainbows", 1)
|
15
26
|
end
|
16
27
|
|
17
28
|
executes do
|
@@ -99,4 +99,19 @@ DependencyDetection.defer do
|
|
99
99
|
end
|
100
100
|
end
|
101
101
|
end
|
102
|
+
|
103
|
+
executes do
|
104
|
+
next unless Gem::Version.new(Sidekiq::VERSION) < Gem::Version.new('5.0.0')
|
105
|
+
deprecation_msg = 'Instrumentation for Sidekiq versions below 5.0.0 is deprecated.' \
|
106
|
+
'They will stop being monitored in version 9.0.0. ' \
|
107
|
+
'Please upgrade your Sidekiq version to continue receiving full support. '
|
108
|
+
|
109
|
+
::NewRelic::Agent.logger.log_once(
|
110
|
+
:warn,
|
111
|
+
:deprecated_sidekiq_version,
|
112
|
+
deprecation_msg
|
113
|
+
)
|
114
|
+
|
115
|
+
::NewRelic::Agent.record_metric("Supportability/Deprecated/Sidekiq", 1)
|
116
|
+
end
|
102
117
|
end
|
@@ -32,18 +32,28 @@ DependencyDetection.defer do
|
|
32
32
|
end
|
33
33
|
|
34
34
|
executes do
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
prepend_instrument ::Sinatra::Base.singleton_class, NewRelic::Agent::Instrumentation::Sinatra::Build::Prepend
|
42
|
-
else
|
43
|
-
chain_instrument NewRelic::Agent::Instrumentation::Sinatra::Build::Chain
|
44
|
-
end
|
35
|
+
# These requires are inside an executes block because they require rack, and
|
36
|
+
# we can't be sure that rack is available when this file is first required.
|
37
|
+
require 'new_relic/rack/agent_hooks'
|
38
|
+
require 'new_relic/rack/browser_monitoring'
|
39
|
+
if use_prepend?
|
40
|
+
prepend_instrument ::Sinatra::Base.singleton_class, NewRelic::Agent::Instrumentation::Sinatra::Build::Prepend
|
45
41
|
else
|
46
|
-
|
42
|
+
chain_instrument NewRelic::Agent::Instrumentation::Sinatra::Build::Chain
|
47
43
|
end
|
48
44
|
end
|
45
|
+
|
46
|
+
executes do
|
47
|
+
next unless Gem::Version.new(Sinatra::VERSION) < Gem::Version.new('2.0.0')
|
48
|
+
deprecation_msg = 'The Ruby Agent is dropping support for Sinatra versions below 2.0.0 ' \
|
49
|
+
'in version 9.0.0. Please upgrade your Sinatra version to continue receiving full compatibility. ' \
|
50
|
+
|
51
|
+
::NewRelic::Agent.logger.log_once(
|
52
|
+
:warn,
|
53
|
+
:deprecated_sinatra_version,
|
54
|
+
deprecation_msg
|
55
|
+
)
|
56
|
+
|
57
|
+
::NewRelic::Agent.record_metric("Supportability/Deprecated/Sinatra", 1)
|
58
|
+
end
|
49
59
|
end
|
@@ -11,6 +11,16 @@ DependencyDetection.defer do
|
|
11
11
|
|
12
12
|
executes do
|
13
13
|
::NewRelic::Agent.logger.info 'Installing Rails Sunspot instrumentation'
|
14
|
+
deprecation_msg = 'The instrumentation for Sunspot is deprecated.' \
|
15
|
+
' It will be removed in version 9.0.0.' \
|
16
|
+
|
17
|
+
::NewRelic::Agent.logger.log_once(
|
18
|
+
:warn,
|
19
|
+
:deprecated_sunspot,
|
20
|
+
deprecation_msg
|
21
|
+
)
|
22
|
+
|
23
|
+
::NewRelic::Agent.record_metric("Supportability/Deprecated/Sunspot", 1)
|
14
24
|
end
|
15
25
|
|
16
26
|
executes do
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
4
|
+
|
5
|
+
require_relative 'instrumentation'
|
6
|
+
|
7
|
+
module NewRelic::Agent::Instrumentation
|
8
|
+
module MonitoredThread
|
9
|
+
module Chain
|
10
|
+
def self.instrument!
|
11
|
+
::Thread.class_eval do
|
12
|
+
include NewRelic::Agent::Instrumentation::MonitoredThread
|
13
|
+
|
14
|
+
alias_method :initialize_without_new_relic, :initialize
|
15
|
+
|
16
|
+
def initialize(*args, &block)
|
17
|
+
traced_block = add_thread_tracing(*args, &block)
|
18
|
+
initialize_with_newrelic_tracing { initialize_without_new_relic(*args, &traced_block) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
4
|
+
|
5
|
+
module NewRelic
|
6
|
+
module Agent
|
7
|
+
module Instrumentation
|
8
|
+
module MonitoredThread
|
9
|
+
attr_reader :nr_parent_thread_id
|
10
|
+
|
11
|
+
def initialize_with_newrelic_tracing
|
12
|
+
@nr_parent_thread_id = ::Thread.current.object_id
|
13
|
+
yield
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_thread_tracing(*args, &block)
|
17
|
+
return block if skip_tracing?
|
18
|
+
NewRelic::Agent::Tracer.thread_block_with_current_transaction(*args, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def skip_tracing?
|
22
|
+
!NewRelic::Agent.config[:'instrumentation.thread.tracing']
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
4
|
+
|
5
|
+
require_relative 'instrumentation'
|
6
|
+
|
7
|
+
module NewRelic
|
8
|
+
module Agent
|
9
|
+
module Instrumentation
|
10
|
+
module MonitoredThread
|
11
|
+
module Prepend
|
12
|
+
include NewRelic::Agent::Instrumentation::MonitoredThread
|
13
|
+
|
14
|
+
def initialize(*args, &block)
|
15
|
+
traced_block = add_thread_tracing(*args, &block)
|
16
|
+
initialize_with_newrelic_tracing { super(*args, &traced_block) }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
4
|
+
|
5
|
+
require_relative 'thread/chain'
|
6
|
+
require_relative 'thread/prepend'
|
7
|
+
|
8
|
+
DependencyDetection.defer do
|
9
|
+
named :thread
|
10
|
+
|
11
|
+
executes do
|
12
|
+
::NewRelic::Agent.logger.info 'Installing Thread Instrumentation'
|
13
|
+
|
14
|
+
if use_prepend?
|
15
|
+
prepend_instrument ::Thread, ::NewRelic::Agent::Instrumentation::MonitoredThread::Prepend
|
16
|
+
else
|
17
|
+
chain_instrument ::NewRelic::Agent::Instrumentation::MonitoredThread::Chain
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -10,8 +10,7 @@ module NewRelic
|
|
10
10
|
|
11
11
|
def initialize(channel_id)
|
12
12
|
@channel_id = channel_id
|
13
|
-
@collector = NewRelic::Control::Server.new(:
|
14
|
-
:port => 0)
|
13
|
+
@collector = NewRelic::Control::Server.new({name: 'parent', port: 0})
|
15
14
|
@pipe = NewRelic::Agent::PipeChannelManager.channels[@channel_id]
|
16
15
|
if @pipe && @pipe.parent_pid != $$
|
17
16
|
@pipe.after_fork_in_child
|
@@ -4,6 +4,8 @@
|
|
4
4
|
module NewRelic
|
5
5
|
module Agent
|
6
6
|
class Stats
|
7
|
+
SKIP_MARSHALLING = [:@lock]
|
8
|
+
|
7
9
|
attr_accessor :call_count
|
8
10
|
attr_accessor :min_call_time
|
9
11
|
attr_accessor :max_call_time
|
@@ -12,6 +14,7 @@ module NewRelic
|
|
12
14
|
attr_accessor :sum_of_squares
|
13
15
|
|
14
16
|
def initialize
|
17
|
+
@lock = Mutex.new
|
15
18
|
reset
|
16
19
|
end
|
17
20
|
|
@@ -34,12 +37,14 @@ module NewRelic
|
|
34
37
|
end
|
35
38
|
|
36
39
|
def merge!(other)
|
37
|
-
@
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
@lock.synchronize do
|
41
|
+
@min_call_time = other.min_call_time if min_time_less?(other)
|
42
|
+
@max_call_time = other.max_call_time if other.max_call_time > max_call_time
|
43
|
+
@total_call_time += other.total_call_time
|
44
|
+
@total_exclusive_time += other.total_exclusive_time
|
45
|
+
@sum_of_squares += other.sum_of_squares
|
46
|
+
@call_count += other.call_count
|
47
|
+
end
|
43
48
|
self
|
44
49
|
end
|
45
50
|
|
@@ -78,13 +83,15 @@ module NewRelic
|
|
78
83
|
# will aggregate all data points collected over a specified period and upload
|
79
84
|
# its data to the NewRelic server
|
80
85
|
def record_data_point(value, exclusive_time = value)
|
81
|
-
@
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
86
|
+
@lock.synchronize do
|
87
|
+
@call_count += 1
|
88
|
+
@total_call_time += value
|
89
|
+
@min_call_time = value if value < @min_call_time || @call_count == 1
|
90
|
+
@max_call_time = value if value > @max_call_time
|
91
|
+
@total_exclusive_time += exclusive_time
|
92
|
+
|
93
|
+
@sum_of_squares += (value * value)
|
94
|
+
end
|
88
95
|
self
|
89
96
|
end
|
90
97
|
|
@@ -92,7 +99,7 @@ module NewRelic
|
|
92
99
|
|
93
100
|
# increments the call_count by one
|
94
101
|
def increment_count(value = 1)
|
95
|
-
@call_count += value
|
102
|
+
@lock.synchronize { @call_count += value }
|
96
103
|
end
|
97
104
|
|
98
105
|
# Concerned about implicit usage of inspect relying on stats format, so
|
@@ -122,17 +129,35 @@ module NewRelic
|
|
122
129
|
alias_method :apdex_f, :total_exclusive_time
|
123
130
|
|
124
131
|
def record_apdex(bucket, apdex_t)
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
132
|
+
@lock.synchronize do
|
133
|
+
case bucket
|
134
|
+
when :apdex_s then @call_count += 1
|
135
|
+
when :apdex_t then @total_call_time += 1
|
136
|
+
when :apdex_f then @total_exclusive_time += 1
|
137
|
+
end
|
138
|
+
if apdex_t
|
139
|
+
@min_call_time = apdex_t
|
140
|
+
@max_call_time = apdex_t
|
141
|
+
else
|
142
|
+
::NewRelic::Agent.logger.warn("Attempted to set apdex_t to #{apdex_t.inspect}, backtrace = #{caller.join("\n")}")
|
143
|
+
end
|
129
144
|
end
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
145
|
+
end
|
146
|
+
|
147
|
+
# Override marshalling methods to exclude @lock from being included in marshalled data
|
148
|
+
def marshal_dump
|
149
|
+
instance_variables.each_with_object({}) do |name, instance_copy|
|
150
|
+
next if SKIP_MARSHALLING.include?(name)
|
151
|
+
instance_copy[name] = instance_variable_get(name)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def marshal_load(marshalled_data)
|
156
|
+
marshalled_data.each do |name, value|
|
157
|
+
instance_variable_set(name, value) unless SKIP_MARSHALLING.include?(name)
|
135
158
|
end
|
159
|
+
# since the lock is excluded when marshalling, create a new lock when loading marshalled data
|
160
|
+
@lock = Mutex.new
|
136
161
|
end
|
137
162
|
|
138
163
|
protected
|
@@ -405,6 +405,19 @@ module NewRelic
|
|
405
405
|
|
406
406
|
alias_method :tl_clear, :clear_state
|
407
407
|
|
408
|
+
def thread_block_with_current_transaction(*args, &block)
|
409
|
+
current_txn = ::Thread.current[:newrelic_tracer_state].current_transaction if ::Thread.current[:newrelic_tracer_state]
|
410
|
+
Proc.new do
|
411
|
+
begin
|
412
|
+
NewRelic::Agent::Tracer.state.current_transaction = current_txn
|
413
|
+
segment = NewRelic::Agent::Tracer.start_segment(name: "Ruby/Thread/#{::Thread.current.object_id}")
|
414
|
+
block.call(*args) if block.respond_to?(:call)
|
415
|
+
ensure
|
416
|
+
segment.finish if segment
|
417
|
+
end
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
408
421
|
private
|
409
422
|
|
410
423
|
def start_and_add_segment segment, parent = nil
|
@@ -445,7 +458,7 @@ module NewRelic
|
|
445
458
|
end
|
446
459
|
|
447
460
|
# Current transaction stack
|
448
|
-
|
461
|
+
attr_accessor :current_transaction
|
449
462
|
|
450
463
|
# Execution tracing on current thread
|
451
464
|
attr_accessor :untraced
|
@@ -20,13 +20,14 @@ module NewRelic
|
|
20
20
|
# after its parent. We will use the optimized exclusive duration
|
21
21
|
# calculation in all other cases.
|
22
22
|
#
|
23
|
-
attr_reader :start_time, :end_time, :duration, :exclusive_duration, :guid
|
23
|
+
attr_reader :start_time, :end_time, :duration, :exclusive_duration, :guid, :starting_thread_id
|
24
24
|
attr_accessor :name, :parent, :children_time, :transaction, :transaction_name
|
25
25
|
attr_writer :record_metrics, :record_scoped_metric, :record_on_finish
|
26
26
|
attr_reader :noticed_error
|
27
27
|
|
28
28
|
def initialize name = nil, start_time = nil
|
29
29
|
@name = name
|
30
|
+
@starting_thread_id = ::Thread.current.object_id
|
30
31
|
@transaction_name = nil
|
31
32
|
@transaction = nil
|
32
33
|
@guid = NewRelic::Agent::GuidGenerator.generate_guid
|
@@ -6,7 +6,7 @@ module NewRelic
|
|
6
6
|
module Agent
|
7
7
|
class Transaction
|
8
8
|
module Tracing
|
9
|
-
attr_reader :
|
9
|
+
attr_reader :current_segment_by_thread
|
10
10
|
|
11
11
|
def async?
|
12
12
|
@async ||= false
|
@@ -23,7 +23,7 @@ module NewRelic
|
|
23
23
|
def add_segment segment, parent = nil
|
24
24
|
segment.transaction = self
|
25
25
|
segment.parent = parent || current_segment
|
26
|
-
|
26
|
+
set_current_segment segment
|
27
27
|
if @segments.length < segment_limit
|
28
28
|
@segments << segment
|
29
29
|
else
|
@@ -34,7 +34,12 @@ module NewRelic
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def segment_complete segment
|
37
|
-
|
37
|
+
# if parent was in another thread, remove the current_segment entry for this thread
|
38
|
+
if segment.parent && segment.parent.starting_thread_id != ::Thread.current.object_id
|
39
|
+
remove_current_segment_by_thread_id(::Thread.current.object_id)
|
40
|
+
else
|
41
|
+
set_current_segment segment.parent
|
42
|
+
end
|
38
43
|
end
|
39
44
|
|
40
45
|
def segment_limit
|
@@ -217,7 +217,8 @@ module NewRelic
|
|
217
217
|
|
218
218
|
def initialize(category, options)
|
219
219
|
@nesting_max_depth = 0
|
220
|
-
@
|
220
|
+
@current_segment_by_thread = {}
|
221
|
+
@current_segment_lock = Mutex.new
|
221
222
|
@segments = []
|
222
223
|
|
223
224
|
self.default_name = options[:transaction_name]
|
@@ -261,6 +262,25 @@ module NewRelic
|
|
261
262
|
end
|
262
263
|
end
|
263
264
|
|
265
|
+
def parent_thread_id
|
266
|
+
::Thread.current.nr_parent_thread_id if ::Thread.current.respond_to?(:nr_parent_thread_id)
|
267
|
+
end
|
268
|
+
|
269
|
+
def current_segment
|
270
|
+
current_thread_id = ::Thread.current.object_id
|
271
|
+
return current_segment_by_thread[current_thread_id] if current_segment_by_thread[current_thread_id]
|
272
|
+
return current_segment_by_thread[parent_thread_id] if current_segment_by_thread[parent_thread_id]
|
273
|
+
current_segment_by_thread[@starting_thread_id]
|
274
|
+
end
|
275
|
+
|
276
|
+
def set_current_segment(new_segment)
|
277
|
+
@current_segment_lock.synchronize { current_segment_by_thread[::Thread.current.object_id] = new_segment }
|
278
|
+
end
|
279
|
+
|
280
|
+
def remove_current_segment_by_thread_id(id)
|
281
|
+
@current_segment_lock.synchronize { current_segment_by_thread.delete(id) }
|
282
|
+
end
|
283
|
+
|
264
284
|
def distributed_tracer
|
265
285
|
@distributed_tracer ||= DistributedTracer.new(self)
|
266
286
|
end
|
@@ -719,9 +739,9 @@ module NewRelic
|
|
719
739
|
# Do not call this. Invoke the class method instead.
|
720
740
|
def notice_error(error, options = {}) # :nodoc:
|
721
741
|
# Only the last error is kept
|
722
|
-
if
|
723
|
-
|
724
|
-
options[:span_id] =
|
742
|
+
if current_segment
|
743
|
+
current_segment.notice_error(error, expected: options[:expected])
|
744
|
+
options[:span_id] = current_segment.guid
|
725
745
|
end
|
726
746
|
|
727
747
|
if @exceptions[error]
|
@@ -63,6 +63,8 @@ module NewRelic
|
|
63
63
|
append_cat payload, attrs
|
64
64
|
DistributedTraceAttributes.copy_to_hash payload, attrs
|
65
65
|
PayloadMetricMapping.append_mapped_metrics payload[:metrics], attrs
|
66
|
+
else
|
67
|
+
attrs[PRIORITY_KEY] = rand.round(NewRelic::PRIORITY_PRECISION)
|
66
68
|
end
|
67
69
|
|
68
70
|
attrs
|
@@ -13,6 +13,7 @@ module NewRelic
|
|
13
13
|
DEFAULT_PROC = Proc.new { |hash, name| hash[name] = NewRelic::Agent::Stats.new }
|
14
14
|
|
15
15
|
def initialize
|
16
|
+
@lock = Mutex.new
|
16
17
|
@unscoped = Hash.new(&DEFAULT_PROC)
|
17
18
|
@scoped = Hash.new(&DEFAULT_PROC)
|
18
19
|
end
|
@@ -42,11 +43,11 @@ module NewRelic
|
|
42
43
|
end
|
43
44
|
|
44
45
|
def each_unscoped
|
45
|
-
@unscoped.each { |name, stats| yield name, stats }
|
46
|
+
@lock.synchronize { @unscoped.each { |name, stats| yield name, stats } }
|
46
47
|
end
|
47
48
|
|
48
49
|
def each_scoped
|
49
|
-
@scoped.each { |name, stats| yield name, stats }
|
50
|
+
@lock.synchronize { @scoped.each { |name, stats| yield name, stats } }
|
50
51
|
end
|
51
52
|
|
52
53
|
def _record_metrics(names, value, aux, target, &blk)
|
@@ -54,10 +55,10 @@ module NewRelic
|
|
54
55
|
case names
|
55
56
|
when Array
|
56
57
|
names.each do |name|
|
57
|
-
target[name].record(value, aux, &blk)
|
58
|
+
@lock.synchronize { target[name].record(value, aux, &blk) }
|
58
59
|
end
|
59
60
|
else
|
60
|
-
target[names].record(value, aux, &blk)
|
61
|
+
@lock.synchronize { target[names].record(value, aux, &blk) }
|
61
62
|
end
|
62
63
|
end
|
63
64
|
end
|
@@ -49,7 +49,19 @@ module NewRelic
|
|
49
49
|
end
|
50
50
|
|
51
51
|
if supports?(:constant_cache_invalidations)
|
52
|
-
snap.constant_cache_invalidations =
|
52
|
+
snap.constant_cache_invalidations = gather_constant_cache_invalidations
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def gather_constant_cache_invalidations
|
57
|
+
# Ruby >= 3.2 uses :constant_cache
|
58
|
+
# see: https://github.com/ruby/ruby/pull/5433 and https://bugs.ruby-lang.org/issues/18589
|
59
|
+
# TODO: now that 3.2+ provides more granual cache invalidation data, should we report it instead of summing?
|
60
|
+
if RUBY_VERSION >= '3.2.0'
|
61
|
+
RubyVM.stat[:constant_cache].values.sum
|
62
|
+
# Ruby < 3.2 uses :global_constant_state
|
63
|
+
else
|
64
|
+
RubyVM.stat[:global_constant_state]
|
53
65
|
end
|
54
66
|
end
|
55
67
|
|
@@ -62,9 +62,40 @@ module NewRelic
|
|
62
62
|
File.join(instrumentation_path, app.to_s, '*.rb')
|
63
63
|
@instrumentation_files.each { |pattern| load_instrumentation_files pattern }
|
64
64
|
DependencyDetection.detect!
|
65
|
+
ruby_22_deprecation
|
66
|
+
rails_32_deprecation
|
65
67
|
::NewRelic::Agent.logger.info "Finished instrumentation"
|
66
68
|
end
|
67
69
|
end
|
70
|
+
|
71
|
+
def rails_32_deprecation
|
72
|
+
return unless defined?(Rails::VERSION) && Gem::Version.new(Rails::VERSION::STRING) <= Gem::Version.new('3.2')
|
73
|
+
deprecation_msg = 'The Ruby Agent is dropping support for Rails 3.2 ' \
|
74
|
+
'in a future major release. Please upgrade your Rails version to continue receiving support. ' \
|
75
|
+
|
76
|
+
Agent.logger.log_once(
|
77
|
+
:warn,
|
78
|
+
:deprecated_rails_version,
|
79
|
+
deprecation_msg
|
80
|
+
)
|
81
|
+
|
82
|
+
::NewRelic::Agent.record_metric("Supportability/Deprecated/Rails32", 1)
|
83
|
+
end
|
84
|
+
|
85
|
+
def ruby_22_deprecation
|
86
|
+
return unless RUBY_VERSION <= '2.2.0'
|
87
|
+
deprecation_msg = 'The Ruby Agent is dropping support for Ruby 2.2 ' \
|
88
|
+
'in version 9.0.0. Please upgrade your Ruby version to continue receiving support. ' \
|
89
|
+
|
90
|
+
::NewRelic::Agent.logger.log_once(
|
91
|
+
:warn,
|
92
|
+
:deprecated_ruby_version,
|
93
|
+
deprecation_msg
|
94
|
+
)
|
95
|
+
|
96
|
+
::NewRelic::Agent.record_metric("Supportability/Deprecated/Ruby22", 1)
|
97
|
+
end
|
98
|
+
|
68
99
|
include Instrumentation
|
69
100
|
end
|
70
101
|
end
|
@@ -146,7 +146,7 @@ module DependencyDetection
|
|
146
146
|
!(disabled_configured? || deprecated_disabled_configured?)
|
147
147
|
end
|
148
148
|
|
149
|
-
# TODO:
|
149
|
+
# TODO: MAJOR VERSION
|
150
150
|
# will only return true if a disabled key is found and is truthy
|
151
151
|
def deprecated_disabled_configured?
|
152
152
|
return false if self.name.nil?
|
@@ -34,6 +34,23 @@ module NewRelic
|
|
34
34
|
RUBY_ENGINE == 'jruby'
|
35
35
|
end
|
36
36
|
|
37
|
+
# TODO: OLD RUBIES - RUBY_VERSION < 2.6
|
38
|
+
#
|
39
|
+
# Ruby 2.6 introduced an improved version of `Object.const_get` that
|
40
|
+
# respects the full namespace of the input and doesn't just grab the first
|
41
|
+
# constant matching the string to the right of the last '::'.
|
42
|
+
# Once we drop support for Ruby 2.5 and below, the only value this custom
|
43
|
+
# method will provide beyond `Object.const_get` itself is to automatically
|
44
|
+
# catch NameError.
|
45
|
+
#
|
46
|
+
# see: https://github.com/rails/rails/commit/7057ccf6565c1cb5354c1906880119276a9d15c0
|
47
|
+
#
|
48
|
+
# With Ruby 2.6+, this method can be defined like so:
|
49
|
+
# def constantize(constant_as_string_or_symbol)
|
50
|
+
# Object.const_get(constant_as_string_or_symbol)
|
51
|
+
# rescue NameError
|
52
|
+
# end
|
53
|
+
#
|
37
54
|
def constantize(const_name)
|
38
55
|
const_name.to_s.sub(/\A::/, '').split('::').inject(Object) do |namespace, name|
|
39
56
|
begin
|