newrelic_rpm 8.11.0 → 8.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -3
  3. data/.rubocop_todo.yml +14 -7
  4. data/Brewfile +1 -0
  5. data/CHANGELOG.md +78 -16
  6. data/README.md +1 -1
  7. data/bin/nrdebug +2 -0
  8. data/docker-compose.yml +22 -0
  9. data/lib/new_relic/agent/agent/shutdown.rb +1 -0
  10. data/lib/new_relic/agent/agent/special_startup.rb +2 -0
  11. data/lib/new_relic/agent/agent/startup.rb +1 -0
  12. data/lib/new_relic/agent/agent_logger.rb +1 -1
  13. data/lib/new_relic/agent/attributes.rb +1 -0
  14. data/lib/new_relic/agent/audit_logger.rb +2 -1
  15. data/lib/new_relic/agent/commands/thread_profiler_session.rb +1 -0
  16. data/lib/new_relic/agent/configuration/default_source.rb +1415 -1359
  17. data/lib/new_relic/agent/configuration/dotted_hash.rb +1 -0
  18. data/lib/new_relic/agent/configuration/environment_source.rb +3 -2
  19. data/lib/new_relic/agent/configuration/high_security_source.rb +1 -0
  20. data/lib/new_relic/agent/configuration/manager.rb +3 -0
  21. data/lib/new_relic/agent/configuration/security_policy_source.rb +10 -0
  22. data/lib/new_relic/agent/configuration/yaml_source.rb +1 -0
  23. data/lib/new_relic/agent/connect/request_builder.rb +1 -0
  24. data/lib/new_relic/agent/database/obfuscation_helpers.rb +1 -0
  25. data/lib/new_relic/agent/database.rb +7 -0
  26. data/lib/new_relic/agent/database_adapter.rb +2 -0
  27. data/lib/new_relic/agent/datastores/mongo/event_formatter.rb +3 -2
  28. data/lib/new_relic/agent/datastores/mongo/metric_translator.rb +1 -1
  29. data/lib/new_relic/agent/datastores/nosql_obfuscator.rb +41 -0
  30. data/lib/new_relic/agent/distributed_tracing/cross_app_tracing.rb +3 -0
  31. data/lib/new_relic/agent/distributed_tracing/distributed_trace_attributes.rb +3 -0
  32. data/lib/new_relic/agent/distributed_tracing/distributed_trace_metrics.rb +1 -0
  33. data/lib/new_relic/agent/distributed_tracing/distributed_trace_payload.rb +1 -0
  34. data/lib/new_relic/agent/distributed_tracing/trace_context.rb +1 -0
  35. data/lib/new_relic/agent/encoding_normalizer.rb +2 -0
  36. data/lib/new_relic/agent/error_collector.rb +3 -0
  37. data/lib/new_relic/agent/error_filter.rb +1 -0
  38. data/lib/new_relic/agent/error_trace_aggregator.rb +1 -0
  39. data/lib/new_relic/agent/event_aggregator.rb +1 -0
  40. data/lib/new_relic/agent/event_loop.rb +2 -0
  41. data/lib/new_relic/agent/http_clients/abstract.rb +2 -0
  42. data/lib/new_relic/agent/http_clients/http_rb_wrappers.rb +1 -1
  43. data/lib/new_relic/agent/http_clients/httpclient_wrappers.rb +1 -1
  44. data/lib/new_relic/agent/http_clients/typhoeus_wrappers.rb +1 -0
  45. data/lib/new_relic/agent/instrumentation/active_merchant.rb +1 -2
  46. data/lib/new_relic/agent/instrumentation/active_storage_subscriber.rb +2 -0
  47. data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +1 -2
  48. data/lib/new_relic/agent/instrumentation/authlogic.rb +0 -2
  49. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +1 -0
  50. data/lib/new_relic/agent/instrumentation/data_mapper.rb +0 -1
  51. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +1 -2
  52. data/lib/new_relic/agent/instrumentation/elasticsearch/chain.rb +29 -0
  53. data/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb +66 -0
  54. data/lib/new_relic/agent/instrumentation/elasticsearch/prepend.rb +13 -0
  55. data/lib/new_relic/agent/instrumentation/elasticsearch.rb +31 -0
  56. data/lib/new_relic/agent/instrumentation/excon.rb +17 -0
  57. data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +1 -0
  58. data/lib/new_relic/agent/instrumentation/logger/instrumentation.rb +4 -0
  59. data/lib/new_relic/agent/instrumentation/mongodb_command_subscriber.rb +2 -0
  60. data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +2 -0
  61. data/lib/new_relic/agent/instrumentation/rack/chain.rb +10 -2
  62. data/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +3 -0
  63. data/lib/new_relic/agent/instrumentation/rack/prepend.rb +9 -2
  64. data/lib/new_relic/agent/instrumentation/rainbows_instrumentation.rb +0 -1
  65. data/lib/new_relic/agent/instrumentation/rake/instrumentation.rb +1 -0
  66. data/lib/new_relic/agent/instrumentation/redis/chain.rb +18 -6
  67. data/lib/new_relic/agent/instrumentation/redis/constants.rb +17 -0
  68. data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +28 -18
  69. data/lib/new_relic/agent/instrumentation/redis/middleware.rb +16 -0
  70. data/lib/new_relic/agent/instrumentation/redis/prepend.rb +6 -0
  71. data/lib/new_relic/agent/instrumentation/redis.rb +6 -0
  72. data/lib/new_relic/agent/instrumentation/sidekiq/client.rb +20 -0
  73. data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delayed_class.rb +30 -0
  74. data/lib/new_relic/agent/instrumentation/sidekiq/server.rb +37 -0
  75. data/lib/new_relic/agent/instrumentation/sidekiq.rb +7 -70
  76. data/lib/new_relic/agent/instrumentation/sinatra.rb +1 -2
  77. data/lib/new_relic/agent/instrumentation/sunspot.rb +0 -2
  78. data/lib/new_relic/agent/instrumentation/thread/instrumentation.rb +1 -0
  79. data/lib/new_relic/agent/instrumentation/tilt/instrumentation.rb +1 -0
  80. data/lib/new_relic/agent/javascript_instrumentor.rb +1 -0
  81. data/lib/new_relic/agent/local_log_decorator.rb +1 -0
  82. data/lib/new_relic/agent/log_event_aggregator.rb +1 -0
  83. data/lib/new_relic/agent/messaging.rb +1 -0
  84. data/lib/new_relic/agent/method_tracer.rb +4 -0
  85. data/lib/new_relic/agent/method_tracer_helpers.rb +1 -1
  86. data/lib/new_relic/agent/monitors/distributed_tracing_monitor.rb +1 -0
  87. data/lib/new_relic/agent/new_relic_service.rb +2 -0
  88. data/lib/new_relic/agent/parameter_filtering.rb +7 -1
  89. data/lib/new_relic/agent/pipe_channel_manager.rb +2 -0
  90. data/lib/new_relic/agent/rules_engine.rb +1 -0
  91. data/lib/new_relic/agent/samplers/cpu_sampler.rb +1 -0
  92. data/lib/new_relic/agent/samplers/memory_sampler.rb +5 -0
  93. data/lib/new_relic/agent/span_event_primitive.rb +1 -0
  94. data/lib/new_relic/agent/stats.rb +1 -0
  95. data/lib/new_relic/agent/stats_engine/gc_profiler.rb +1 -0
  96. data/lib/new_relic/agent/system_info.rb +3 -0
  97. data/lib/new_relic/agent/threading/agent_thread.rb +1 -0
  98. data/lib/new_relic/agent/threading/backtrace_service.rb +1 -0
  99. data/lib/new_relic/agent/threading/thread_profile.rb +3 -0
  100. data/lib/new_relic/agent/tracer.rb +5 -1
  101. data/lib/new_relic/agent/transaction/abstract_segment.rb +3 -0
  102. data/lib/new_relic/agent/transaction/datastore_segment.rb +3 -0
  103. data/lib/new_relic/agent/transaction/distributed_tracer.rb +4 -0
  104. data/lib/new_relic/agent/transaction/distributed_tracing.rb +1 -0
  105. data/lib/new_relic/agent/transaction/external_request_segment.rb +1 -0
  106. data/lib/new_relic/agent/transaction/message_broker_segment.rb +1 -0
  107. data/lib/new_relic/agent/transaction/segment.rb +1 -0
  108. data/lib/new_relic/agent/transaction/trace.rb +4 -0
  109. data/lib/new_relic/agent/transaction/trace_node.rb +1 -0
  110. data/lib/new_relic/agent/transaction/transaction_sample_buffer.rb +2 -0
  111. data/lib/new_relic/agent/transaction.rb +10 -0
  112. data/lib/new_relic/agent/transaction_event_aggregator.rb +1 -0
  113. data/lib/new_relic/agent/transaction_time_aggregator.rb +1 -0
  114. data/lib/new_relic/agent/utilization/pcf.rb +1 -0
  115. data/lib/new_relic/agent/utilization/vendor.rb +2 -0
  116. data/lib/new_relic/agent/utilization_data.rb +3 -0
  117. data/lib/new_relic/agent.rb +4 -2
  118. data/lib/new_relic/cli/commands/install.rb +1 -0
  119. data/lib/new_relic/coerce.rb +6 -0
  120. data/lib/new_relic/collection_helper.rb +1 -0
  121. data/lib/new_relic/constants.rb +2 -0
  122. data/lib/new_relic/control/frameworks/rails.rb +5 -0
  123. data/lib/new_relic/control/instrumentation.rb +6 -8
  124. data/lib/new_relic/dependency_detection.rb +2 -0
  125. data/lib/new_relic/helper.rb +1 -0
  126. data/lib/new_relic/language_support.rb +1 -0
  127. data/lib/new_relic/latest_changes.rb +1 -0
  128. data/lib/new_relic/local_environment.rb +7 -1
  129. data/lib/new_relic/metric_spec.rb +2 -0
  130. data/lib/new_relic/rack/agent_middleware.rb +2 -0
  131. data/lib/new_relic/rack/browser_monitoring.rb +1 -0
  132. data/lib/new_relic/traced_thread.rb +1 -0
  133. data/lib/new_relic/version.rb +1 -1
  134. data/lib/tasks/helpers/format.rb +3 -0
  135. data/lib/tasks/helpers/prompt.rb +1 -1
  136. data/lib/tasks/instrumentation_generator/README.md +2 -2
  137. data/lib/tasks/instrumentation_generator/TODO.md +5 -5
  138. data/lib/tasks/instrumentation_generator/instrumentation.thor +27 -5
  139. data/lib/tasks/instrumentation_generator/templates/chain.tt +2 -1
  140. data/lib/tasks/instrumentation_generator/templates/chain_method.tt +3 -2
  141. data/lib/tasks/instrumentation_generator/templates/instrumentation.tt +2 -1
  142. data/lib/tasks/instrumentation_generator/templates/instrumentation_method.tt +1 -1
  143. data/lib/tasks/instrumentation_generator/templates/prepend.tt +1 -1
  144. data/lib/tasks/instrumentation_generator/templates/prepend_method.tt +1 -1
  145. data/lib/tasks/instrumentation_generator/templates/test.tt +1 -1
  146. data/newrelic.yml +13 -3
  147. data/newrelic_rpm.gemspec +7 -7
  148. data/test/agent_helper.rb +24 -0
  149. metadata +18 -79
  150. data/lib/new_relic/agent/datastores/mongo/obfuscator.rb +0 -43
