newrelic_rpm 9.3.0 → 9.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/.build_ignore +6 -1
  3. data/CHANGELOG.md +193 -6
  4. data/README.md +4 -0
  5. data/Rakefile +1 -1
  6. data/lib/new_relic/agent/attribute_pre_filtering.rb +109 -0
  7. data/lib/new_relic/agent/configuration/default_source.rb +177 -34
  8. data/lib/new_relic/agent/configuration/environment_source.rb +1 -1
  9. data/lib/new_relic/agent/distributed_tracing.rb +1 -1
  10. data/lib/new_relic/agent/http_clients/async_http_wrappers.rb +83 -0
  11. data/lib/new_relic/agent/http_clients/ethon_wrappers.rb +111 -0
  12. data/lib/new_relic/agent/http_clients/httpx_wrappers.rb +93 -0
  13. data/lib/new_relic/agent/instrumentation/action_controller_other_subscriber.rb +1 -1
  14. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +1 -2
  15. data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger/chain.rb +69 -0
  16. data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger/instrumentation.rb +13 -0
  17. data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger/prepend.rb +37 -0
  18. data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger.rb +23 -0
  19. data/lib/new_relic/agent/instrumentation/active_support_logger/instrumentation.rb +4 -0
  20. data/lib/new_relic/agent/instrumentation/active_support_logger.rb +3 -1
  21. data/lib/new_relic/agent/instrumentation/async_http/chain.rb +23 -0
  22. data/lib/new_relic/agent/instrumentation/async_http/instrumentation.rb +37 -0
  23. data/lib/new_relic/agent/instrumentation/async_http/prepend.rb +15 -0
  24. data/lib/new_relic/agent/instrumentation/async_http.rb +26 -0
  25. data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +9 -0
  26. data/lib/new_relic/agent/instrumentation/concurrent_ruby/instrumentation.rb +2 -2
  27. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +1 -2
  28. data/lib/new_relic/agent/instrumentation/curb/instrumentation.rb +4 -0
  29. data/lib/new_relic/agent/instrumentation/delayed_job/instrumentation.rb +3 -0
  30. data/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb +4 -1
  31. data/lib/new_relic/agent/instrumentation/ethon/chain.rb +39 -0
  32. data/lib/new_relic/agent/instrumentation/ethon/instrumentation.rb +105 -0
  33. data/lib/new_relic/agent/instrumentation/ethon/prepend.rb +35 -0
  34. data/lib/new_relic/agent/instrumentation/ethon.rb +39 -0
  35. data/lib/new_relic/agent/instrumentation/excon/middleware.rb +3 -0
  36. data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +4 -0
  37. data/lib/new_relic/agent/instrumentation/grpc/client/instrumentation.rb +4 -0
  38. data/lib/new_relic/agent/instrumentation/grpc/server/instrumentation.rb +4 -0
  39. data/lib/new_relic/agent/instrumentation/grpc_client.rb +1 -1
  40. data/lib/new_relic/agent/instrumentation/grpc_server.rb +1 -1
  41. data/lib/new_relic/agent/instrumentation/httpclient/instrumentation.rb +4 -0
  42. data/lib/new_relic/agent/instrumentation/httprb/instrumentation.rb +4 -0
  43. data/lib/new_relic/agent/instrumentation/httpx/chain.rb +20 -0
  44. data/lib/new_relic/agent/instrumentation/httpx/instrumentation.rb +51 -0
  45. data/lib/new_relic/agent/instrumentation/httpx/prepend.rb +15 -0
  46. data/lib/new_relic/agent/instrumentation/httpx.rb +27 -0
  47. data/lib/new_relic/agent/instrumentation/logger/instrumentation.rb +3 -0
  48. data/lib/new_relic/agent/instrumentation/memcache/instrumentation.rb +9 -0
  49. data/lib/new_relic/agent/instrumentation/memcache.rb +2 -2
  50. data/lib/new_relic/agent/instrumentation/mongodb_command_subscriber.rb +1 -3
  51. data/lib/new_relic/agent/instrumentation/net_http/instrumentation.rb +5 -1
  52. data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +4 -0
  53. data/lib/new_relic/agent/instrumentation/padrino/instrumentation.rb +4 -0
  54. data/lib/new_relic/agent/instrumentation/queue_time.rb +1 -1
  55. data/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +6 -0
  56. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +4 -0
  57. data/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb +1 -0
  58. data/lib/new_relic/agent/instrumentation/rake/instrumentation.rb +4 -0
  59. data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +4 -0
  60. data/lib/new_relic/agent/instrumentation/resque/instrumentation.rb +4 -0
  61. data/lib/new_relic/agent/instrumentation/roda/chain.rb +43 -0
  62. data/lib/new_relic/agent/instrumentation/roda/ignorer.rb +45 -0
  63. data/lib/new_relic/agent/instrumentation/roda/instrumentation.rb +68 -0
  64. data/lib/new_relic/agent/instrumentation/roda/prepend.rb +24 -0
  65. data/lib/new_relic/agent/instrumentation/roda/roda_transaction_namer.rb +29 -0
  66. data/lib/new_relic/agent/instrumentation/roda.rb +36 -0
  67. data/lib/new_relic/agent/instrumentation/sequel.rb +1 -1
  68. data/lib/new_relic/agent/instrumentation/sidekiq/client.rb +4 -0
  69. data/lib/new_relic/agent/instrumentation/sidekiq/server.rb +26 -3
  70. data/lib/new_relic/agent/instrumentation/sidekiq.rb +5 -3
  71. data/lib/new_relic/agent/instrumentation/sinatra/instrumentation.rb +4 -0
  72. data/lib/new_relic/agent/instrumentation/sinatra/transaction_namer.rb +1 -3
  73. data/lib/new_relic/agent/instrumentation/stripe.rb +28 -0
  74. data/lib/new_relic/agent/instrumentation/stripe_subscriber.rb +77 -0
  75. data/lib/new_relic/agent/instrumentation/tilt/instrumentation.rb +4 -0
  76. data/lib/new_relic/agent/instrumentation/typhoeus/instrumentation.rb +5 -1
  77. data/lib/new_relic/agent/log_event_attributes.rb +1 -1
  78. data/lib/new_relic/agent/messaging.rb +2 -2
  79. data/lib/new_relic/agent/monitors/synthetics_monitor.rb +12 -1
  80. data/lib/new_relic/agent/new_relic_service.rb +33 -17
  81. data/lib/new_relic/agent/pipe_service.rb +1 -1
  82. data/lib/new_relic/agent/rules_engine.rb +1 -1
  83. data/lib/new_relic/agent/span_event_primitive.rb +16 -4
  84. data/lib/new_relic/agent/system_info.rb +26 -0
  85. data/lib/new_relic/agent/tracer.rb +5 -6
  86. data/lib/new_relic/agent/transaction/abstract_segment.rb +55 -0
  87. data/lib/new_relic/agent/transaction/external_request_segment.rb +5 -2
  88. data/lib/new_relic/agent/transaction/message_broker_segment.rb +1 -2
  89. data/lib/new_relic/agent/transaction/request_attributes.rb +46 -10
  90. data/lib/new_relic/agent/transaction.rb +30 -6
  91. data/lib/new_relic/agent/transaction_error_primitive.rb +16 -0
  92. data/lib/new_relic/agent/transaction_event_primitive.rb +19 -0
  93. data/lib/new_relic/agent/utilization/gcp.rb +1 -3
  94. data/lib/new_relic/agent/utilization/vendor.rb +5 -7
  95. data/lib/new_relic/agent.rb +19 -3
  96. data/lib/new_relic/cli/command.rb +1 -0
  97. data/lib/new_relic/constants.rb +3 -0
  98. data/lib/new_relic/control/class_methods.rb +1 -7
  99. data/lib/new_relic/control/frameworks/rails.rb +14 -2
  100. data/lib/new_relic/control/frameworks/roda.rb +20 -0
  101. data/lib/new_relic/language_support.rb +9 -0
  102. data/lib/new_relic/noticed_error.rb +5 -2
  103. data/lib/new_relic/rack/agent_hooks.rb +1 -1
  104. data/lib/new_relic/rack/agent_middleware.rb +0 -16
  105. data/lib/new_relic/rack/browser_monitoring.rb +1 -1
  106. data/lib/new_relic/supportability_helper.rb +1 -0
  107. data/lib/new_relic/version.rb +1 -1
  108. data/lib/tasks/bump_version.rake +1 -1
  109. data/lib/tasks/config.rake +3 -2
  110. data/lib/tasks/helpers/config.html.erb +93 -0
  111. data/lib/tasks/helpers/format.rb +11 -7
  112. data/lib/tasks/helpers/version_bump.rb +2 -2
  113. data/lib/tasks/instrumentation_generator/instrumentation.thor +3 -3
  114. data/lib/tasks/newrelicyml.rake +1 -1
  115. data/lib/tasks/tests.rake +71 -0
  116. data/newrelic.yml +103 -31
  117. data/newrelic_rpm.gemspec +12 -6
  118. data/test/agent_helper.rb +1027 -0
  119. metadata +63 -8
  120. data/lib/tasks/helpers/removers.rb +0 -33
  121. data/lib/tasks/multiverse.rake +0 -6
  122. data/lib/tasks/multiverse.rb +0 -76
