newrelic_rpm 9.2.2 → 9.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/.build_ignore +26 -0
  3. data/CHANGELOG.md +168 -0
  4. data/README.md +8 -4
  5. data/lib/new_relic/agent/attribute_pre_filtering.rb +109 -0
  6. data/lib/new_relic/agent/configuration/default_source.rb +176 -32
  7. data/lib/new_relic/agent/configuration/environment_source.rb +1 -1
  8. data/lib/new_relic/agent/configuration/manager.rb +3 -2
  9. data/lib/new_relic/agent/configuration/yaml_source.rb +13 -0
  10. data/lib/new_relic/agent/distributed_tracing.rb +1 -1
  11. data/lib/new_relic/agent/instrumentation/action_controller_other_subscriber.rb +1 -1
  12. data/lib/new_relic/agent/instrumentation/active_record.rb +1 -1
  13. data/lib/new_relic/agent/instrumentation/active_record_notifications.rb +2 -1
  14. data/lib/new_relic/agent/instrumentation/active_support_logger/instrumentation.rb +4 -0
  15. data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +9 -0
  16. data/lib/new_relic/agent/instrumentation/concurrent_ruby/chain.rb +1 -1
  17. data/lib/new_relic/agent/instrumentation/concurrent_ruby/instrumentation.rb +3 -4
  18. data/lib/new_relic/agent/instrumentation/concurrent_ruby/prepend.rb +1 -1
  19. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +1 -2
  20. data/lib/new_relic/agent/instrumentation/curb/instrumentation.rb +4 -0
  21. data/lib/new_relic/agent/instrumentation/delayed_job/instrumentation.rb +3 -0
  22. data/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb +4 -1
  23. data/lib/new_relic/agent/instrumentation/excon/middleware.rb +3 -0
  24. data/lib/new_relic/agent/instrumentation/fiber/chain.rb +10 -3
  25. data/lib/new_relic/agent/instrumentation/fiber/instrumentation.rb +1 -2
  26. data/lib/new_relic/agent/instrumentation/fiber/prepend.rb +10 -3
  27. data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +4 -0
  28. data/lib/new_relic/agent/instrumentation/grpc/client/instrumentation.rb +4 -0
  29. data/lib/new_relic/agent/instrumentation/grpc/server/instrumentation.rb +4 -0
  30. data/lib/new_relic/agent/instrumentation/grpc_client.rb +1 -1
  31. data/lib/new_relic/agent/instrumentation/grpc_server.rb +1 -1
  32. data/lib/new_relic/agent/instrumentation/httpclient/instrumentation.rb +4 -0
  33. data/lib/new_relic/agent/instrumentation/httprb/instrumentation.rb +4 -0
  34. data/lib/new_relic/agent/instrumentation/logger/instrumentation.rb +3 -0
  35. data/lib/new_relic/agent/instrumentation/memcache/instrumentation.rb +12 -3
  36. data/lib/new_relic/agent/instrumentation/memcache.rb +2 -2
  37. data/lib/new_relic/agent/instrumentation/net_http/instrumentation.rb +4 -0
  38. data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +4 -0
  39. data/lib/new_relic/agent/instrumentation/padrino/instrumentation.rb +4 -0
  40. data/lib/new_relic/agent/instrumentation/queue_time.rb +1 -1
  41. data/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +6 -0
  42. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +4 -0
  43. data/lib/new_relic/agent/instrumentation/rails_notifications/action_cable.rb +1 -1
  44. data/lib/new_relic/agent/instrumentation/rake/instrumentation.rb +4 -0
  45. data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +4 -0
  46. data/lib/new_relic/agent/instrumentation/resque/instrumentation.rb +4 -0
  47. data/lib/new_relic/agent/instrumentation/roda/chain.rb +43 -0
  48. data/lib/new_relic/agent/instrumentation/roda/instrumentation.rb +56 -0
  49. data/lib/new_relic/agent/instrumentation/roda/prepend.rb +24 -0
  50. data/lib/new_relic/agent/instrumentation/roda/roda_transaction_namer.rb +30 -0
  51. data/lib/new_relic/agent/instrumentation/roda.rb +34 -0
  52. data/lib/new_relic/agent/instrumentation/sequel.rb +1 -1
  53. data/lib/new_relic/agent/instrumentation/sidekiq/client.rb +4 -0
  54. data/lib/new_relic/agent/instrumentation/sidekiq/server.rb +26 -3
  55. data/lib/new_relic/agent/instrumentation/sidekiq.rb +2 -2
  56. data/lib/new_relic/agent/instrumentation/sinatra/instrumentation.rb +4 -0
  57. data/lib/new_relic/agent/instrumentation/stripe.rb +28 -0
  58. data/lib/new_relic/agent/instrumentation/stripe_subscriber.rb +77 -0
  59. data/lib/new_relic/agent/instrumentation/thread/chain.rb +1 -1
  60. data/lib/new_relic/agent/instrumentation/thread/instrumentation.rb +0 -1
  61. data/lib/new_relic/agent/instrumentation/thread/prepend.rb +1 -1
  62. data/lib/new_relic/agent/instrumentation/tilt/instrumentation.rb +4 -0
  63. data/lib/new_relic/agent/instrumentation/typhoeus/instrumentation.rb +5 -1
  64. data/lib/new_relic/agent/log_event_aggregator.rb +49 -2
  65. data/lib/new_relic/agent/log_event_attributes.rb +115 -0
  66. data/lib/new_relic/agent/logging.rb +4 -4
  67. data/lib/new_relic/agent/method_tracer_helpers.rb +26 -5
  68. data/lib/new_relic/agent/new_relic_service.rb +33 -17
  69. data/lib/new_relic/agent/pipe_service.rb +1 -1
  70. data/lib/new_relic/agent/tracer.rb +6 -5
  71. data/lib/new_relic/agent/transaction/abstract_segment.rb +52 -0
  72. data/lib/new_relic/agent/transaction/request_attributes.rb +45 -7
  73. data/lib/new_relic/agent/transaction.rb +5 -4
  74. data/lib/new_relic/agent/utilization/vendor.rb +5 -7
  75. data/lib/new_relic/agent.rb +50 -1
  76. data/lib/new_relic/cli/command.rb +1 -0
  77. data/lib/new_relic/control/class_methods.rb +1 -7
  78. data/lib/new_relic/control/frameworks/roda.rb +20 -0
  79. data/lib/new_relic/dependency_detection.rb +6 -0
  80. data/lib/new_relic/language_support.rb +5 -0
  81. data/lib/new_relic/latest_changes.rb +1 -1
  82. data/lib/new_relic/noticed_error.rb +5 -2
  83. data/lib/new_relic/rack/agent_hooks.rb +1 -1
  84. data/lib/new_relic/rack/agent_middleware.rb +0 -16
  85. data/lib/new_relic/rack/browser_monitoring.rb +1 -1
  86. data/lib/new_relic/supportability_helper.rb +2 -0
  87. data/lib/new_relic/traced_thread.rb +2 -3
  88. data/lib/new_relic/version.rb +2 -2
  89. data/lib/sequel/extensions/new_relic_instrumentation.rb +1 -1
  90. data/lib/tasks/bump_version.rake +21 -0
  91. data/lib/tasks/config.rake +3 -2
  92. data/lib/tasks/helpers/config.html.erb +93 -0
  93. data/lib/tasks/helpers/format.rb +11 -7
  94. data/lib/tasks/helpers/newrelicyml.rb +144 -0
  95. data/lib/tasks/helpers/version_bump.rb +62 -0
  96. data/lib/tasks/newrelicyml.rake +13 -0
  97. data/newrelic.yml +362 -265
  98. data/newrelic_rpm.gemspec +11 -7
  99. metadata +36 -25
  100. data/.gitignore +0 -43
  101. data/.project +0 -23
  102. data/.rubocop.yml +0 -1845
  103. data/.rubocop_todo.yml +0 -61
  104. data/.simplecov +0 -16
  105. data/.snyk +0 -11
  106. data/.yardopts +0 -27
  107. data/Brewfile +0 -13
  108. data/DOCKER.md +0 -167
  109. data/Dockerfile +0 -10
  110. data/Guardfile +0 -27
  111. data/config/database.yml +0 -5
  112. data/config.dot +0 -278
  113. data/docker-compose.yml +0 -107
  114. data/lefthook.yml +0 -9
  115. data/lib/tasks/helpers/removers.rb +0 -33
  116. data/lib/tasks/multiverse.rake +0 -6
  117. data/lib/tasks/multiverse.rb +0 -84
