newrelic_rpm 8.15.0 → 9.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -28
  3. data/.rubocop_todo.yml +41 -3
  4. data/CHANGELOG.md +191 -38
  5. data/CONTRIBUTING.md +1 -1
  6. data/README.md +3 -1
  7. data/bin/nrdebug +16 -16
  8. data/lib/new_relic/agent/agent_helpers/connect.rb +1 -1
  9. data/lib/new_relic/agent/agent_helpers/special_startup.rb +1 -2
  10. data/lib/new_relic/agent/attribute_filter.rb +0 -2
  11. data/lib/new_relic/agent/commands/thread_profiler_session.rb +3 -3
  12. data/lib/new_relic/agent/configuration/default_source.rb +139 -476
  13. data/lib/new_relic/agent/configuration/high_security_source.rb +0 -2
  14. data/lib/new_relic/agent/configuration/security_policy_source.rb +0 -16
  15. data/lib/new_relic/agent/database.rb +0 -14
  16. data/lib/new_relic/agent/distributed_tracing/cross_app_tracing.rb +1 -2
  17. data/lib/new_relic/agent/error_collector.rb +1 -1
  18. data/lib/new_relic/agent/error_filter.rb +3 -3
  19. data/lib/new_relic/agent/instrumentation/action_cable_subscriber.rb +6 -19
  20. data/lib/new_relic/agent/instrumentation/action_controller_other_subscriber.rb +39 -0
  21. data/lib/new_relic/agent/instrumentation/action_dispatch.rb +31 -0
  22. data/lib/new_relic/agent/instrumentation/action_dispatch_subscriber.rb +64 -0
  23. data/lib/new_relic/agent/instrumentation/action_mailbox.rb +30 -0
  24. data/lib/new_relic/agent/instrumentation/action_mailbox_subscriber.rb +33 -0
  25. data/lib/new_relic/agent/instrumentation/action_mailer.rb +30 -0
  26. data/lib/new_relic/agent/instrumentation/action_mailer_subscriber.rb +85 -0
  27. data/lib/new_relic/agent/instrumentation/action_view_subscriber.rb +7 -7
  28. data/lib/new_relic/agent/instrumentation/active_job.rb +15 -2
  29. data/lib/new_relic/agent/instrumentation/active_job_subscriber.rb +41 -0
  30. data/lib/new_relic/agent/instrumentation/active_storage.rb +4 -0
  31. data/lib/new_relic/agent/instrumentation/active_storage_subscriber.rb +2 -30
  32. data/lib/new_relic/agent/instrumentation/active_support.rb +21 -6
  33. data/lib/new_relic/agent/instrumentation/active_support_subscriber.rb +41 -0
  34. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +1 -1
  35. data/lib/new_relic/agent/instrumentation/custom_events.rb +12 -0
  36. data/lib/new_relic/agent/instrumentation/fiber/chain.rb +20 -0
  37. data/lib/new_relic/agent/instrumentation/fiber/instrumentation.rb +24 -0
  38. data/lib/new_relic/agent/instrumentation/fiber/prepend.rb +18 -0
  39. data/lib/new_relic/agent/instrumentation/fiber.rb +25 -0
  40. data/lib/new_relic/agent/instrumentation/grape.rb +1 -1
  41. data/lib/new_relic/agent/instrumentation/memcache.rb +2 -2
  42. data/lib/new_relic/agent/instrumentation/net_http.rb +1 -1
  43. data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +41 -0
  44. data/lib/new_relic/agent/instrumentation/rails_notifications/action_cable.rb +4 -4
  45. data/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb +13 -1
  46. data/lib/new_relic/agent/instrumentation/rake/instrumentation.rb +1 -8
  47. data/lib/new_relic/agent/instrumentation/rake.rb +1 -1
  48. data/lib/new_relic/agent/instrumentation/redis.rb +1 -1
  49. data/lib/new_relic/agent/instrumentation/resque.rb +1 -1
  50. data/lib/new_relic/agent/instrumentation/sequel.rb +4 -5
  51. data/lib/new_relic/agent/instrumentation/thread/instrumentation.rb +3 -7
  52. data/lib/new_relic/agent/monitors/cross_app_monitor.rb +0 -1
  53. data/lib/new_relic/agent/new_relic_service/security_policy_settings.rb +0 -1
  54. data/lib/new_relic/agent/new_relic_service.rb +1 -1
  55. data/lib/new_relic/agent/rules_engine/segment_terms_rule.rb +0 -1
  56. data/lib/new_relic/agent/samplers/delayed_job_sampler.rb +1 -1
  57. data/lib/new_relic/agent/tracer.rb +10 -1
  58. data/lib/new_relic/agent/transaction/abstract_segment.rb +2 -2
  59. data/lib/new_relic/agent/transaction/tracing.rb +2 -2
  60. data/lib/new_relic/agent/transaction.rb +17 -16
  61. data/lib/new_relic/agent.rb +1 -19
  62. data/lib/new_relic/cli/commands/install.rb +9 -9
  63. data/lib/new_relic/control/instance_methods.rb +1 -1
  64. data/lib/new_relic/local_environment.rb +0 -10
  65. data/lib/new_relic/supportability_helper.rb +0 -1
  66. data/lib/new_relic/version.rb +2 -2
  67. data/lib/newrelic_rpm.rb +1 -1
  68. data/lib/sequel/extensions/{newrelic_instrumentation.rb → new_relic_instrumentation.rb} +3 -3
  69. data/lib/sequel/plugins/{newrelic_instrumentation.rb → new_relic_instrumentation.rb} +3 -3
  70. data/lib/tasks/helpers/format.rb +1 -1
  71. data/lib/tasks/instrumentation_generator/instrumentation.thor +7 -10
  72. data/lib/tasks/instrumentation_generator/templates/Envfile.tt +1 -1
  73. data/newrelic.yml +15 -9
  74. data/newrelic_rpm.gemspec +17 -13
  75. data/test/agent_helper.rb +1 -1
  76. metadata +37 -14
  77. data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +0 -83
  78. data/lib/new_relic/agent/instrumentation/authlogic.rb +0 -33
  79. data/lib/new_relic/agent/instrumentation/data_mapper.rb +0 -215
  80. data/lib/new_relic/agent/instrumentation/rainbows_instrumentation.rb +0 -36
  81. data/lib/new_relic/agent/instrumentation/sunspot.rb +0 -41