@@ -0,0 +1,43 @@
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 Roda
7
+ module Chain
8
+ def self.instrument!
9
+ ::Roda.class_eval do
10
+ include ::NewRelic::Agent::Instrumentation::Roda::Tracer
11
+
12
+ alias_method(:_roda_handle_main_route_without_tracing, :_roda_handle_main_route)
13
+
14
+ def _roda_handle_main_route(*args)
15
+ _roda_handle_main_route_with_tracing(*args) do
16
+ _roda_handle_main_route_without_tracing(*args)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ module Build
24
+ module Chain
25
+ def self.instrument!
26
+ ::Roda.class_eval do
27
+ include ::NewRelic::Agent::Instrumentation::Roda::Tracer
28
+
29
+ class << self
30
+ alias_method(:build_rack_app_without_tracing, :build_rack_app)
31
+
32
+ def build_rack_app
33
+ build_rack_app_with_tracing do
34
+ build_rack_app_without_tracing
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,45 @@
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 Roda
7
+ module Ignorer
8
+ def self.should_ignore?(app, type)
9
+ return false unless app.opts.include?(:newrelic_ignores)
10
+
11
+ app.opts[:newrelic_ignores][type].any? do |pattern|
12
+ pattern === app.request.path_info
13
+ end
14
+ end
15
+
16
+ def newrelic_ignore(*routes)
17
+ set_newrelic_ignore(:routes, *routes)
18
+ end
19
+
20
+ def newrelic_ignore_apdex(*routes)
21
+ set_newrelic_ignore(:apdex, *routes)
22
+ end
23
+
24
+ def newrelic_ignore_enduser(*routes)
25
+ set_newrelic_ignore(:enduser, *routes)
26
+ end
27
+
28
+ private
29
+
30
+ def set_newrelic_ignore(type, *routes)
31
+ # Create a newrelic_ignores hash if one doesn't exist
32
+ opts[:newrelic_ignores] = Hash.new([]) if !opts.include?(:newrelic_ignores)
33
+
34
+ if routes.empty?
35
+ opts[:newrelic_ignores][type] += [Regexp.new('.*')]
36
+ else
37
+ opts[:newrelic_ignores][type] += routes.map do |r|
38
+ # Roda adds leading slashes to routes, so we need to do the same
39
+ "#{'/' unless r.start_with?('/')}#{r}"
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,68 @@
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 Roda
7
+ module Tracer
8
+ include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
9
+
10
+ INSTRUMENTATION_NAME = 'Roda'
11
+
12
+ def self.included(clazz)
13
+ clazz.extend(self)
14
+ end
15
+
16
+ def newrelic_middlewares
17
+ middlewares = [NewRelic::Rack::BrowserMonitoring]
18
+ if NewRelic::Rack::AgentHooks.needed?
19
+ middlewares << NewRelic::Rack::AgentHooks
20
+ end
21
+ middlewares
22
+ end
23
+
24
+ def build_rack_app_with_tracing
25
+ unless NewRelic::Agent.config[:disable_roda_auto_middleware]
26
+ newrelic_middlewares.each do |middleware_class|
27
+ self.use middleware_class
28
+ end
29
+ end
30
+ yield
31
+ end
32
+
33
+ # Roda makes use of Rack, so we can get params from the request object
34
+ def rack_request_params
35
+ begin
36
+ @_request.params
37
+ rescue => e
38
+ NewRelic::Agent.logger.debug('Failed to get params from Rack request.', e)
39
+ NewRelic::EMPTY_HASH
40
+ end
41
+ end
42
+
43
+ def _roda_handle_main_route_with_tracing(*args)
44
+ NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
45
+
46
+ perform_action_with_newrelic_trace(
47
+ category: :roda,
48
+ name: ::NewRelic::Agent::Instrumentation::Roda::TransactionNamer.transaction_name(request),
49
+ params: ::NewRelic::Agent::ParameterFiltering::apply_filters(request.env, rack_request_params)
50
+ ) do
51
+ yield
52
+ end
53
+ end
54
+
55
+ def do_not_trace?
56
+ NewRelic::Agent::Instrumentation::Roda::Ignorer.should_ignore?(self, :routes)
57
+ end
58
+
59
+ def ignore_apdex?
60
+ NewRelic::Agent::Instrumentation::Roda::Ignorer.should_ignore?(self, :apdex)
61
+ end
62
+
63
+ def ignore_enduser?
64
+ NewRelic::Agent::Instrumentation::Roda::Ignorer.should_ignore?(self, :enduser)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,24 @@
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 Roda
7
+ module Prepend
8
+ include ::NewRelic::Agent::Instrumentation::Roda::Tracer
9
+
10
+ def _roda_handle_main_route(*args)
11
+ _roda_handle_main_route_with_tracing(*args) { super }
12
+ end
13
+ end
14
+
15
+ module Build
16
+ module Prepend
17
+ include ::NewRelic::Agent::Instrumentation::Roda::Tracer
18
+ def build_rack_app
19
+ build_rack_app_with_tracing { super }
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,29 @@
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
6
+ module Agent
7
+ module Instrumentation
8
+ module Roda
9
+ module TransactionNamer
10
+ extend self
11
+
12
+ REGEX_MULTIPLE_SLASHES = %r{^[/^]*(.*?)[/$?]*$}.freeze
13
+
14
+ def transaction_name(request)
15
+ path = request.path || ::NewRelic::Agent::UNKNOWN_METRIC
16
+ name = path.gsub(REGEX_MULTIPLE_SLASHES, '\1') # remove any rogue slashes
17
+ name = NewRelic::ROOT if name.empty?
18
+ name = "#{request.request_method} #{name}" if request.respond_to?(:request_method)
19
+
20
+ name
21
+ rescue => e
22
+ ::NewRelic::Agent.logger.debug("#{e.class} : #{e.message} - Error encountered trying to identify Roda transaction name")
23
+ ::NewRelic::Agent::UNKNOWN_METRIC
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,36 @@
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 'roda/instrumentation'
6
+ require_relative 'roda/roda_transaction_namer'
7
+ require_relative 'roda/ignorer'
8
+
9
+ DependencyDetection.defer do
10
+ named :roda
11
+
12
+ depends_on do
13
+ defined?(Roda) &&
14
+ Gem::Version.new(Roda::RodaVersion) >= Gem::Version.new('3.19.0') &&
15
+ Roda::RodaPlugins::Base::ClassMethods.private_method_defined?(:build_rack_app) &&
16
+ Roda::RodaPlugins::Base::InstanceMethods.method_defined?(:_roda_handle_main_route)
17
+ end
18
+
19
+ executes do
20
+ require_relative '../../rack/agent_hooks'
21
+ require_relative '../../rack/browser_monitoring'
22
+
23
+ NewRelic::Agent.logger.info('Installing Roda instrumentation')
24
+
25
+ if use_prepend?
26
+ require_relative 'roda/prepend'
27
+ prepend_instrument Roda.singleton_class, NewRelic::Agent::Instrumentation::Roda::Build::Prepend
28
+ prepend_instrument Roda, NewRelic::Agent::Instrumentation::Roda::Prepend
29
+ else
30
+ require_relative 'roda/chain'
31
+ chain_instrument NewRelic::Agent::Instrumentation::Roda::Build::Chain
32
+ chain_instrument NewRelic::Agent::Instrumentation::Roda::Chain
33
+ end
34
+ Roda.class_eval { extend NewRelic::Agent::Instrumentation::Roda::Ignorer }
35
+ end
36
+ end
@@ -30,7 +30,7 @@ DependencyDetection.defer do
30
30
  else