@@ -3,7 +3,6 @@
3
3
  # frozen_string_literal: true
4
4
 
5
5
  require 'zlib'
6
- require 'timeout'
7
6
  require 'new_relic/agent/audit_logger'
8
7
  require 'new_relic/agent/new_relic_service/encoders'
9
8
  require 'new_relic/agent/new_relic_service/marshaller'
@@ -19,7 +18,13 @@ module NewRelic
19
18
 
20
19
  # These include Errno connection errors, and all indicate that the
21
20
  # underlying TCP connection may be in a bad state.
22
- CONNECTION_ERRORS = [Timeout::Error, EOFError, SystemCallError, SocketError].freeze
21
+ CONNECTION_ERRORS = [Net::OpenTimeout, Net::ReadTimeout, EOFError, SystemCallError, SocketError]
22
+ # TODO: MAJOR VERSION - Net::WriteTimeout wasn't defined until Ruby 2.6.
23
+ # Once support for Ruby 2.5 is dropped, we should simply include
24
+ # Net::WriteTimeout in the connection errors array directly instead
25
+ # of with a conditional
26
+ CONNECTION_ERRORS << Net::WriteTimeout if defined?(Net::WriteTimeout)
27
+ CONNECTION_ERRORS.freeze
23
28
 
24
29
  # The maximum number of times to attempt an HTTP request