@@ -11,8 +11,6 @@ module NewRelic
11
11
  def initialize(local_settings)
12
12
  super({
13
13
  :capture_params => false,
14
- :'resque.capture_params' => false,
15
- :'sidekiq.capture_params' => false,
16
14
  :'attributes.include' => [],
17
15
 
18
16
  :'transaction_tracer.record_sql' => record_sql_setting(local_settings, :'transaction_tracer.record_sql'),
@@ -191,22 +191,6 @@ module NewRelic
191
191
  disabled_value: false,
192
192
  permitted_fn: nil
193
193
  }
194
- ],
195
- "job_arguments" => [
196
- {
197
- option: :'resque.capture_params',
198
- supported: true,
199
- enabled_fn: method(:enabled?),
200
- disabled_value: false,
201
- permitted_fn: nil
202
- },
203
- {
204
- option: :'sidekiq.capture_params',
205
- supported: true,
206
- enabled_fn: method(:enabled?),
207
- disabled_value: false,
208
- permitted_fn: nil
209
- }
210
194
  ]
211
195
  }
212
196
 
@@ -7,20 +7,6 @@ require 'new_relic/agent/database/explain_plan_helpers'
7
7
  require 'new_relic/agent/database/obfuscator'
8
8
 
9
9
  module NewRelic