31
31
  NewRelic::Agent.logger.info('Detected Sequel version %s.' % [Sequel::VERSION])
32
32
  NewRelic::Agent.logger.info('Please see additional documentation: ' +
33
- 'https://newrelic.com/docs/ruby/sequel-instrumentation')
33
+ 'https://docs.newrelic.com/docs/apm/agents/ruby-agent/frameworks/sequel-instrumentation/')
34
34
  end
35
35
 
36
36
  Sequel.synchronize { Sequel::DATABASES.dup }.each do |db|
@@ -6,7 +6,11 @@ module NewRelic::Agent::Instrumentation::Sidekiq
6
6
  class Client
7
7
  include Sidekiq::ClientMiddleware if defined?(Sidekiq::ClientMiddleware)
8
8
 
9
+ INSTRUMENTATION_NAME = 'SidekiqClient'
10
+
9
11
  def call(_worker_class, job, *_)
12
+ NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
13
+
10
14
  job[NewRelic::NEWRELIC_KEY] ||= distributed_tracing_headers if ::NewRelic::Agent.config[:'distributed_tracing.enabled']
11
15
  yield
12
16
  end
@@ -7,9 +7,16 @@ module NewRelic::Agent::Instrumentation::Sidekiq
7
7
  include NewRelic::Agent::Instrumentation::ControllerInstrumentation