25
30
  MAX_ATTEMPTS = 2
@@ -319,13 +324,15 @@ module NewRelic
319
324
 
320
325
  def start_connection(conn)
321
326
  NewRelic::Agent.logger.debug("Opening TCP connection to #{conn.address}:#{conn.port}")
322
- Timeout.timeout(@request_timeout) { conn.start }
323
- conn
327
+ conn.start
324
328
  end
325
329
 
326
330
  def setup_connection_timeouts(conn)
327
- # We use Timeout explicitly instead of this
328
- conn.read_timeout = nil
331
+ conn.open_timeout = @request_timeout
332
+ conn.read_timeout = @request_timeout
333
+ # TODO: MAJOR VERSION - #write_timeout= requires Ruby 2.6+, so remove
334
+ # the conditional check once support for Ruby 2.5 is dropped
335
+ conn.write_timeout = @request_timeout if conn.respond_to?(:write_timeout=)
329
336
 
330
337
  if conn.respond_to?(:keep_alive_timeout) && NewRelic::Agent.config[:aggressive_keepalive]
331
338
  conn.keep_alive_timeout = NewRelic::Agent.config[:keep_alive_timeout]
@@ -362,8 +369,8 @@ module NewRelic
362
369
  conn = create_http_connection
363
370
  start_connection(conn)
364
371
  conn
365
- rescue Timeout::Error
366
- ::NewRelic::Agent.logger.info('Timeout while attempting to connect. You may need to install system-level CA Certificates, as the ruby agent no longer includes these.')
372
+ rescue Net::OpenTimeout
373
+ ::NewRelic::Agent.logger.info('Timed out while attempting to connect. For SSL issues, you may need to install system-level CA Certificates to be used by Net::HTTP.')
367
374
  raise
368
375
  end
369
376
 
@@ -436,13 +443,9 @@ module NewRelic
436
443
  end
437
444
 
438
445
  def attempt_request(request, opts)
439
- response = nil
440
446
  conn = http_connection
441
447
  ::NewRelic::Agent.logger.debug("Sending request to #{opts[:collector]}#{opts[:uri]} with #{request.method}")
442
- Timeout.timeout(@request_timeout) do
443
- response = conn.request(request)
444
- end
445
- response
448
+ conn.request(request)
446
449
  end
447
450
 
448
451
  def handle_error_response(response, endpoint)
@@ -450,7 +453,9 @@ module NewRelic
450
453
  when Net::HTTPRequestTimeOut,
451
454
  Net::HTTPTooManyRequests,
452
455
  Net::HTTPInternalServerError,
453
- Net::HTTPServiceUnavailable
456
+ Net::HTTPServiceUnavailable,
457
+ Net::OpenTimeout,
458
+ Net::ReadTimeout
454
459
  handle_server_connection_exception(response, endpoint)
455
460
  when Net::HTTPBadRequest,
456
461
  Net::HTTPForbidden,
@@ -471,9 +476,20 @@ module NewRelic
471
476
  when Net::HTTPGone
472
477
  handle_gone_response(response, endpoint)
473
478
  else
474
- record_endpoint_attempts_supportability_metrics(endpoint)
475
- record_error_response_supportability_metrics(response.code)
476
- raise UnrecoverableServerException, "#{response.code}: #{response.message}"
479
+ # TODO: MAJOR VERSION - Net::WriteTimeout wasn't defined until
480
+ # Ruby 2.6, so it can't be included in the case statement
481
+ # as a constant and instead needs to be found here. Once
482
+ # support for Ruby 2.5 is dropped, we should have
483
+ # Net::WriteTimeout sit in the 'when' clause above alongside
484
+ # Net::OpenTimeout and Net::ReadTimeout and this entire if/else
485
+ # conditional can be removed.
486
+ if response.respond_to?(:name) && response.name == 'Net::WriteTimeout'
487
+ handle_server_connection_exception(response, endpoint)
488
+ else
489
+ record_endpoint_attempts_supportability_metrics(endpoint)
490
+ record_error_response_supportability_metrics(response.code)
491
+ raise UnrecoverableServerException, "#{response.code}: #{response.message}"
492
+ end
477
493
  end
478
494
  response
479
495
  end
@@ -15,7 +15,7 @@ module NewRelic
15
15
  if @pipe && @pipe.parent_pid != $$
16
16
  @pipe.after_fork_in_child
17
17
  else