@@ -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_relative 'elasticsearch/instrumentation'
6
+ require_relative 'elasticsearch/chain'
7
+ require_relative 'elasticsearch/prepend'
8
+
9
+ DependencyDetection.defer do
10
+ named :elasticsearch
11
+
12
+ depends_on do
13
+ defined?(::Elasticsearch)
14
+ end
15
+
16
+ executes do
17
+ ::NewRelic::Agent.logger.info('Installing Elasticsearch instrumentation')
18
+
19
+ to_instrument = if ::Gem::Version.create(::Elasticsearch::VERSION) < ::Gem::Version.create("8.0.0")
20
+ ::Elasticsearch::Transport::Client
21
+ else
22
+ ::Elastic::Transport::Client
23
+ end
24
+
25
+ if use_prepend?
26
+ prepend_instrument to_instrument, NewRelic::Agent::Instrumentation::Elasticsearch::Prepend
27
+ else
28
+ chain_instrument NewRelic::Agent::Instrumentation::Elasticsearch
29
+ end
30
+ end
31
+ end
@@ -17,6 +17,7 @@ DependencyDetection.defer do
17
17
  # so we could safely subscribe and not be clobbered by future subscribers,
18
18
  # but alas, it does not yet.
19
19
 
20
+ # TODO: MAJOR VERSION - update min version to 0.56.0
20
21
  EXCON_MIN_VERSION = Gem::Version.new("0.19.0")