8
8
  include Sidekiq::ServerMiddleware if defined?(Sidekiq::ServerMiddleware)
9
9
 
10
+ ATTRIBUTE_BASE_NAMESPACE = 'sidekiq.args'
11
+ ATTRIBUTE_FILTER_TYPES = %i[include exclude].freeze
12
+ ATTRIBUTE_JOB_NAMESPACE = :"job.#{ATTRIBUTE_BASE_NAMESPACE}"
13
+ INSTRUMENTATION_NAME = 'SidekiqServer'
14
+
10
15
  # Client middleware has additional parameters, and our tests use the
11
16
  # middleware client-side to work inline.
12
17
  def call(worker, msg, queue, *_)
18
+ NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
19
+
13
20
  trace_args = if worker.respond_to?(:newrelic_trace_args)
14
21
  worker.newrelic_trace_args(msg, queue)
15
22
  else
@@ -18,10 +25,16 @@ module NewRelic::Agent::Instrumentation::Sidekiq
18
25
  trace_headers = msg.delete(NewRelic::NEWRELIC_KEY)
19
26
 
20
27
  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)
28
+ NewRelic::Agent::Transaction.merge_untrusted_agent_attributes(
29
+ NewRelic::Agent::AttributePreFiltering.pre_filter(msg['args'], self.class.nr_attribute_options),
30
+ ATTRIBUTE_JOB_NAMESPACE,
31
+ NewRelic::Agent::AttributeFilter::DST_NONE
32
+ )
33
+
34
+ if ::NewRelic::Agent.config[:'distributed_tracing.enabled'] && trace_headers&.any?
35
+ ::NewRelic::Agent::DistributedTracing::accept_distributed_trace_headers(trace_headers, 'Other')
36
+ end
23
37
 