18
- NewRelic::Agent.logger.error('No communication channel to parent process, please see https://newrelic.com/docs/ruby/resque-instrumentation for more information.')
18
+ NewRelic::Agent.logger.error('No communication channel to parent process, please see https://docs.newrelic.com/docs/apm/agents/ruby-agent/background-jobs/resque-instrumentation/ for more information.')
19
19
  end
20
20
  end
21
21
 
@@ -66,9 +66,10 @@ module NewRelic
66
66
  #
67
67
  # @api public
68
68
  def transaction_sampled?
69
- if txn = current_transaction
70
- txn.sampled?
71
- end
69
+ txn = current_transaction
70
+ return false unless txn
71
+
72
+ txn.sampled?
72
73
  end
73
74
  alias_method :sampled?, :transaction_sampled?
74
75
 
@@ -419,10 +420,10 @@ module NewRelic
419
420
  NewRelic::Agent.config[:'instrumentation.thread.tracing']
420
421
  end
421
422
 
422
- def thread_block_with_current_transaction(*args, segment_name:, parent: nil, &block)
423
+ def thread_block_with_current_transaction(segment_name:, parent: nil, &block)
423
424
  parent ||= current_segment
424
425
  current_txn = ::Thread.current[:newrelic_tracer_state]&.current_transaction if ::Thread.current[:newrelic_tracer_state]&.is_execution_traced?
425
- proc do
426
+ proc do |*args|
426
427
  begin
427
428
  if current_txn && !current_txn.finished?
428
429
  NewRelic::Agent::Tracer.state.current_transaction = current_txn
@@ -24,6 +24,9 @@ module NewRelic
24
24
  attr_writer :record_metrics, :record_scoped_metric, :record_on_finish
25
25
  attr_reader :noticed_error
26
26
 
27
+ CALLBACK = :@callback
28
+ SEGMENT = 'segment'
29
+
27
30
  def initialize(name = nil, start_time = nil)
28
31
  @name = name
29
32
  @starting_segment_key = NewRelic::Agent::Tracer.current_segment_key
@@ -49,6 +52,7 @@ module NewRelic
49
52
  @code_function = nil
50
53
  @code_lineno = nil
51
54
  @code_namespace = nil
55
+ invoke_callback
52
56
  end
53
57
 
54
58
  def start
@@ -327,6 +331,54 @@ module NewRelic
327
331
  Tracer.state
328
332
  end
329
333
  end
334
+
335
+ # for segment callback usage info, see self.set_segment_callback
336
+ def invoke_callback
337
+ return unless self.class.instance_variable_defined?(CALLBACK)
338
+
339
+ NewRelic::Agent.logger.debug("Invoking callback for #{self.class.name}...")
340
+ self.class.instance_variable_get(CALLBACK).call
341
+ end
342
+
343
+ # Setting and invoking a segment callback
344
+ # =======================================
345
+ # Each individual segment class such as `ExternalRequestSegment` allows
346
+ # for exactly one instance of a `Proc` (meaning a proc or lambda) to be
347
+ # set as a callback. A callback can be set on a segment class by calling
348
+ # `.set_segment_callback` with a proc or lambda as the only argument.
349
+ # If set, the callback will be invoked with `#call` at segment class
350
+ # initialization time.
351
+ #
352
+ # Example usage:
353
+ # callback = -> { puts 'Hello, World! }
354
+ # ExternalRequestSegment.set_segment_callback(callback)
355
+ # ExternalRequestSegment.new(library, uri, procedure)
356
+ #
357
+ # A callback set on a segment class will only be called when that
358
+ # specific segment class is initialized. Other segment classes will not
359
+ # be impacted.
360
+ #
361
+ # Great caution should be taken in the defining of the callback block
362
+ # to not have the block perform anything too time consuming or resource
363
+ # intensive in order to keep the New Relic Ruby agent operating
364
+ # normally.
365
+ #
366
+ # Given that callbacks are user defined, they must be set entirely at
367
+ # the user's own risk. It is recommended that each callback use
368
+ # conditional logic that only performs work for certain qualified
369
+ # segments. It is recommended that each callback be thoroughly tested
370
+ # in non-production environments before being introduced to production
371
+ # environments.
372
+ def self.set_segment_callback(callback_proc)
373
+ unless callback_proc.is_a?(Proc)
374
+ NewRelic::Agent.logger.error("#{self}.#{__method__}: expected an argument of type Proc, " \
375
+ "got #{callback_proc.class}")
376
+ return
377
+ end
378
+
379
+ NewRelic::Agent.record_api_supportability_metric(:set_segment_callback)
380
+ instance_variable_set(CALLBACK, callback_proc)
381
+ end
330
382
  end
331
383
  end
332
384
  end
@@ -8,11 +8,17 @@ module NewRelic
8
8
  module Agent
9
9
  class Transaction
10
10
  class RequestAttributes