10
- # columns for a mysql explain plan
11
- MYSQL_EXPLAIN_COLUMNS = [
12
- "Id",
13
- "Select Type",
14
- "Table",
15
- "Type",
16
- "Possible Keys",
17
- "Key",
18
- "Key Length",
19
- "Ref",
20
- "Rows",
21
- "Extra"
22
- ].freeze
23
-
24
10
  module Agent
25
11
  module Database
26
12
  MAX_QUERY_LENGTH = 16384
@@ -166,8 +166,7 @@ module NewRelic
166
166
 
167
167
  def cross_application_tracer_enabled?
168
168
  !NewRelic::Agent.config[:"distributed_tracing.enabled"] &&
169
- (NewRelic::Agent.config[:"cross_application_tracer.enabled"] ||
170
- NewRelic::Agent.config[:cross_application_tracing])
169
+ NewRelic::Agent.config[:"cross_application_tracer.enabled"]
171
170
  end
172
171
 
173
172
  def obfuscator
@@ -26,7 +26,7 @@ module NewRelic
26
26
  @error_filter = NewRelic::Agent::ErrorFilter.new
27
27
 
28
28
  %w[
29
- ignore_errors ignore_classes ignore_messages ignore_status_codes
29
+ ignore_classes ignore_messages ignore_status_codes
30
30
  expected_classes expected_messages expected_status_codes
31
31
  ].each do |w|
32
32
  Agent.config.register_callback(:"error_collector.#{w}") do |value|
@@ -19,7 +19,7 @@ module NewRelic
19
19
 
20
20
  def load_all
21
21
  %i[
22
- ignore_errors ignore_classes ignore_messages ignore_status_codes
22
+ ignore_classes ignore_messages ignore_status_codes
23
23
  expected_classes expected_messages expected_status_codes
24
24
  ].each { |setting| load_from_config(setting) }
25
25
  end
@@ -31,7 +31,7 @@ module NewRelic
31
31
  return if new_value.nil? || (new_value.respond_to?(:empty?) && new_value.empty?)
32
32
 
33
33
  case setting.to_sym
34
- when :ignore_errors, :ignore_classes
34
+ when :ignore_classes
35
35
  new_value = new_value.split(',').map!(&:strip) if new_value.is_a?(String)
36
36
  errors = @ignore_classes = new_value
37
37
  when :ignore_messages
@@ -120,7 +120,7 @@ module NewRelic
120
120
 
121
121
  def log_filter(setting, errors)
122
122
  case setting
123
- when :ignore_errors, :ignore_classes
123
+ when :ignore_classes
124
124
  errors.each do |error|
125
125
  ::NewRelic::Agent.logger.debug("Ignoring errors of type '#{error}'")
126
126
  end
@@ -10,9 +10,7 @@ module NewRelic
10
10
  class ActionCableSubscriber < NotificationsSubscriber
11
11
  PERFORM_ACTION = 'perform_action.action_cable'.freeze
12
12
 
13
- def start(name, id, payload) # THREAD_LOCAL_ACCESS
14
- return unless state.is_execution_traced?
15
-
13
+ def start_segment(name, id, payload) # THREAD_LOCAL_ACCESS
16
14
  finishable = if name == PERFORM_ACTION