24
- ::NewRelic::Agent::DistributedTracing::accept_distributed_trace_headers(trace_headers, 'Other') if ::NewRelic::Agent.config[:'distributed_tracing.enabled'] && trace_headers&.any?
25
38
  yield
26
39
  end
27
40
  end
@@ -33,5 +46,15 @@ module NewRelic::Agent::Instrumentation::Sidekiq
33
46
  :category => 'OtherTransaction/SidekiqJob'
34
47
  }
35
48
  end
49
+
50
+ def self.nr_attribute_options
51
+ @nr_attribute_options ||= begin
52
+ ATTRIBUTE_FILTER_TYPES.each_with_object({}) do |type, opts|
53
+ pattern =
54
+ NewRelic::Agent::AttributePreFiltering.formulate_regexp_union(:"#{ATTRIBUTE_BASE_NAMESPACE}.#{type}")
55
+ opts[type] = pattern if pattern
56
+ end.merge(attribute_namespace: ATTRIBUTE_JOB_NAMESPACE)
57
+ end
58
+ end
36
59
  end
37
60
  end
@@ -33,7 +33,9 @@ DependencyDetection.defer do
33
33
  end
34
34
 
35
35
  if config.respond_to?(:error_handlers)
36
- config.error_handlers << proc do |error, *_|
36
+ # Sidekiq 3.0.0 - 7.1.4 expect error_handlers to have 2 arguments
37
+ # Sidekiq 7.1.5+ expect error_handlers to have 3 arguments
38
+ config.error_handlers << proc do |error, _ctx, *_|
37
39
  NewRelic::Agent.notice_error(error)