21
22
 
22
23
  depends_on do
@@ -32,6 +33,22 @@ DependencyDetection.defer do
32
33
  end
33
34
  end
34
35
 
36
+ executes do
37
+ next unless Gem::Version.new(::Excon::VERSION) < Gem::Version.new('0.56.0')
38
+
39
+ deprecation_msg = 'Instrumentation for Excon versions below 0.56.0 is deprecated.' \
40
+ 'They will stop being monitored in version 9.0.0. ' \
41
+ 'Please upgrade your Excon version to continue receiving full support. '
42
+
43
+ ::NewRelic::Agent.logger.log_once(
44
+ :warn,
45
+ :deprecated_excon_version,
46
+ deprecation_msg
47
+ )
48
+
49
+ ::NewRelic::Agent.record_metric("Supportability/Deprecated/Excon", 1)
50
+ end
51
+
35
52
  def install_excon_instrumentation(excon_version)
36
53
  require 'new_relic/agent/distributed_tracing/cross_app_tracing'
37
54
  require 'new_relic/agent/http_clients/excon_wrappers'
@@ -45,6 +45,7 @@ module NewRelic::Agent::Instrumentation
45
45
 
46
46
  def handle_transaction(endpoint, class_name, version)
47
47
  return unless endpoint && route = endpoint.route
48
+
48
49
  name_transaction(route, class_name, version)
49
50
  capture_params(endpoint)
50
51
  end
@@ -15,21 +15,25 @@ module NewRelic
15
15
  # and AuditLogger without them having to know the inner details.
16
16
  def self.mark_skip_instrumenting(logger)
17
17
  return if logger.frozen?
18
+
18
19
  logger.instance_variable_set(:@skip_instrumenting, true)
19
20
  end