11
- attr_reader :request_path, :referer, :accept, :content_length, :content_type,
12
- :host, :port, :user_agent, :request_method
11
+ # the HTTP standard has "referrer" mispelled as "referer"
12
+ attr_reader :accept, :content_length, :content_type, :host, :other_headers, :port, :referer, :request_method,
13
+ :request_path, :user_agent
13
14
 
14
15
  HTTP_ACCEPT_HEADER_KEY = 'HTTP_ACCEPT'.freeze
15
16
 
17
+ BASE_HEADERS = %w[CONTENT_LENGTH CONTENT_TYPE HTTP_ACCEPT HTTP_REFERER HTTP_USER_AGENT PATH_INFO REMOTE_HOST
18
+ REQUEST_METHOD REQUEST_URI SERVER_PORT].freeze
19
+
20
+ ATTRIBUTE_PREFIX = 'request.headers.'
21
+
16
22
  def initialize(request)
17
23
  @request_path = path_from_request(request)
18
24
  @referer = referer_from_request(request)
@@ -23,6 +29,7 @@ module NewRelic
23
29
  @port = port_from_request(request)
24
30
  @user_agent = attribute_from_request(request, :user_agent)
25
31
  @request_method = attribute_from_request(request, :request_method)
32
+ @other_headers = other_headers_from_request(request)
26
33
  end
27
34
 
28
35
  def assign_agent_attributes(txn)
@@ -31,14 +38,17 @@ module NewRelic
31
38
  AttributeFilter::DST_ERROR_COLLECTOR
32
39
 
33
40
  if referer
34
- txn.add_agent_attribute(:'request.headers.referer', referer, AttributeFilter::DST_ERROR_COLLECTOR)
41
+ destinations = allow_other_headers? ? default_destinations : AttributeFilter::DST_ERROR_COLLECTOR
42
+ txn.add_agent_attribute(:'request.headers.referer', referer, destinations)
35
43
  end
36
44
 
37
45
  if request_path
38
- txn.add_agent_attribute(:'request.uri',
39
- request_path,
40
- AttributeFilter::DST_TRANSACTION_TRACER |
41
- AttributeFilter::DST_ERROR_COLLECTOR)
46
+ destinations = if allow_other_headers?
47
+ default_destinations
48
+ else
49
+ AttributeFilter::DST_TRANSACTION_TRACER | AttributeFilter::DST_ERROR_COLLECTOR
50
+ end
51
+ txn.add_agent_attribute(:'request.uri', request_path, destinations)
42
52
  end
43
53
 
44
54
  if accept
@@ -64,6 +74,14 @@ module NewRelic
64
74
  if request_method
65
75
  txn.add_agent_attribute(:'request.method', request_method, default_destinations)
66
76
  end
77
+
78
+ if port && allow_other_headers?
79
+ txn.add_agent_attribute(:'request.headers.port', port, default_destinations)
80
+ end
81
+
82
+ other_headers.each do |header, value|
83
+ txn.add_agent_attribute(header, value, default_destinations)
84
+ end
67
85
  end
68
86
 
69
87
  private
@@ -116,6 +134,26 @@ module NewRelic
116
134
  env[key]
117
135
  end
118
136
  end
137
+
138
+ def allow_other_headers?
139
+ NewRelic::Agent.config[:allow_all_headers] && !NewRelic::Agent.config[:high_security]
140
+ end
141
+
142
+ def other_headers_from_request(request)
143
+ # confirm that `request` is an instance of `Rack::Request` by checking
144
+ # for #each_header
145
+ return NewRelic::EMPTY_HASH unless allow_other_headers? && request.respond_to?(:each_header)
146
+
147
+ request.each_header.with_object({}) do |(header, value), hash|
148
+ next if BASE_HEADERS.include?(header)
149
+
150
+ hash[formatted_header(header)] = value
151
+ end
152
+ end
153
+
154
+ def formatted_header(raw_name)
155
+ "#{ATTRIBUTE_PREFIX}#{NewRelic::LanguageSupport.camelize_with_first_letter_downcased(raw_name)}".to_sym
156
+ end
119
157
  end
120
158
  end
121
159
  end
@@ -31,11 +31,12 @@ module NewRelic
31
31
  RAKE_PREFIX = "#{OTHER_TRANSACTION_PREFIX}Rake/"
32
32
  MESSAGE_PREFIX = "#{OTHER_TRANSACTION_PREFIX}Message/"
33
33
  RACK_PREFIX = "#{CONTROLLER_PREFIX}Rack/"
34
+ RODA_PREFIX = "#{CONTROLLER_PREFIX}Roda/"
34
35
  SINATRA_PREFIX = "#{CONTROLLER_PREFIX}Sinatra/"
35
36
  GRAPE_PREFIX = "#{CONTROLLER_PREFIX}Grape/"
36
37
  ACTION_CABLE_PREFIX = "#{CONTROLLER_PREFIX}ActionCable/"