38
40
  end
39
41
  end
@@ -43,8 +45,8 @@ DependencyDetection.defer do
43
45
  executes do
44
46
  next unless Gem::Version.new(Sidekiq::VERSION) < Gem::Version.new('5.0.0')
45
47
 
46
- deprecation_msg = 'Instrumentation for Sidekiq versions below 5.0.0 is deprecated.' \
47
- 'They will stop being monitored in version 9.0.0. ' \
48
+ deprecation_msg = 'Instrumentation for Sidekiq versions below 5.0.0 is deprecated ' \
49
+ 'and will be dropped entirely in a future major New Relic Ruby agent release.' \
48
50
  'Please upgrade your Sidekiq version to continue receiving full support. '
49
51
 
50
52
  NewRelic::Agent.logger.log_once(
@@ -13,6 +13,8 @@ module NewRelic::Agent::Instrumentation
13
13
  module Tracer
14
14
  include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
15
15
 
16
+ INSTRUMENTATION_NAME = 'Sinatra'
17
+
16
18
  def self.included(clazz)
17
19
  clazz.extend(self)
18
20
  end
@@ -90,6 +92,8 @@ module NewRelic::Agent::Instrumentation
90
92
  end
91
93
 
92
94
  def dispatch_with_tracing
95
+ NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
96
+
93
97
  request_params = get_request_params
94
98
  filtered_params = ::NewRelic::Agent::ParameterFiltering::apply_filters(request.env, request_params || {})
95
99
 
@@ -25,14 +25,12 @@ module NewRelic
25
25
  transaction_name(::NewRelic::Agent::UNKNOWN_METRIC, request)
26
26
  end
27
27
 
28
- ROOT = '/'.freeze
29
-
30
28
  def transaction_name(route_text, request)
31
29
  verb = http_verb(request)
32
30
 
33
31
  route_text = route_text.source if route_text.is_a?(Regexp)
34
32
  name = route_text.gsub(%r{^[/^\\A]*(.*?)[/\$\?\\z]*$}, '\1')
35
- name = ROOT if name.empty?
33
+ name = NewRelic::ROOT if name.empty?
36
34
  name = "#{verb} #{name}" unless verb.nil?
37
35
  name
38
36
  rescue => e
@@ -0,0 +1,28 @@
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/stripe_subscriber'
6
+
7
+ DependencyDetection.defer do
8
+ named :stripe
9
+
10
+ depends_on do
11
+ NewRelic::Agent.config[:'instrumentation.stripe'] == 'enabled'
12
+ end
13
+
14
+ depends_on do
15
+ defined?(Stripe) &&
16
+ Gem::Version.new(Stripe::VERSION) >= Gem::Version.new('5.38.0')
17
+ end
18
+
19
+ executes do
20
+ NewRelic::Agent.logger.info('Installing Stripe instrumentation')
21
+ end
22
+
23
+ executes do
24
+ newrelic_subscriber = NewRelic::Agent::Instrumentation::StripeSubscriber.new
25
+ Stripe::Instrumentation.subscribe(:request_begin) { |event| newrelic_subscriber.start_segment(event) }
26
+ Stripe::Instrumentation.subscribe(:request_end) { |event| newrelic_subscriber.finish_segment(event) }
27
+ end
28
+ end
@@ -0,0 +1,77 @@
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
6
+ module Agent
7
+ module Instrumentation
8
+ class StripeSubscriber
9
+ DEFAULT_DESTINATIONS = AttributeFilter::DST_SPAN_EVENTS
10
+ EVENT_ATTRIBUTES = %i[http_status method num_retries path request_id].freeze
11
+ ATTRIBUTE_NAMESPACE = 'stripe.user_data'
12
+ ATTRIBUTE_FILTER_TYPES = %i[include exclude].freeze
13
+
14
+ def start_segment(event)
15
+ return unless is_execution_traced?
16
+
17
+ segment = NewRelic::Agent::Tracer.start_segment(name: metric_name(event))
18
+ event.user_data[:newrelic_segment] = segment
19
+ rescue => e
20
+ NewRelic::Agent.logger.error("Error starting New Relic Stripe segment: #{e}")
21
+ end
22
+
23
+ def finish_segment(event)
24
+ return unless is_execution_traced?
25
+
26
+ segment = remove_and_return_nr_segment(event)
27
+ add_stripe_attributes(segment, event)
28
+ add_custom_attributes(segment, event)
29
+ rescue => e
30
+ NewRelic::Agent.logger.error("Error finishing New Relic Stripe segment: #{e}")
31
+ ensure
32
+ segment&.finish
33
+ end
34
+
35
+ private
36
+
37
+ def is_execution_traced?
38
+ NewRelic::Agent::Tracer.state.is_execution_traced?
39
+ end
40
+
41
+ def metric_name(event)
42
+ "Stripe#{event.path}/#{event.method}"
43
+ end
44
+
45
+ def add_stripe_attributes(segment, event)
46
+ EVENT_ATTRIBUTES.each do |attribute|
47
+ segment.add_agent_attribute("stripe_#{attribute}", event.send(attribute), DEFAULT_DESTINATIONS)
48
+ end
49
+ end
50
+
51
+ def add_custom_attributes(segment, event)
52
+ return if NewRelic::Agent.config[:'stripe.user_data.include'].empty?
53
+
54
+ filtered_attributes = NewRelic::Agent::AttributePreFiltering.pre_filter_hash(event.user_data, nr_attribute_options)
55
+ filtered_attributes.each do |key, value|
56
+ segment.add_agent_attribute("stripe_user_data_#{key}", value, DEFAULT_DESTINATIONS)
57
+ end
58
+ end
59
+
60
+ def nr_attribute_options
61
+ ATTRIBUTE_FILTER_TYPES.each_with_object({}) do |type, opts|
62
+ pattern =
63
+ NewRelic::Agent::AttributePreFiltering.formulate_regexp_union(:"#{ATTRIBUTE_NAMESPACE}.#{type}")
64
+ opts[type] = pattern if pattern
65
+ end
66
+ end
67
+
68
+ def remove_and_return_nr_segment(event)
69
+ segment = event.user_data[:newrelic_segment]
70
+ event.user_data.delete(:newrelic_segment)
71
+
72
+ segment
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -6,6 +6,8 @@ module NewRelic
6
6
  module Agent
7
7
  module Instrumentation
8
8
  module Tilt
9
+ INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name)
10
+
9
11
  def metric_name(klass, file)