20
21
 
21
22
  def self.clear_skip_instrumenting(logger)
22
23
  return if logger.frozen?
24
+
23
25
  logger.instance_variable_set(:@skip_instrumenting, false)
24
26
  end
25
27
 
26
28
  def mark_skip_instrumenting
27
29
  return if frozen?
30
+
28
31
  @skip_instrumenting = true
29
32
  end
30
33
 
31
34
  def clear_skip_instrumenting
32
35
  return if frozen?
36
+
33
37
  @skip_instrumenting = false
34
38
  end
35
39
 
@@ -14,6 +14,7 @@ module NewRelic
14
14
  def started(event)
15
15
  begin
16
16
  return unless NewRelic::Agent::Tracer.tracing_enabled?
17
+
17
18
  segments[event.operation_id] = start_segment(event)
18
19
  rescue Exception => e
19
20
  log_notification_error('started', e)
@@ -33,6 +34,7 @@ module NewRelic
33
34
  def completed(event)
34
35
  begin
35
36
  return unless NewRelic::Agent::Tracer.tracing_enabled?
37
+
36
38
  segment = segments.delete(event.operation_id)
37
39
  return unless segment
38
40
 
@@ -76,6 +76,7 @@ module NewRelic
76
76
  # defensive.
77
77
  return if defined?(exception_object)
78
78
  return unless defined?(::ActiveSupport::VERSION)
79
+
79
80
  if ::ActiveSupport::VERSION::STRING < "5.0.0"
80
81
  # Earlier versions of Rails did not add the exception itself to the
81
82
  # payload accessible via :exception_object, so we create a stand-in
@@ -85,6 +86,7 @@ module NewRelic
85
86
  def exception_object(payload)
86
87
  exception_class, message = payload[:exception]
87
88
  return nil unless exception_class
89
+
88
90
  NewRelic::Agent::NoticeableError.new(exception_class, message)
89
91
  end
90
92
  else
@@ -21,8 +21,16 @@ module NewRelic::Agent::Instrumentation
21
21
  if ::NewRelic::Agent::Instrumentation::RackHelpers.middleware_instrumentation_enabled?
22
22
  ::NewRelic::Agent.logger.info("Installing #{builder_class} middleware instrumentation")
23
23
 
24
- def run_with_newrelic(app, *args)
25
- run_with_tracing(app) { |wrapped_app| run_without_newrelic(wrapped_app, *args) }
24
+ def run_with_newrelic(app = nil, *args, &block)
25
+ app_or_block = app || block
26
+ run_with_tracing(app_or_block) do |wrapped|
27
+ # Rack::Builder#run for Rack v3+ supports a block, and does not
28
+ # support args. Whether a block or an app is provided, that
29
+ # callable object will be wrapped into a MiddlewareProxy
30
+ # instance. That proxy instance must then be passed to
31
+ # run_without_newrelic as the app argument.
32
+ block ? run_without_newrelic(wrapped, &nil) : run_without_newrelic(wrapped, *args)
33
+ end
26
34
  end
27
35
 
28
36
  alias_method(:run_without_newrelic, :run)
@@ -23,6 +23,7 @@ module NewRelic
23
23
 
24
24
  def check_for_late_instrumentation(app)
25
25
  return if defined?(@checked_for_late_instrumentation) && @checked_for_late_instrumentation
26
+
26
27
  @checked_for_late_instrumentation = true
27
28
  if middleware_instrumentation_enabled?
28
29
  if ::NewRelic::Agent::Instrumentation::MiddlewareProxy.needs_wrapping?(app)
@@ -49,12 +50,14 @@ module NewRelic
49
50
 
50
51
  def run_with_tracing(app)
51
52
  return yield(app) unless middleware_instrumentation_enabled?
53
+
52
54
  yield(::NewRelic::Agent::Instrumentation::MiddlewareProxy.wrap(app, true))
53
55
  end
54
56
 
55
57
  def use_with_tracing(middleware_class)
56
58
  return if middleware_class.nil?
57
59
  return yield(middleware_class) unless middleware_instrumentation_enabled?
60
+
58
61
  yield(::NewRelic::Agent::Instrumentation::MiddlewareProxy.for_class(middleware_class))
59
62
  end
60
63
  end
@@ -23,8 +23,15 @@ module NewRelic::Agent::Instrumentation
23
23
  with_deferred_dependency_detection { super }
24
24
  end
25
25
 
26
- def run(app, *args)
27
- run_with_tracing(app) { |wrapped_app| super(wrapped_app, *args) }
26
+ def run(app = nil, *args, &block)
27
+ app_or_block = app || block
28
+ run_with_tracing(app_or_block) do |wrapped|
29
+ # Rack::Builder#run for Rack v3+ supports a block, and does not
30
+ # support args. Whether a block or an app is provided, that callable
31
+ # object will be wrapped into a MiddlewareProxy instance. That
32
+ # proxy instance must then be passed to super as the app argument.
33
+ block ? super(wrapped, &nil) : super(wrapped, *args)
34
+ end
28
35
  end