37
38
 
38
- WEB_TRANSACTION_CATEGORIES = [:web, :controller, :uri, :rack, :sinatra, :grape, :middleware, :action_cable].freeze
39
+ WEB_TRANSACTION_CATEGORIES = %i[action_cable controller grape middleware rack roda sinatra web uri].freeze
39
40
 
40
41
  MIDDLEWARE_SUMMARY_METRICS = ['Middleware/all'].freeze
41
42
  WEB_SUMMARY_METRIC = 'HttpDispatcher'
@@ -289,7 +290,7 @@ module NewRelic
289
290
  end
290
291
 
291
292
  def sampled?
292
- return unless Agent.config[:'distributed_tracing.enabled']
293
+ return false unless Agent.config[:'distributed_tracing.enabled']
293
294
 
294
295
  if @sampled.nil?
295
296
  @sampled = NewRelic::Agent.instance.adaptive_sampler.sampled?
@@ -545,8 +546,8 @@ module NewRelic
545
546
  end
546
547
 
547
548
  def user_defined_rules_ignore?
548
- return unless request_path
549
- return if (rules = NewRelic::Agent.config[:"rules.ignore_url_regexes"]).empty?
549
+ return false unless request_path
550
+ return false if (rules = NewRelic::Agent.config[:"rules.ignore_url_regexes"]).empty?
550
551
 
551
552
  rules.any? do |rule|
552
553
  request_path.match(rule)
@@ -75,14 +75,12 @@ module NewRelic
75
75
  processed_headers = headers
76
76
  raise if processed_headers.value?(:error)
77
77
 
78
- Timeout.timeout(1) do
79
- response = nil
80
- Net::HTTP.start(endpoint.host, endpoint.port) do |http|
81
- req = Net::HTTP::Get.new(endpoint, processed_headers)
82
- response = http.request(req)
83
- end
84
- response
78
+ response = nil
79
+ Net::HTTP.start(endpoint.host, endpoint.port, open_timeout: 1, read_timeout: 1) do |http|
80
+ req = Net::HTTP::Get.new(endpoint, processed_headers)
81
+ response = http.request(req)
85
82
  end
83
+ response
86
84
  rescue
87
85
  NewRelic::Agent.logger.debug("#{vendor_name} environment not detected")
88
86
  end
@@ -58,6 +58,7 @@ module NewRelic
58
58
  require 'new_relic/agent/deprecator'
59
59
  require 'new_relic/agent/logging'
60
60
  require 'new_relic/agent/distributed_tracing'
61
+ require 'new_relic/agent/attribute_pre_filtering'
61
62
  require 'new_relic/agent/attribute_processing'
62
63
  require 'new_relic/agent/linking_metadata'
63
64
  require 'new_relic/agent/local_log_decorator'
@@ -213,6 +214,17 @@ module NewRelic
213
214
  record_metric(metric_name, value)
214
215
  end
215
216
 
217
+ def record_instrumentation_invocation(library)
218
+ record_metric_once("Supportability/#{library}/Invoked")
219
+ end
220
+
221
+ # see ActiveSupport::Inflector.demodulize
222
+ def base_name(klass_name)
223
+ return klass_name unless ridx = klass_name.rindex('::')
224
+
225
+ klass_name[(ridx + 2), klass_name.length]
226
+ end
227
+
216
228
  SUPPORTABILITY_INCREMENT_METRIC = 'Supportability/API/increment_metric'.freeze
217
229
 
218
230
  # Increment a simple counter metric.
@@ -298,7 +310,7 @@ module NewRelic
298
310
 
299
311
  # Set a callback proc for determining an error's error group name
300
312
  #
301
- # @param [Proc] the callback proc
313
+ # @param callback_proc [Proc] the callback proc
302
314
  #
303
315
  # Typically this method should be called only once to set a callback for
304
316
  # use with all noticed errors. If it is called multiple times, each new
@@ -649,6 +661,43 @@ module NewRelic
649
661
  end
650
662
  end
651
663
 
664
+ # Add custom attributes to log events for the current agent instance.
665
+ #
666
+ # @param [Hash] params A Hash of attributes to attach to log
667
+ # events. The agent accepts up to 240 custom
668
+ # log event attributes.
669
+ #
670
+ # Keys will be coerced into Strings and must
671
+ # be less than 256 characters. Keys longer
672
+ # than 255 characters will be truncated.
673
+ #
674
+ # Values may be Strings, Symbols, numeric
675
+ # values or Booleans and must be less than
676
+ # 4095 characters. If the value is a String
677
+ # or a Symbol, values longer than 4094
678
+ # characters will be truncated. If the value
679
+ # exceeds 4094 characters and is of a
680
+ # different class, the attribute pair will
681
+ # be dropped.
682
+ #
683
+ # This API can be called multiple times.
684
+ # If the same key is passed more than once,
685
+ # the value associated with the last call
686
+ # will be preserved.
687
+ #
688
+ # Attribute pairs with empty or nil contents
689
+ # will be dropped.
690
+ # @api public
691
+ def add_custom_log_attributes(params)
692
+ record_api_supportability_metric(:add_custom_log_attributes)
693
+
694
+ if params.is_a?(Hash)
695
+ NewRelic::Agent.agent.log_event_aggregator.add_custom_attributes(params)
696
+ else
697
+ NewRelic::Agent.logger.warn("Bad argument passed to #add_custom_log_attributes. Expected Hash but got #{params.class}.")
698
+ end
699
+ end
700
+
652
701
  # Set the user id for the current transaction. When present, this value will be included in the agent attributes for transaction and error events as 'enduser.id'.