17
15
  Tracer.start_transaction_or_segment(
18
16
  name: transaction_name_from_payload(payload),
@@ -22,21 +20,6 @@ module NewRelic
22
20
  Tracer.start_segment(name: metric_name_from_payload(name, payload))
23
21
  end
24
22
  push_segment(id, finishable)
25
- rescue => e
26
- log_notification_error(e, name, 'start')
27
- end
28
-
29
- def finish(name, id, payload) # THREAD_LOCAL_ACCESS
30
- return unless state.is_execution_traced?
31
-
32
- if exception = exception_object(payload)
33
- NewRelic::Agent.notice_error(exception)
34
- end
35
-
36
- finishable = pop_segment(id)
37
- finishable.finish if finishable
38
- rescue => e
39
- log_notification_error(e, name, 'finish')
40
23
  end
41
24
 
42
25
  private
@@ -46,7 +29,11 @@ module NewRelic
46
29
  end
47
30
 
48
31
  def metric_name_from_payload(name, payload)
49
- "Ruby/ActionCable/#{payload[:channel_class]}/#{action_name(name)}"
32
+ "Ruby/ActionCable/#{metric_name(payload)}/#{action_name(name)}"
33
+ end
34
+
35
+ def metric_name(payload)
36
+ payload[:broadcasting] || payload[:channel_class]
50
37
  end
51
38
 
52
39
  DOT_ACTION_CABLE = '.action_cable'.freeze
@@ -0,0 +1,39 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ require 'new_relic/agent/instrumentation/notifications_subscriber'
6
+ require 'new_relic/agent/instrumentation/ignore_actions'
7
+ require 'new_relic/agent/parameter_filtering'
8
+
9
+ module NewRelic
10
+ module Agent
11
+ module Instrumentation
12
+ class ActionControllerOtherSubscriber < NotificationsSubscriber
13
+ def add_segment_params(segment, payload)
14
+ segment.params[:filter] = payload[:filter] if payload[:filter]
15
+ segment.params[:keys] = payload[:keys] if payload[:keys]
16
+ segment.params[:original_path] = payload[:request].original_fullpath if payload[:request]
17
+
18
+ if payload[:context]
19
+ segment.params[:action] = payload[:context][:action]
20
+ segment.params[:controller] = payload[:context][:controller]
21
+ end
22
+ end
23
+
24
+ def metric_name(name, payload)
25
+ controller_name = controller_name_for_metric(payload)
26
+ "Ruby/ActionController#{"/#{controller_name}" if controller_name}/#{name.gsub(/\.action_controller/, '')}"
27
+ end
28
+
29
+ def controller_name_for_metric(payload)
30
+ # redirect_to
31
+ return payload[:request].controller_class.controller_path if payload[:request] && payload[:request].controller_class
32
+
33
+ # unpermitted_parameters
34
+ ::NewRelic::LanguageSupport.constantize(payload[:context][:controller]).controller_path if payload[:context] && payload[:context][:controller]
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,31 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ require 'new_relic/agent/instrumentation/action_dispatch_subscriber'
6
+
7
+ DependencyDetection.defer do
8
+ named :action_dispatch
9
+
10
+ depends_on do
11
+ !NewRelic::Agent.config[:disable_action_dispatch]
12
+ end
13
+
14
+ depends_on do
15
+ defined?(ActiveSupport) &&
16
+ defined?(ActionDispatch) &&
17
+ defined?(ActionPack) &&
18
+ ActionPack.respond_to?(:gem_version) &&
19
+ ActionPack.gem_version >= Gem::Version.new('6.0.0') && # notifications for dispatch added in Rails 6
20
+ !NewRelic::Agent::Instrumentation::ActionDispatchSubscriber.subscribed?
21
+ end
22
+
23
+ executes do
24
+ NewRelic::Agent.logger.info('Installing ActionDispatch instrumentation')
25
+ end
26
+
27
+ executes do
28
+ ActiveSupport::Notifications.subscribe(/\A[^\.]+\.action_dispatch\z/,
29
+ NewRelic::Agent::Instrumentation::ActionDispatchSubscriber.new)
30
+ end
31
+ end
@@ -0,0 +1,64 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ require 'new_relic/agent/instrumentation/notifications_subscriber'
6
+
7
+ module NewRelic
8
+ module Agent
9
+ module Instrumentation
10
+ class ActionDispatchSubscriber < NotificationsSubscriber
11
+ def start(name, id, payload)
12
+ return unless state.is_execution_traced?
13
+
14
+ start_segment(name, id, payload)
15
+ rescue => e
16
+ log_notification_error(e, name, 'start')
17
+ end
18
+
19
+ def finish(name, id, payload)
20
+ return unless state.is_execution_traced?
21
+
22
+ finish_segment(id, payload)
23
+ rescue => e
24
+ log_notification_error(e, name, 'finish')
25
+ end
26
+
27
+ def start_segment(name, id, payload)
28
+ segment = Tracer.start_segment(name: metric_name(name, payload))
29
+ push_segment(id, segment)
30
+ end
31
+
32
+ def finish_segment(id, payload)
33
+ if segment = pop_segment(id)
34
+ if exception = exception_object(payload)
35
+ segment.notice_error(exception)
36
+ end
37
+ segment.finish
38
+ end
39
+ end
40
+
41
+ def metric_name(name, payload)
42
+ middleware = payload[:middleware]
43
+ method = method_from_name(name)
44
+ "Ruby/ActionDispatch/#{middleware}/#{method}"
45
+ end
46
+
47
+ PATTERN = /\A([^\.]+)\.action_dispatch\z/
48
+ UNKNOWN = 'unknown'.freeze
49
+
50
+ METHOD_NAME_MAPPING = Hash.new do |h, k|
51
+ if PATTERN =~ k
52
+ h[k] = $1
53
+ else
54
+ h[k] = UNKNOWN
55
+ end
56
+ end
57
+
58
+ def method_from_name(name)
59
+ METHOD_NAME_MAPPING[name]
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,30 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ require 'new_relic/agent/instrumentation/action_mailbox_subscriber'
6
+
7
+ DependencyDetection.defer do
8
+ named :action_mailbox
9
+
10
+ depends_on do
11
+ !NewRelic::Agent.config[:disable_action_mailbox]
12
+ end
13
+
14
+ depends_on do
15
+ defined?(ActiveSupport) &&
16
+ defined?(ActionMailbox) &&
17
+ ActionMailbox.respond_to?(:gem_version) && # 'require "action_mailbox"' doesn't require version...
18
+ ActionMailbox.gem_version >= Gem::Version.new('7.1.0.alpha') && # notifications added in Rails 7.1
19
+ !NewRelic::Agent::Instrumentation::ActionMailboxSubscriber.subscribed?
20
+ end
21
+
22
+ executes do
23
+ NewRelic::Agent.logger.info('Installing ActionMailbox instrumentation')
24
+ end
25
+
26
+ executes do
27
+ ActiveSupport::Notifications.subscribe(/\A[^\.]+\.action_mailbox\z/,
28
+ NewRelic::Agent::Instrumentation::ActionMailboxSubscriber.new)
29
+ end
30
+ end
@@ -0,0 +1,33 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ require 'new_relic/agent/instrumentation/notifications_subscriber'
6
+
7
+ module NewRelic
8
+ module Agent
9
+ module Instrumentation
10
+ class ActionMailboxSubscriber < NotificationsSubscriber
11
+ def metric_name(name, payload)
12
+ mailbox = payload[:mailbox].class.name
13
+ method = method_from_name(name)
14
+ "Ruby/ActionMailbox/#{mailbox}/#{method}"
15
+ end
16
+
17
+ PATTERN = /\A([^\.]*)\.action_mailbox\z/
18
+
19
+ METHOD_NAME_MAPPING = Hash.new do |h, k|
20
+ if PATTERN =~ k
21
+ h[k] = $1
22
+ else
23
+ h[k] = NewRelic::UNKNOWN
24
+ end
25
+ end
26
+
27
+ def method_from_name(name)
28
+ METHOD_NAME_MAPPING[name]
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,30 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ require 'new_relic/agent/instrumentation/action_mailer_subscriber'
6
+
7
+ DependencyDetection.defer do
8
+ named :action_mailer
9
+
10
+ depends_on do
11
+ !NewRelic::Agent.config[:disable_action_mailer]
12
+ end
13
+
14
+ depends_on do
15
+ defined?(ActiveSupport) &&
16
+ defined?(ActionMailer) &&
17
+ ActionMailer.respond_to?(:gem_version) &&
18
+ ActionMailer.gem_version >= Gem::Version.new('5.0') &&
19
+ !NewRelic::Agent::Instrumentation::ActionMailerSubscriber.subscribed?
20
+ end
21
+
22
+ executes do
23
+ NewRelic::Agent.logger.info('Installing ActionMailer instrumentation')
24
+ end
25
+
26
+ executes do
27
+ ActiveSupport::Notifications.subscribe(/\A(?:[^\.]+)\.action_mailer\z/,
28
+ NewRelic::Agent::Instrumentation::ActionMailerSubscriber.new)
29
+ end
30
+ end
@@ -0,0 +1,85 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ require 'new_relic/agent/instrumentation/notifications_subscriber'
6
+
7
+ module NewRelic
8
+ module Agent
9
+ module Instrumentation
10
+ # NOTE: as of v7.1.0.0.alpha, deliver.action_mailer will provide
11
+ # an empty payload hash ({}) to #start, so in this subscriber class
12
+ # we defer params population until #finish and start the segment with
13
+ # a temporary name that is later replaced
14
+ class ActionMailerSubscriber < NotificationsSubscriber
15
+ BASE_NAME = 'Ruby/ActionMailer'
16
+ PAYLOAD_KEYS = %i[action data key mailer message_id perform_deliveries subject]
17
+ PATTERN = /\A([^\.]+)\.action_mailer\z/
18
+ UNKNOWN_MAILER = %r{^#{BASE_NAME}/#{UNKNOWN}/}
19
+
20
+ METHOD_NAME_MAPPING = Hash.new do |h, k|
21
+ if PATTERN =~ k
22
+ h[k] = $1
23
+ else
24
+ h[k] = NewRelic::UNKNOWN
25
+ end
26
+ end
27
+
28
+ def start(name, id, payload)
29
+ return unless state.is_execution_traced?
30
+
31
+ start_segment(name, id, payload)
32
+ rescue => e
33
+ log_notification_error(e, name, 'start')
34
+ end
35
+
36
+ def finish(name, id, payload)
37
+ return unless state.is_execution_traced?
38
+
39
+ finish_segment(id, payload)
40
+ rescue => e
41
+ log_notification_error(e, name, 'finish')
42
+ end
43
+
44
+ private
45
+
46
+ def start_segment(name, id, payload)
47
+ segment = Tracer.start_segment(name: metric_name(name, payload))
48
+ push_segment(id, segment)
49
+ end
50
+
51
+ def finish_segment(id, payload)
52
+ segment = pop_segment(id)
53
+ return unless segment
54
+
55
+ if segment.name.match?(UNKNOWN_MAILER) && payload.key?(:mailer)
56
+ segment.name = segment.name.sub(UNKNOWN_MAILER, "#{BASE_NAME}/#{payload[:mailer]}/")
57
+ end
58
+
59
+ PAYLOAD_KEYS.each do |key|
60
+ segment.params[key] = payload[key] if payload.key?(key)
61
+ end
62
+
63
+ notice_exception(segment, payload)
64
+ segment.finish
65
+ end
66
+
67
+ def notice_exception(segment, payload)
68
+ if exception = exception_object(payload)
69
+ segment.notice_error(exception)
70
+ end
71
+ end
72
+
73
+ def metric_name(name, payload)
74
+ mailer = payload[:mailer] || UNKNOWN
75
+ method = method_from_name(name)
76
+ "#{BASE_NAME}/#{mailer}/#{method}"
77
+ end
78
+
79
+ def method_from_name(name)
80
+ METHOD_NAME_MAPPING[name]
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -10,28 +10,25 @@ module NewRelic
10
10
  module Agent
11
11
  module Instrumentation
12
12
  class ActionViewSubscriber < NotificationsSubscriber
13
- def start(name, id, payload) # THREAD_LOCAL_ACCESS
13
+ def start_segment(name, id, payload)
14
14
  parent = segment_stack[id].last
15
15
  metric_name = format_metric_name(name, payload, parent)
16
16
 
17
17
  event = ActionViewEvent.new(metric_name, payload[:identifier])
18
- if state.is_execution_traced? && recordable?(name, metric_name)
18
+
19
+ if recordable?(name, metric_name)
19
20
  event.finishable = Tracer.start_segment(name: metric_name)
20
21
  end
21
22
  push_segment(id, event)
22
- rescue => e
23
- log_notification_error(e, name, 'start')
24
23
  end
25
24
 
26
- def finish(name, id, payload)
25
+ def finish_segment(id, payload)
27
26
  if segment = pop_segment(id)
28
27
  if exception = exception_object(payload)
29
28
  segment.notice_error(exception)
30
29
  end
31
30
  segment.finish
32
31
  end
33
- rescue => e
34
- log_notification_error(e, name, 'finish')
35
32
  end
36
33
 
37
34
  def format_metric_name(event_name, payload, parent)
@@ -61,12 +58,15 @@ module NewRelic
61
58
  RENDER_TEMPLATE_EVENT_NAME = 'render_template.action_view'.freeze
62
59
  RENDER_PARTIAL_EVENT_NAME = 'render_partial.action_view'.freeze
63
60
  RENDER_COLLECTION_EVENT_NAME = 'render_collection.action_view'.freeze
61
+ RENDER_LAYOUT_EVENT_NAME = 'render_layout.action_view'.freeze
64
62
 
65
63
  def metric_action(name)
66
64
  case name
67
65
  when /#{RENDER_TEMPLATE_EVENT_NAME}$/o then 'Rendering'
68
66
  when RENDER_PARTIAL_EVENT_NAME then 'Partial'
69
67
  when RENDER_COLLECTION_EVENT_NAME then 'Partial'
68
+ when RENDER_LAYOUT_EVENT_NAME then 'Layout'
69
+ else NewRelic::UNKNOWN
70
70
  end
71
71
  end
72
72
 
@@ -12,7 +12,7 @@ DependencyDetection.defer do
12
12
  end
13
13
 
14
14
  executes do
15
- NewRelic::Agent.logger.info('Installing ActiveJob instrumentation')
15
+ NewRelic::Agent.logger.info('Installing base ActiveJob instrumentation')
16
16
 
17
17
  ActiveSupport.on_load(:active_job) do
18
18
  ActiveJob::Base.around_enqueue do |job, block|
@@ -26,6 +26,19 @@ DependencyDetection.defer do
26
26
  NewRelic::Agent::PrependSupportability.record_metrics_for(ActiveJob::Base)
27
27
  end
28
28
  end
29
+
30
+ executes do
31
+ if defined?(ActiveSupport) &&
32
+ ActiveJob.respond_to?(:gem_version) &&
33
+ ActiveJob.gem_version >= Gem::Version.new('6.0.0') &&
34
+ !NewRelic::Agent.config[:disable_activejob] &&
35
+ !NewRelic::Agent::Instrumentation::ActiveJobSubscriber.subscribed?
36
+ NewRelic::Agent.logger.info('Installing notifications based ActiveJob instrumentation')
37
+
38
+ ActiveSupport::Notifications.subscribe(/\A[^\.]+\.active_job\z/,
39
+ NewRelic::Agent::Instrumentation::ActiveJobSubscriber.new)
40
+ end
41
+ end
29
42
  end
30
43
 
31
44
  module NewRelic
@@ -58,7 +71,7 @@ module NewRelic
58
71
  end
59
72
 
60
73
  def self.run_in_trace(job, block, event)
61
- trace_execution_scoped("MessageBroker/#{adapter}/Queue/#{event}/Named/#{job.queue_name}",
74
+ trace_execution_scoped("ActiveJob/#{adapter.sub(/^ActiveJob::/, '')}/Queue/#{event}/Named/#{job.queue_name}",
62
75
  code_information: code_information_for_job(job)) do
63
76
  block.call
64
77
  end
@@ -0,0 +1,41 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ require 'new_relic/agent/instrumentation/notifications_subscriber'
6
+
7
+ module NewRelic
8
+ module Agent
9
+ module Instrumentation
10
+ class ActiveJobSubscriber < NotificationsSubscriber
11
+ PAYLOAD_KEYS = %i[adapter db_runtime error job wait]
12
+
13
+ def add_segment_params(segment, payload)
14
+ PAYLOAD_KEYS.each do |key|
15
+ segment.params[key] = payload[key] if payload.key?(key)
16
+ end
17
+ end
18
+
19
+ def metric_name(name, payload)
20
+ queue = payload[:job].queue_name
21
+ method = method_from_name(name)
22
+ "Ruby/ActiveJob/#{queue}/#{method}"
23
+ end
24
+
25
+ PATTERN = /\A([^\.]+)\.active_job\z/
26
+
27
+ METHOD_NAME_MAPPING = Hash.new do |h, k|
28
+ if PATTERN =~ k
29
+ h[k] = $1
30
+ else
31
+ h[k] = NewRelic::UNKNOWN
32
+ end
33
+ end
34
+
35
+ def method_from_name(name)
36
+ METHOD_NAME_MAPPING[name]
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -7,6 +7,10 @@ require 'new_relic/agent/instrumentation/active_storage_subscriber'
7
7
  DependencyDetection.defer do
8
8
  named :active_storage
9
9
 
10
+ depends_on do
11
+ !NewRelic::Agent.config[:disable_active_storage]
12
+ end
13
+
10
14
  depends_on do
11
15
  defined?(ActiveStorage) &&
12
16
  !NewRelic::Agent::Instrumentation::ActiveStorageSubscriber.subscribed?
@@ -8,36 +8,9 @@ module NewRelic
8
8
  module Agent
9
9
  module Instrumentation
10
10
  class ActiveStorageSubscriber < NotificationsSubscriber
11
- def start(name, id, payload)
12
- return unless state.is_execution_traced?
13
-
14
- start_segment(name, id, payload)
15
- rescue => e
16
- log_notification_error(e, name, 'start')
17
- end
18
-
19
- def finish(name, id, payload)
20
- return unless state.is_execution_traced?
21
-
22
- finish_segment(id, payload)
23
- rescue => e
24
- log_notification_error(e, name, 'finish')
25
- end
26
-
27
- def start_segment(name, id, payload)
28
- segment = Tracer.start_segment(name: metric_name(name, payload))
11
+ def add_segment_params(segment, payload)
29
12
  segment.params[:key] = payload[:key]
30
13
  segment.params[:exist] = payload[:exist] if payload.key?(:exist)
31
- push_segment(id, segment)
32
- end
33
-
34
- def finish_segment(id, payload)
35
- if segment = pop_segment(id)
36
- if exception = exception_object(payload)
37
- segment.notice_error(exception)
38
- end
39
- segment.finish
40
- end
41
14
  end
42
15
 
43
16
  def metric_name(name, payload)
@@ -47,13 +20,12 @@ module NewRelic
47
20
  end
48
21
 
49
22
  PATTERN = /\Aservice_([^\.]*)\.active_storage\z/
50
- UNKNOWN = "unknown".freeze
51
23
 
52
24
  METHOD_NAME_MAPPING = Hash.new do |h, k|
53
25
  if PATTERN =~ k
54
26
  h[k] = $1
55
27
  else
56
- h[k] = UNKNOWN
28
+ h[k] = NewRelic::UNKNOWN
57
29
  end
58
30
  end
59
31