29
36
 
30
37
  def use(middleware_class, *args, &blk)
@@ -22,7 +22,6 @@ DependencyDetection.defer do
22
22
  :deprecated_rainbows_dispatcher,
23
23
  deprecation_msg
24
24
  )
25
- ::NewRelic::Agent.record_metric("Supportability/Deprecated/Rainbows", 1)
26
25
  end
27
26
 
28
27
  executes do
@@ -37,6 +37,7 @@ module NewRelic
37
37
 
38
38
  def safe_from_third_party_gem?
39
39
  return true unless NewRelic::LanguageSupport.bundled_gem?("newrelic-rake")
40
+
40
41
  ::NewRelic::Agent.logger.info("Not installing New Relic supported Rake instrumentation because the third party newrelic-rake gem is present")
41
42
  false
42
43
  end
@@ -9,16 +9,28 @@ module NewRelic::Agent::Instrumentation
9
9
  ::Redis::Client.class_eval do
10
10
  include NewRelic::Agent::Instrumentation::Redis
11
11
 
12
- alias_method(:call_without_new_relic, :call)
12
+ if method_defined?(:call_v)
13
+ alias_method(:call_v_without_new_relic, :call_v)
13
14
 
14
- def call(*args, &block)
15
- call_with_tracing(args[0]) { call_without_new_relic(*args, &block) }
15
+ def call_v(*args, &block)
16
+ call_with_tracing(args[0]) { call_v_without_new_relic(*args, &block) }
17
+ end
16
18
  end
17
19
 
18
- alias_method(:call_pipeline_without_new_relic, :call_pipeline)
20
+ if method_defined?(:call)
21
+ alias_method(:call_without_new_relic, :call)
19
22
 
20
- def call_pipeline(*args, &block)
21
- call_pipeline_with_tracing(args[0]) { call_pipeline_without_new_relic(*args, &block) }
23
+ def call(*args, &block)
24
+ call_with_tracing(args[0]) { call_without_new_relic(*args, &block) }
25
+ end
26
+ end
27
+
28
+ if method_defined?(:call_pipeline)
29
+ alias_method(:call_pipeline_without_new_relic, :call_pipeline)
30
+
31
+ def call_pipeline(*args, &block)
32
+ call_pipeline_with_tracing(args[0]) { call_pipeline_without_new_relic(*args, &block) }
33
+ end
22
34
  end
23
35
 
24
36
  alias_method(:connect_without_new_relic, :connect)
@@ -0,0 +1,17 @@
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
+ module NewRelic::Agent::Instrumentation::Redis
6
+ class Constants
7
+ PRODUCT_NAME = 'Redis'
8
+ CONNECT = 'connect'
9
+ UNKNOWN = 'unknown'
10
+ LOCALHOST = 'localhost'
11
+ MULTI_OPERATION = 'multi'
12
+ PIPELINE_OPERATION = 'pipeline'
13
+ HAS_REDIS_CLIENT = defined?(::Redis) &&
14
+ Gem::Version.new(::Redis::VERSION) >= Gem::Version.new('5.0.0') &&
15
+ !!defined?(::RedisClient)
16
+ end
17
+ end
@@ -2,42 +2,48 @@
2
2
  # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
3
  # frozen_string_literal: true
4
4
 
5
+ require_relative 'constants'
6
+
5
7
  module NewRelic::Agent::Instrumentation
6
8
  module Redis
7
- PRODUCT_NAME = 'Redis'
8
- CONNECT = 'connect'
9
- UNKNOWN = "unknown"
10
- LOCALHOST = "localhost"
11
- MULTI_OPERATION = 'multi'
12
- PIPELINE_OPERATION = 'pipeline'
9
+ def connect_with_tracing
10
+ with_tracing(Constants::CONNECT, database: db) { yield }
11
+ end
13
12
 
14
13
  def call_with_tracing(command, &block)
15
14
  operation = command[0]
16
15
  statement = ::NewRelic::Agent::Datastores::Redis.format_command(command)
17
16
 
18
- with_tracing(operation, statement) { yield }
17
+ with_tracing(operation, statement: statement, database: db) { yield }
19
18
  end
20
19
 
20
+ # Used for Redis 4.x and 3.x
21
21
  def call_pipeline_with_tracing(pipeline)
22
- operation = pipeline.is_a?(::Redis::Pipeline::Multi) ? MULTI_OPERATION : PIPELINE_OPERATION
22
+ operation = pipeline.is_a?(::Redis::Pipeline::Multi) ? Constants::MULTI_OPERATION : Constants::PIPELINE_OPERATION
23
23
  statement = ::NewRelic::Agent::Datastores::Redis.format_pipeline_commands(pipeline.commands)
24
24
 
25
- with_tracing(operation, statement) { yield }
25
+ with_tracing(operation, statement: statement, database: db) { yield }
26
26
  end