653
702
  #
654
703
  # @param [String] user_id The user id to add to the current transaction attributes
@@ -60,6 +60,7 @@ module NewRelic
60
60
  extra = []
61
61
  options = ARGV.options do |opts|
62
62
  script_name = File.basename($0)
63
+ # TODO: MAJOR VERSION - remove newrelic_cmd, deprecated since version 2.13
63
64
  if /newrelic_cmd$/.match?(script_name)
64
65
  $stdout.puts "warning: the 'newrelic_cmd' script has been renamed 'newrelic'"
65
66
  script_name = 'newrelic'
@@ -49,19 +49,13 @@ module NewRelic
49
49
  # maybe it is already loaded by some external system
50
50
  # i.e. rpm_contrib or user extensions?
51
51
  end
52
- NewRelic::Control::Frameworks.const_get(camelize(framework.to_s))
52
+ NewRelic::Control::Frameworks.const_get(NewRelic::LanguageSupport.camelize(framework.to_s))
53
53
  end
54
54
 
55
55
  # The root directory for the plugin or gem
56
56
  def newrelic_root
57
57
  File.expand_path(File.join('..', '..', '..', '..'), __FILE__)
58
58
  end
59
-
60
- def camelize(snake_case_name)
61
- snake_case_name.gsub(/(\_|^)[a-z]/) do |substring|
62
- substring[-1].capitalize!
63
- end
64
- end
65
59
  end
66
60
  extend ClassMethods
67
61
  end
@@ -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
+ require 'new_relic/control/frameworks/ruby'
6
+ module NewRelic
7
+ class Control
8
+ module Frameworks
9
+ # Contains basic control logic for Roda
10
+ class Roda < NewRelic::Control::Frameworks::Ruby
11
+ protected
12
+
13
+ def install_shim
14
+ super
15
+ ::Roda.class_eval { include NewRelic::Agent::Instrumentation::ControllerInstrumentation::Shim }
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -27,6 +27,8 @@ module DependencyDetection
27
27
  @items.each do |item|
28
28
  if item.dependencies_satisfied?
29
29
  item.execute
30
+ else
31
+ item.configure_as_unsatisfied unless item.disabled_configured?
30
32
  end
31
33
  end
32
34
  end
@@ -62,6 +64,10 @@ module DependencyDetection
62
64
  !executed and check_dependencies
63
65
  end
64
66
 
67
+ def configure_as_unsatisfied
68
+ NewRelic::Agent.config.instance_variable_get(:@cache)[config_key] = :unsatisfied
69
+ end
70
+
65
71
  def source_location_for(klass, method_name)
66
72
  Object.instance_method(:method).bind(klass.allocate).call(method_name).source_location.to_s
67
73
  end
@@ -78,6 +78,11 @@ module NewRelic
78
78
  camelized.split(/\-|\_/).map(&:capitalize).join
79
79
  end
80
80
 
81
+ def camelize_with_first_letter_downcased(string)
82
+ camelized = camelize(string)
83
+ camelized[0].downcase.concat(camelized[1..-1])
84
+ end
85
+
81
86
  def bundled_gem?(gem_name)
82
87
  defined?(Bundler) && Bundler.rubygems.all_specs.map(&:name).include?(gem_name)
83
88
  rescue => e
@@ -8,7 +8,7 @@ module NewRelic
8
8
  File.join(File.dirname(__FILE__), '..', '..', 'CHANGELOG.md')
9
9
  end
10
10
 
11
- FOOTER = <<'EOS'
11
+ FOOTER = <<EOS
12
12
  See https://github.com/newrelic/newrelic-ruby-agent/blob/main/CHANGELOG.md for a full list of
13
13
  changes.
14
14
  EOS
@@ -13,7 +13,7 @@ class NewRelic::NoticedError
13
13
  attr_accessor :path, :timestamp, :message, :exception_class_name,
14
14
  :request_uri, :request_port, :file_name, :line_number,
15
15
  :stack_trace, :attributes_from_notice_error, :attributes,
16
- :expected
16
+ :expected, :transaction_id
17
17
 