10
12
  "View/#{klass}/#{file}/Rendering"
11
13
  end
@@ -21,6 +23,8 @@ module NewRelic
21
23
  end
22
24
 
23
25
  def render_with_tracing(*args, &block)
26
+ NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
27
+
24
28
  begin
25
29
  finishable = Tracer.start_segment(
26
30
  name: metric_name(self.class, create_filename_for_metric(self.file))
@@ -8,8 +8,8 @@ module NewRelic
8
8
  module Typhoeus
9
9
  HYDRA_SEGMENT_NAME = 'External/Multiple/Typhoeus::Hydra/run'
10
10
  NOTICEABLE_ERROR_CLASS = 'Typhoeus::Errors::TyphoeusError'
11
-
12
11
  EARLIEST_VERSION = Gem::Version.new('0.5.3')
12
+ INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name)
13
13
 
14
14
  def self.is_supported_version?
15
15
  Gem::Version.new(::Typhoeus::VERSION) >= EARLIEST_VERSION
@@ -31,6 +31,8 @@ module NewRelic
31
31
  end
32
32
 
33
33
  def with_tracing
34
+ NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
35
+
34
36
  segment = NewRelic::Agent::Tracer.start_segment(name: HYDRA_SEGMENT_NAME)
35
37
  instance_variable_set(:@__newrelic_hydra_segment, segment)