27
27
 
28
- def connect_with_tracing
29
- with_tracing(CONNECT) { yield }
28
+ # Used for Redis 5.x+
29
+ def call_pipelined_with_tracing(pipeline)
30
+ operation = pipeline.flatten.include?('MULTI') ? Constants::MULTI_OPERATION : Constants::PIPELINE_OPERATION
31
+ statement = ::NewRelic::Agent::Datastores::Redis.format_pipeline_commands(pipeline)
32
+
33
+ # call_pipelined isn't invoked on the client object, so use client.db to
34
+ # access the client instance var on self
35
+ with_tracing(operation, statement: statement, database: client.db) { yield }
30
36
  end
31
37
 
32
38
  private
33
39
 
34
- def with_tracing(operation, statement = nil)
40
+ def with_tracing(operation, statement: nil, database: nil)
35
41
  segment = NewRelic::Agent::Tracer.start_datastore_segment(
36
- product: PRODUCT_NAME,
42
+ product: Constants::PRODUCT_NAME,
37
43
  operation: operation,
38
44
  host: _nr_hostname,
39
45
  port_path_or_id: _nr_port_path_or_id,
40
- database_name: db
46
+ database_name: database
41
47
  )
42
48
  begin
43
49
  segment.notice_nosql_statement(statement) if statement
@@ -48,17 +54,21 @@ module NewRelic::Agent::Instrumentation
48
54
  end
49
55
 
50
56
  def _nr_hostname
51
- self.path ? LOCALHOST : self.host
57
+ _nr_client.path ? Constants::LOCALHOST : _nr_client.host
52
58
  rescue => e
53
59
  NewRelic::Agent.logger.debug("Failed to retrieve Redis host: #{e}")
54
- UNKNOWN
60
+ Constants::UNKNOWN
55
61
  end
56
62
 
57
63
  def _nr_port_path_or_id
58
- self.path || self.port
64
+ _nr_client.path || _nr_client.port
59
65
  rescue => e
60
66
  NewRelic::Agent.logger.debug("Failed to retrieve Redis port_path_or_id: #{e}")
61
- UNKNOWN
67
+ Constants::UNKNOWN
68
+ end
69
+
70
+ def _nr_client
71
+ @nr_client ||= self.is_a?(::Redis::Client) ? self : client
62
72
  end
63
73
  end
64
74
  end
@@ -0,0 +1,16 @@
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
+ module NewRelic::Agent::Instrumentation
6
+ module RedisClient
7
+ module Middleware
8
+ # This module is used to instrument Redis 5.x+
9
+ include NewRelic::Agent::Instrumentation::Redis
10
+
11
+ def call_pipelined(*args, &block)
12
+ call_pipelined_with_tracing(args[0]) { super }
13
+ end
14
+ end
15
+ end
16
+ end
@@ -7,6 +7,12 @@ module NewRelic::Agent::Instrumentation
7
7
  module Prepend
8
8
  include NewRelic::Agent::Instrumentation::Redis
9
9
 
10
+ # Defined in version 5.x+
11
+ def call_v(*args, &block)
12
+ call_with_tracing(args[0]) { super }
13
+ end
14
+
15
+ # Defined in version 4.x, 3.x
10
16
  def call(*args, &block)
11
17
  call_with_tracing(args[0]) { super }
12
18
  end
@@ -7,7 +7,9 @@ require 'new_relic/agent/datastores/redis'
7
7
 
8
8
  require_relative 'redis/instrumentation'
9
9
  require_relative 'redis/chain'
10
+ require_relative 'redis/constants'
10
11
  require_relative 'redis/prepend'
12
+ require_relative 'redis/middleware'
11
13
 
12
14
  DependencyDetection.defer do
13
15
  # Why not :redis? newrelic-redis used that name, so avoid conflicting
@@ -29,6 +31,10 @@ DependencyDetection.defer do
29
31
 
30
32
  executes do
31
33
  NewRelic::Agent.logger.info('Installing Redis Instrumentation')
34
+ if NewRelic::Agent::Instrumentation::Redis::Constants::HAS_REDIS_CLIENT
35
+ ::RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::Middleware)
36
+ end
37
+
32
38
  if use_prepend?
33
39
  prepend_instrument ::Redis::Client, NewRelic::Agent::Instrumentation::Redis::Prepend
34
40
  else