18
18
  attr_reader :error_group, :exception_id, :is_internal
19
19
 
@@ -45,6 +45,7 @@ class NewRelic::NoticedError
45
45
  @is_internal = (exception.class < NewRelic::Agent::InternalAgentError)
46
46
 
47
47
  extract_class_name_and_message_from(exception)
48
+ @transaction_id = NewRelic::Agent::Tracer&.current_transaction&.guid
48
49
 
49
50
  # clamp long messages to 4k so that we don't send a lot of
50
51
  # overhead across the wire
@@ -79,11 +80,13 @@ class NewRelic::NoticedError
79
80
  include NewRelic::Coerce
80
81
 
81
82
  def to_collector_array(encoder = nil)
82
- [NewRelic::Helper.time_to_millis(timestamp),
83
+ arr = [NewRelic::Helper.time_to_millis(timestamp),
83
84
  string(path),
84
85
  string(message),
85
86
  string(exception_class_name),
86
87
  processed_attributes]
88
+ arr << @transaction_id if @transaction_id
89
+ arr
87
90
  end
88
91
 
89
92
  # Note that we process attributes lazily and store the result. This is because
@@ -23,7 +23,7 @@ module NewRelic::Rack
23
23
  #
24
24
  class AgentHooks < AgentMiddleware
25
25
  def self.needed?
26
- !NewRelic::Agent.config[:disable_middleware_instrumentation]
26
+ NewRelic::Agent.config[:disable_middleware_instrumentation]
27
27
  end
28
28
 
29
29
  def traced_call(env)
@@ -26,22 +26,6 @@ module NewRelic
26
26
  prefix = ::NewRelic::Agent::Instrumentation::ControllerInstrumentation::TransactionNamer.prefix_for_category(nil, @category)
27
27
  "#{prefix}#{self.class.name}/call"
28
28
  end
29
-
30
- # If middleware tracing is disabled, we'll still inject our agent-specific
31
- # middlewares, and still trace those, but we don't want to capture HTTP
32
- # response codes, since middleware that's outside of ours might change the
33
- # response code before it goes back to the client.
34
- def capture_http_response_code(state, result)
35
- return if NewRelic::Agent.config[:disable_middleware_instrumentation]
36
-
37
- super
38
- end
39
-
40
- def capture_response_content_type(state, result)
41
- return if NewRelic::Agent.config[:disable_middleware_instrumentation]
42
-
43
- super
44
- end
45
29
  end
46
30
  end
47
31
  end
@@ -143,7 +143,7 @@ module NewRelic
143
143
  end
144
144
 
145
145
  # Per "The Response > The Body" section of Rack spec, we should close
146
- # if our response is able. http://rack.rubyforge.org/doc/SPEC.html
146
+ # if our response is able. https://github.com/rack/rack/blob/main/SPEC.rdoc
147
147
  def close_old_response(response)
148
148
  response.close if response.respond_to?(:close)
149
149
  end
@@ -13,6 +13,7 @@ module NewRelic
13
13
  :insert_distributed_trace_headers,
14
14
  :accept_distributed_trace_headers,
15
15
  :add_custom_attributes,
16
+ :add_custom_log_attributes,
16
17
  :add_custom_span_attributes,
17
18
  :add_instrumentation,
18
19
  :add_method_tracer,
@@ -45,6 +46,7 @@ module NewRelic
45
46
  :recording_web_transaction?,
46
47
  :require_test_helper,
47
48
  :set_error_group_callback,
49
+ :set_segment_callback,
48
50
  :set_sql_obfuscator,
49
51
  :set_transaction_name,
50
52
  :set_user_id,
@@ -22,15 +22,14 @@ module NewRelic
22
22
  # @api public
23
23
  def initialize(*args, &block)
24
24
  NewRelic::Agent.record_api_supportability_metric(:traced_thread)
25
- traced_block = create_traced_block(*args, &block)
25
+ traced_block = create_traced_block(&block)
26
26
  super(*args, &traced_block)
27
27
  end
28
28
 
29
- def create_traced_block(*args, &block)
29
+ def create_traced_block(&block)
30
30
  return block if NewRelic::Agent.config[:'instrumentation.thread.tracing'] # if this is on, don't double trace
31
31
 
32
32
  NewRelic::Agent::Tracer.thread_block_with_current_transaction(
33
- *args,
34
33
  segment_name: 'Ruby/TracedThread',
35
34
  &block
36
35
  )
@@ -6,8 +6,8 @@
6
6
  module NewRelic
7
7
  module VERSION # :nodoc:
8
8
  MAJOR = 9
9
- MINOR = 2
10
- TINY = 2
9
+ MINOR = 5
10
+ TINY = 0
11
11
 
12
12
  STRING = "#{MAJOR}.#{MINOR}.#{TINY}"
13
13
  end