36
38
  begin
@@ -41,6 +43,8 @@ module NewRelic
41
43
  end
42
44
 
43
45
  def self.trace(request)
46
+ NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
47
+
44
48
  state = NewRelic::Agent::Tracer.state
45
49
  return unless state.is_execution_traced?
46
50
 
@@ -10,7 +10,7 @@ module NewRelic
10
10
  ATTRIBUTE_VALUE_CHARACTER_LIMIT = 4094
11
11
 
12
12
  def add_custom_attributes(attributes)
13
- return if @custom_attribute_limit_reached
13
+ return if defined?(@custom_attribute_limit_reached) && @custom_attribute_limit_reached
14
14
 
15
15
  attributes.each do |key, value|
16
16
  next if absent?(key) || absent?(value)
@@ -329,9 +329,9 @@ module NewRelic
329
329
 
330
330
  def transaction_name(library, destination_type, destination_name)
331
331
  transaction_name = Transaction::MESSAGE_PREFIX + library
332
- transaction_name << Transaction::MessageBrokerSegment::SLASH
332
+ transaction_name << NewRelic::SLASH
333
333
  transaction_name << Transaction::MessageBrokerSegment::TYPES[destination_type]
334
- transaction_name << Transaction::MessageBrokerSegment::SLASH
334
+ transaction_name << NewRelic::SLASH
335
335
 
336
336
  case destination_type
337
337
  when :queue
@@ -5,7 +5,8 @@
5
5
  module NewRelic
6
6
  module Agent
7
7
  class SyntheticsMonitor < InboundRequestMonitor
8
- SYNTHETICS_HEADER_KEY = 'HTTP_X_NEWRELIC_SYNTHETICS'.freeze
8
+ SYNTHETICS_HEADER_KEY = 'HTTP_X_NEWRELIC_SYNTHETICS'
9
+ SYNTHETICS_INFO_HEADER_KEY = 'HTTP_X_NEWRELIC_SYNTHETICS_INFO'
9
10
 
10
11
  SUPPORTED_VERSION = 1
11
12
  EXPECTED_PAYLOAD_LENGTH = 5
@@ -16,6 +17,7 @@ module NewRelic
16
17
 
17
18
  def on_before_call(request) # THREAD_LOCAL_ACCESS
18
19
  encoded_header = request[SYNTHETICS_HEADER_KEY]
20
+ info_header = request[SYNTHETICS_INFO_HEADER_KEY]
19
21
  return unless encoded_header
20
22
 
21
23
  incoming_payload = deserialize_header(encoded_header, SYNTHETICS_HEADER_KEY)
@@ -27,7 +29,16 @@ module NewRelic
27
29
 
28
30
  txn = Tracer.current_transaction
29
31
  txn.raw_synthetics_header = encoded_header
32
+ txn.raw_synthetics_info_header = info_header
30
33
  txn.synthetics_payload = incoming_payload
34
+ txn.synthetics_info_payload = load_json(info_header, SYNTHETICS_INFO_HEADER_KEY)
35
+ end
36
+
37
+ def load_json(header, key)
38
+ ::JSON.load(header)
39
+ rescue => err
40
+ NewRelic::Agent.logger.debug("Failure loading json header '#{key}' in #{self.class}, #{err.class}, #{err.message}")
41
+ nil
31
42
  end
32
43
 
33
44
  class << self