@@ -0,0 +1,20 @@
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
+ module NewRelic::Agent::Instrumentation::Sidekiq
6
+ class Client
7
+ include Sidekiq::ClientMiddleware if defined?(Sidekiq::ClientMiddleware)
8
+
9
+ def call(_worker_class, job, *_)
10
+ job[NewRelic::NEWRELIC_KEY] ||= distributed_tracing_headers if ::NewRelic::Agent.config[:'distributed_tracing.enabled']
11
+ yield
12
+ end
13
+
14
+ def distributed_tracing_headers
15
+ headers = {}
16
+ ::NewRelic::Agent::DistributedTracing.insert_distributed_trace_headers(headers)
17
+ headers
18
+ end
19
+ end
20
+ 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
+ # TODO: remove this class once Sidekiq v6 is no longer supported.
6
+ # Delayed extensions are disabled by default in Sidekiq 5 and 6 and
7
+ # were removed entirely in Sidekiq 7.
8
+ #
9
+ # see https://github.com/mperham/sidekiq/issues/5076 for the discussion
10
+ # of the removal, which includes mentions of alternatives
11
+ if defined?(Sidekiq::VERSION) && Sidekiq::VERSION < '7.0.0'
12
+ class Sidekiq::Extensions::DelayedClass
13
+ def newrelic_trace_args(msg, queue)
14
+ (target, method_name, _args) = if YAML.respond_to?(:unsafe_load)
15
+ YAML.unsafe_load(msg['args'][0])
16
+ else
17
+ YAML.load(msg['args'][0])
18
+ end
19
+
20
+ {
21
+ :name => method_name,
22
+ :class_name => target.name,
23
+ :category => 'OtherTransaction/SidekiqJob'
24
+ }
25
+ rescue => e
26
+ NewRelic::Agent.logger.error("Failure during deserializing YAML for Sidekiq::Extensions::DelayedClass", e)
27
+ NewRelic::Agent::Instrumentation::Sidekiq::Server.default_trace_args(msg)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,37 @@
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
+ module NewRelic::Agent::Instrumentation::Sidekiq
6
+ class Server
7
+ include NewRelic::Agent::Instrumentation::ControllerInstrumentation
8
+ include Sidekiq::ServerMiddleware if defined?(Sidekiq::ServerMiddleware)
9
+
10
+ # Client middleware has additional parameters, and our tests use the
11
+ # middleware client-side to work inline.
12
+ def call(worker, msg, queue, *_)
13
+ trace_args = if worker.respond_to?(:newrelic_trace_args)
14
+ worker.newrelic_trace_args(msg, queue)
15
+ else
16
+ self.class.default_trace_args(msg)
17
+ end
18
+ trace_headers = msg.delete(NewRelic::NEWRELIC_KEY)
19
+
20
+ perform_action_with_newrelic_trace(trace_args) do
21
+ NewRelic::Agent::Transaction.merge_untrusted_agent_attributes(msg['args'], :'job.sidekiq.args',
22
+ NewRelic::Agent::AttributeFilter::DST_NONE)
23
+
24
+ ::NewRelic::Agent::DistributedTracing::accept_distributed_trace_headers(trace_headers, "Other") if ::NewRelic::Agent.config[:'distributed_tracing.enabled']
25
+ yield
26
+ end
27
+ end
28
+
29
+ def self.default_trace_args(msg)
30
+ {
31
+ :name => 'perform',
32
+ :class_name => msg['class'],
33
+ :category => 'OtherTransaction/SidekiqJob'
34
+ }
35
+ end
36
+ end
37
+ end
@@ -1,6 +1,9 @@
1
1
  # This file is distributed under New Relic's license terms.
2
2
  # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
3
  # frozen_string_literal: true
4
+ require_relative 'sidekiq/client'
5
+ require_relative 'sidekiq/server'
6
+ require_relative 'sidekiq/extensions/delayed_class'
4
7
 
5
8
  DependencyDetection.defer do
6
9
  @name = :sidekiq
@@ -14,83 +17,18 @@ DependencyDetection.defer do
14
17
  end
15
18
 
16
19
  executes do
17
- module NewRelic::SidekiqInstrumentation
18
- class Server
19
- include NewRelic::Agent::Instrumentation::ControllerInstrumentation
20
-
21
- # Client middleware has additional parameters, and our tests use the
22
- # middleware client-side to work inline.
23
- def call(worker, msg, queue, *_)
24
- trace_args = if worker.respond_to?(:newrelic_trace_args)
25
- worker.newrelic_trace_args(msg, queue)
26
- else
27
- self.class.default_trace_args(msg)
28
- end
29
- trace_headers = msg.delete(NewRelic::NEWRELIC_KEY)
30
-
31
- perform_action_with_newrelic_trace(trace_args) do
32
- NewRelic::Agent::Transaction.merge_untrusted_agent_attributes(msg['args'], :'job.sidekiq.args',
33
- NewRelic::Agent::AttributeFilter::DST_NONE)
34
-
35
- ::NewRelic::Agent::DistributedTracing::accept_distributed_trace_headers(trace_headers, "Other") if ::NewRelic::Agent.config[:'distributed_tracing.enabled']
36
- yield
37
- end
38
- end
39
-
40
- def self.default_trace_args(msg)
41
- {
42
- :name => 'perform',
43
- :class_name => msg['class'],
44
- :category => 'OtherTransaction/SidekiqJob'
45
- }
46
- end
47
- end
48
-
49
- class Client
50
- def call(_worker_class, job, *_)
51
- job[NewRelic::NEWRELIC_KEY] ||= distributed_tracing_headers if ::NewRelic::Agent.config[:'distributed_tracing.enabled']
52
- yield
53
- end
54
-
55
- def distributed_tracing_headers
56
- headers = {}
57
- ::NewRelic::Agent::DistributedTracing.insert_distributed_trace_headers(headers)
58
- headers
59
- end
60
- end
61
- end
62
-
63
- class Sidekiq::Extensions::DelayedClass
64
- def newrelic_trace_args(msg, queue)
65
- (target, method_name, _args) = if YAML.respond_to?(:unsafe_load)
66
- YAML.unsafe_load(msg['args'][0])
67
- else
68
- YAML.load(msg['args'][0])
69
- end
70
-
71
- {
72
- :name => method_name,
73
- :class_name => target.name,
74
- :category => 'OtherTransaction/SidekiqJob'
75
- }
76
- rescue => e
77
- NewRelic::Agent.logger.error("Failure during deserializing YAML for Sidekiq::Extensions::DelayedClass", e)
78
- NewRelic::SidekiqInstrumentation::Server.default_trace_args(msg)
79
- end
80
- end
81
-
82
20
  Sidekiq.configure_client do |config|
83
21
  config.client_middleware do |chain|
84
- chain.add(NewRelic::SidekiqInstrumentation::Client)
22
+ chain.add(NewRelic::Agent::Instrumentation::Sidekiq::Client)
85
23
  end
86
24
  end
87
25
 
88
26
  Sidekiq.configure_server do |config|
89
27
  config.client_middleware do |chain|
90
- chain.add(NewRelic::SidekiqInstrumentation::Client)
28
+ chain.add(NewRelic::Agent::Instrumentation::Sidekiq::Client)
91
29
  end
92
30
  config.server_middleware do |chain|
93
- chain.add(NewRelic::SidekiqInstrumentation::Server)
31
+ chain.add(NewRelic::Agent::Instrumentation::Sidekiq::Server)
94
32
  end
95
33
 
96
34
  if config.respond_to?(:error_handlers)
@@ -103,6 +41,7 @@ DependencyDetection.defer do
103
41
 
104
42
  executes do
105
43
  next unless Gem::Version.new(Sidekiq::VERSION) < Gem::Version.new('5.0.0')
44
+
106
45
  deprecation_msg = 'Instrumentation for Sidekiq versions below 5.0.0 is deprecated.' \
107
46
  'They will stop being monitored in version 9.0.0. ' \
108
47
  'Please upgrade your Sidekiq version to continue receiving full support. '
@@ -112,7 +51,5 @@ DependencyDetection.defer do
112
51
  :deprecated_sidekiq_version,
113
52
  deprecation_msg
114
53
  )
115
-
116
- ::NewRelic::Agent.record_metric("Supportability/Deprecated/Sidekiq", 1)
117
54
  end
118
55
  end
@@ -45,6 +45,7 @@ DependencyDetection.defer do
45
45
 
46
46
  executes do
47
47
  next unless Gem::Version.new(Sinatra::VERSION) < Gem::Version.new('2.0.0')
48
+
48
49
  deprecation_msg = 'The Ruby Agent is dropping support for Sinatra versions below 2.0.0 ' \
49
50
  'in version 9.0.0. Please upgrade your Sinatra version to continue receiving full compatibility. ' \
50
51
 
@@ -53,7 +54,5 @@ DependencyDetection.defer do
53
54
  :deprecated_sinatra_version,
54
55
  deprecation_msg
55
56
  )
56
-
57
- ::NewRelic::Agent.record_metric("Supportability/Deprecated/Sinatra", 1)
58
57
  end
59
58
  end
@@ -19,8 +19,6 @@ DependencyDetection.defer do
19
19
  :deprecated_sunspot,
20
20
  deprecation_msg
21
21
  )
22
-
23
- ::NewRelic::Agent.record_metric("Supportability/Deprecated/Sunspot", 1)
24
22
  end
25
23
 
26
24
  executes do
@@ -15,6 +15,7 @@ module NewRelic
15
15
 
16
16
  def add_thread_tracing(*args, &block)
17
17
  return block if skip_tracing?
18
+
18
19
  NewRelic::Agent::Tracer.thread_block_with_current_transaction(*args, &block)
19
20
  end
20
21
 
@@ -14,6 +14,7 @@ module NewRelic
14
14
  # So here we are only grabbing the file name and name of directory it is in
15
15
  def create_filename_for_metric(file)
16
16
  return file unless defined?(::Sinatra) && defined?(::Sinatra::Base)
17
+
17
18
  file.split('/')[-2..-1].join('/')
18
19
  rescue NoMethodError
19
20
  file
@@ -118,6 +118,7 @@ module NewRelic
118
118
 
119
119
  def create_nonce(nonce = nil)
120
120
  return '' unless nonce
121
+
121
122
  " nonce=\"#{nonce.to_s}\""
122
123
  end
123
124