newrelic_rpm 9.3.0 → 9.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.build_ignore +6 -1
  3. data/CHANGELOG.md +43 -0
  4. data/README.md +4 -0
  5. data/lib/new_relic/agent/configuration/default_source.rb +25 -2
  6. data/lib/new_relic/agent/configuration/environment_source.rb +1 -1
  7. data/lib/new_relic/agent/distributed_tracing.rb +1 -1
  8. data/lib/new_relic/agent/instrumentation/action_controller_other_subscriber.rb +1 -1
  9. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +1 -2
  10. data/lib/new_relic/agent/instrumentation/memcache.rb +2 -2
  11. data/lib/new_relic/agent/instrumentation/queue_time.rb +1 -1
  12. data/lib/new_relic/agent/instrumentation/roda/chain.rb +43 -0
  13. data/lib/new_relic/agent/instrumentation/roda/instrumentation.rb +52 -0
  14. data/lib/new_relic/agent/instrumentation/roda/prepend.rb +24 -0
  15. data/lib/new_relic/agent/instrumentation/roda/roda_transaction_namer.rb +30 -0
  16. data/lib/new_relic/agent/instrumentation/roda.rb +33 -0
  17. data/lib/new_relic/agent/instrumentation/sequel.rb +1 -1
  18. data/lib/new_relic/agent/log_event_attributes.rb +1 -1
  19. data/lib/new_relic/agent/new_relic_service.rb +33 -17
  20. data/lib/new_relic/agent/pipe_service.rb +1 -1
  21. data/lib/new_relic/agent/tracer.rb +4 -3
  22. data/lib/new_relic/agent/transaction/request_attributes.rb +45 -7
  23. data/lib/new_relic/agent/transaction.rb +5 -4
  24. data/lib/new_relic/agent/utilization/vendor.rb +5 -7
  25. data/lib/new_relic/agent.rb +1 -1
  26. data/lib/new_relic/cli/command.rb +1 -0
  27. data/lib/new_relic/control/class_methods.rb +1 -7
  28. data/lib/new_relic/control/frameworks/roda.rb +20 -0
  29. data/lib/new_relic/language_support.rb +5 -0
  30. data/lib/new_relic/noticed_error.rb +5 -2
  31. data/lib/new_relic/rack/browser_monitoring.rb +1 -1
  32. data/lib/new_relic/version.rb +1 -1
  33. data/lib/tasks/bump_version.rake +1 -1
  34. data/lib/tasks/config.rake +3 -2
  35. data/lib/tasks/helpers/config.html.erb +93 -0
  36. data/lib/tasks/helpers/format.rb +11 -7
  37. data/lib/tasks/helpers/version_bump.rb +2 -2
  38. data/lib/tasks/newrelicyml.rake +1 -1
  39. data/newrelic.yml +11 -0
  40. data/newrelic_rpm.gemspec +8 -5
  41. data/test/agent_helper.rb +1027 -0
  42. metadata +26 -8
  43. data/lib/tasks/helpers/removers.rb +0 -33
  44. data/lib/tasks/multiverse.rake +0 -6
  45. data/lib/tasks/multiverse.rb +0 -76
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4538568787069b9254f2ae6e51761daba690c0936a62bd725503df73a807c225
4
- data.tar.gz: c413c62d9b122964b48631be9a5cf240200dad7ee44a84b1d92a76f0f0bf52e3
3
+ metadata.gz: c8e0198f3fe3562d84248d3be65acdc8e7ae92e0ca27ecaa1023ca2303152464
4
+ data.tar.gz: 6d721589df2371d8d63b96eba38adddff1e534678e19b9adfdf028807233d109
5
5
  SHA512:
6
- metadata.gz: 351addff95df2919f155541fcb1b74a17d98f04c1ac1527383c969e38c50480a169e41ddaf725a31624f38517e7cdf1e2d172f10da6ca3ace290a757810df34d
7
- data.tar.gz: 9e1da523b1fc5aad52e1ceda6f5afd780fcf104bf5a06db370ba21364fa10d115371e876a994fd7c445ca5ccb5c56447b84a39ba472991afc9bee5c083a43f47
6
+ metadata.gz: 5e72bfc0219779d6912631c687d64d896b5becf69be013b35f0a88729ebc444f592d72261b2620d7fdc419b7f3fe0557af56e7e3577a6a482c1cdd4fd19aea7a
7
+ data.tar.gz: 99a8dee22642c178cf8800e1eec28544262c9b09abcfeb9f856495121de33d5fe1e33483e233d41d746d37cb2e0a2377db00a446d80653816dc252967b64b3e1
data/.build_ignore CHANGED
@@ -1,4 +1,4 @@
1
- .github
1
+ .github/
2
2
  .gitignore
3
3
  .project
4
4
  .rubocop.yml
@@ -19,3 +19,8 @@ lefthook.yml
19
19
  log/
20
20
  README.md
21
21
  test/
22
+ lib/tasks/bump_version.rb
23
+ lib/tasks/coverage_report.rb
24
+ lib/tasks/multiverse.rake
25
+ lib/tasks/multiverse.rb
26
+ lib/tasks/tests.rb
data/CHANGELOG.md CHANGED
@@ -1,5 +1,48 @@
1
1
  # New Relic Ruby Agent Release Notes
2
2
 
3
+ ## v9.4.0
4
+
5
+ Version 9.4.0 of the agent adds [Roda](https://roda.jeremyevans.net/) instrumentation, adds a new `allow_all_headers` configuration option to permit capturing all HTTP headers, introduces improved error tracking functionality by associating a transaction id with each error, and uses more reliable network timeout logic.
6
+
7
+ - **Feature: Add Roda instrumentation**
8
+
9
+ [Roda](https://roda.jeremyevans.net/) is a now an instrumented framework. The agent currently supports Roda versions 3.19.0+. [PR#2144](https://github.com/newrelic/newrelic-ruby-agent/pull/2144)
10
+
11
+ - **Feature: New allow_all_headers configuration option**
12
+
13
+ A new `allow_all_headers` configuration option brings parity with the [Node.js agent](https://docs.newrelic.com/docs/release-notes/agent-release-notes/nodejs-release-notes/node-agent-270/) to capture all HTTP request headers.
14
+
15
+ This configuration option:
16
+ * Defaults to `false`
17
+ * Is not compatible with high security mode
18
+ * Requires Rack version 2 or higher (as does Ruby on Rails version 5 and above)
19
+ * Respects all existing behavior for the `attributes.include` and `attributes.exclude` [configuration options](https://docs.newrelic.com/docs/apm/agents/ruby-agent/configuration/ruby-agent-configuration/#attributes)
20
+ * Captures the additional headers as attributes prefixed with `request.headers.`
21
+
22
+ This work was done in response to a feature request submitted by community member [@jamesarosen](https://github.com/jamesarosen). Thank you very much, @jamesarosen! [Issue#1029](https://github.com/newrelic/newrelic-ruby-agent/issues/1029)
23
+
24
+ - **Feature: Improved error tracking transaction linking**
25
+
26
+ Errors tracked and sent to the New Relic errors inbox will now be associated with a transaction id to enable improved UI/UX associations between transactions and errors. [PR#2035](https://github.com/newrelic/newrelic-ruby-agent/pull/2035)
27
+
28
+ - **Feature: Use Net::HTTP native timeout logic**
29
+
30
+ In line with current Ruby best practices, make use of Net::HTTP's own timeout logic and avoid the use of `Timeout.timeout()` when possible. The agent's data transmissions and cloud provider detection routines have been updated accordingly. [PR#2147](https://github.com/newrelic/newrelic-ruby-agent/pull/2147)
31
+
32
+ ## v9.3.1
33
+
34
+ Version 9.3.1 of the agent fixes `NewRelic::Agent.require_test_helper`.
35
+
36
+ - **Bugfix: Fix NewRelic::Agent.require_test_helper**
37
+
38
+ Version 9.3.0 of the agent made a change to the files distributed with the gem. This change unintentionally broke the `NewRelic::Agent.require_test_helper` API by removing the `test/agent_helper.rb` file. The file has been added back to the gem. This change also removes the `lib/new_relic/build.rb` file from the list because it is no longer created with our current release process.
39
+
40
+ Our thanks go to [@ajesler](https://github.com/ajesler) for reporting this issue and writing a test for the bug. [Issue#2113](https://github.com/newrelic/newrelic-ruby-agent/issues/2113), [PR#2115](https://github.com/newrelic/newrelic-ruby-agent/pull/2115), [Issue#2117](https://github.com/newrelic/newrelic-ruby-agent/issues/2117), [PR#2118](https://github.com/newrelic/newrelic-ruby-agent/pull/2118)
41
+
42
+ - **Source Documentation: update the Rack spec URL**
43
+
44
+ Community member [@olleolleolle](https://github.com/olleolleolle) noticed that our source code was referencing a now defunct URL for the Rack specification and submitted [PR#2121](https://github.com/newrelic/newrelic-ruby-agent/pull/2121) to update it. He also provided a terrific recommendation that we automate the checking of links to proactively catch defunct ones in future. Thanks, @olleolleolle!
45
+
3
46
  ## v9.3.0
4
47
 
5
48
  Version 9.3.0 of the agent adds log-level filtering, adds custom attributes for log events, and updates instrumentation for Action Cable. It also provides fixes for how `Fiber` args are treated, Code-Level Metrics, unnecessary files being included in the gem, and `NewRelic::Agent::Logging::DecoratingFormatter#clear_tags!` being incorrectly private.
data/README.md CHANGED
@@ -134,6 +134,10 @@ The New Relic Ruby agent may use source code from third-party libraries. When us
134
134
 
135
135
  ## Thank You
136
136
 
137
+ We always look forward to connecting with the community. We welcome [contributions](https://github.com/newrelic/newrelic-ruby-agent#contributing) to our source code and suggestions for improvements, and would love to hear about what you like and want to see in the future.
138
+
139
+ Visit our [project board](https://github.com/orgs/newrelic/projects/84/) to see what's upcoming in a future release, what we're currently working on, and what we're planning next.
140
+
137
141
  Thank you,
138
142
 
139
143
  New Relic Ruby agent team
@@ -24,7 +24,7 @@ module NewRelic
24
24
  # Does not appear in logs.
25
25
  def self.deprecated_description(new_setting, description)
26
26
  link_ref = new_setting.to_s.tr('.', '-')
27
- %{Please see: [#{new_setting}](docs/agents/ruby-agent/configuration/ruby-agent-configuration##{link_ref}). \n\n#{description}}
27
+ %{Please see: [#{new_setting}](##{link_ref}). \n\n#{description}}
28
28
  end
29
29
 
30
30
  class Boolean
@@ -115,6 +115,7 @@ module NewRelic
115
115
  :rails_notifications
116
116
  end
117
117
  when defined?(::Sinatra) && defined?(::Sinatra::Base) then :sinatra
118
+ when defined?(::Roda) then :roda
118
119
  when defined?(::NewRelic::IA) then :external
119
120
  else :ruby
120
121
  end
@@ -818,6 +819,13 @@ module NewRelic
818
819
  :description => 'If `true`, the agent captures metrics related to logging for your application.'
819
820
  },
820
821
  # Attributes
822
+ :'allow_all_headers' => {
823
+ :default => false,
824
+ :public => true,
825
+ :type => Boolean,
826
+ :allowed_from_server => false,
827
+ :description => 'If `true`, enables capture of all HTTP request headers for all destinations.'
828
+ },
821
829
  :'attributes.enabled' => {
822
830
  :default => true,
823
831
  :public => true,
@@ -1042,7 +1050,7 @@ module NewRelic
1042
1050
  :allowed_from_server => true,
1043
1051
  :deprecated => true,
1044
1052
  :description => deprecated_description(
1045
- :'distributed_tracing-enabled',
1053
+ :'distributed_tracing.enabled',
1046
1054
  'If `true`, enables [cross-application tracing](/docs/agents/ruby-agent/features/cross-application-tracing-ruby/) when `distributed_tracing.enabled` is set to `false`.'
1047
1055
  )
1048
1056
  },
@@ -1227,6 +1235,13 @@ module NewRelic
1227
1235
  :allowed_from_server => false,
1228
1236
  :description => 'If `true`, disables [Sidekiq instrumentation](/docs/agents/ruby-agent/background-jobs/sidekiq-instrumentation).'
1229
1237
  },
1238
+ :disable_roda_auto_middleware => {
1239
+ :default => false,
1240
+ :public => true,
1241
+ :type => Boolean,
1242
+ :allowed_from_server => false,
1243
+ :description => 'If `true`, disables agent middleware for Roda. This middleware is responsible for advanced feature support such as [page load timing](/docs/browser/new-relic-browser/getting-started/new-relic-browser) and [error collection](/docs/apm/applications-menu/events/view-apm-error-analytics).'
1244
+ },
1230
1245
  :disable_sinatra_auto_middleware => {
1231
1246
  :default => false,
1232
1247
  :public => true,
@@ -1564,6 +1579,14 @@ module NewRelic
1564
1579
  :allowed_from_server => false,
1565
1580
  :description => 'Controls auto-instrumentation of resque at start up. May be one of: `auto`, `prepend`, `chain`, `disabled`.'
1566
1581
  },
1582
+ :'instrumentation.roda' => {
1583
+ :default => 'auto',
1584
+ :public => true,
1585
+ :type => String,
1586
+ :dynamic_name => true,
1587
+ :allowed_from_server => false,
1588
+ :description => 'Controls auto-instrumentation of Roda at start up. May be one of: `auto`, `prepend`, `chain`, `disabled`.'
1589
+ },
1567
1590
  :'instrumentation.sinatra' => {
1568
1591
  :default => 'auto',
1569
1592
  :public => true,
@@ -101,7 +101,7 @@ module NewRelic
101
101
  end
102
102
  else
103
103
  ::NewRelic::Agent.logger.info("#{environment_key} does not have a corresponding configuration setting (#{config_key} does not exist).")
104
- ::NewRelic::Agent.logger.info('Run `rake newrelic:config:docs` or visit https://newrelic.com/docs/ruby/ruby-agent-configuration to see a list of available configuration settings.')
104
+ ::NewRelic::Agent.logger.info('Run `rake newrelic:config:docs` or visit https://docs.newrelic.com/docs/apm/agents/ruby-agent/configuration/ruby-agent-configuration to see a list of available configuration settings.')
105
105
  self[config_key] = value
106
106
  end
107
107
  end
@@ -87,7 +87,7 @@ module NewRelic
87
87
  # header-friendly string returned from
88
88
  # {DistributedTracePayload#http_safe}
89
89
  #
90
- # @param transport_Type [String] May be one of: +HTTP+, +HTTPS+, +Kafka+, +JMS+,
90
+ # @param transport_type [String] May be one of: +HTTP+, +HTTPS+, +Kafka+, +JMS+,
91
91
  # +IronMQ+, +AMQP+, +Queue+, +Other+. Values are
92
92
  # case sensitive. All other values result in +Unknown+
93
93
  #
@@ -23,7 +23,7 @@ module NewRelic
23
23
 
24
24
  def metric_name(name, payload)
25
25
  controller_name = controller_name_for_metric(payload)
26
- "Ruby/ActionController#{"/#{controller_name}" if controller_name}/#{name.gsub(/\.action_controller/, '')}"
26
+ "Ruby/ActionController#{"/#{controller_name}" if controller_name}/#{name.gsub('.action_controller', '')}"
27
27
  end
28
28
 
29
29
  def controller_name_for_metric(payload)
@@ -41,8 +41,6 @@ module NewRelic
41
41
  clazz.extend(ClassMethodsShim)
42
42
  end
43
43
 
44
- def new_relic_trace_controller_action(*args); yield; end
45
-
46
44
  def perform_action_with_newrelic_trace(*args); yield; end
47
45
  end
48
46
 
@@ -245,6 +243,7 @@ module NewRelic
245
243
  when :background then ::NewRelic::Agent::Transaction::TASK_PREFIX
246
244
  when :rack then ::NewRelic::Agent::Transaction::RACK_PREFIX
247
245
  when :uri then ::NewRelic::Agent::Transaction::CONTROLLER_PREFIX
246
+ when :roda then ::NewRelic::Agent::Transaction::RODA_PREFIX
248
247
  when :sinatra then ::NewRelic::Agent::Transaction::SINATRA_PREFIX
249
248
  when :middleware then ::NewRelic::Agent::Transaction::MIDDLEWARE_PREFIX
250
249
  when :grape then ::NewRelic::Agent::Transaction::GRAPE_PREFIX
@@ -5,8 +5,8 @@
5
5
  # NOTE: there are multiple implementations of the Memcached client in Ruby,
6
6
  # each with slightly different APIs and semantics.
7
7
  # See:
8
- # http://www.deveiate.org/code/Ruby-MemCache/ (Gem: Ruby-MemCache)
9
- # http://seattlerb.rubyforge.org/memcache-client/ (Gem: memcache-client)
8
+ # https://rubygems.org/gems/Ruby-MemCache (Gem: Ruby-MemCache)
9
+ # https://github.com/mperham/memcache-client (Gem: memcache-client)
10
10
  # https://github.com/mperham/dalli (Gem: dalli)
11
11
 
12
12
  require_relative 'memcache/helper'
@@ -5,7 +5,7 @@
5
5
  module NewRelic
6
6
  module Agent
7
7
  module Instrumentation
8
- # https://newrelic.com/docs/features/tracking-front-end-time
8
+ # https://docs.newrelic.com/docs/features/tracking-front-end-time
9
9
  # Record queue time metrics based on any of three headers
10
10
  # which can be set on the request.
11
11
  module QueueTime
@@ -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,52 @@
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
+ def self.included(clazz)
11
+ clazz.extend(self)
12
+ end
13
+
14
+ def newrelic_middlewares
15
+ middlewares = [NewRelic::Rack::BrowserMonitoring]
16
+ if NewRelic::Rack::AgentHooks.needed?
17
+ middlewares << NewRelic::Rack::AgentHooks
18
+ end
19
+ middlewares
20
+ end
21
+
22
+ def build_rack_app_with_tracing
23
+ unless NewRelic::Agent.config[:disable_roda_auto_middleware]
24
+ newrelic_middlewares.each do |middleware_class|
25
+ self.use middleware_class
26
+ end
27
+ end
28
+ yield
29
+ end
30
+
31
+ # Roda makes use of Rack, so we can get params from the request object
32
+ def rack_request_params
33
+ begin
34
+ @_request.params
35
+ rescue => e
36
+ NewRelic::Agent.logger.debug('Failed to get params from Rack request.', e)
37
+ NewRelic::EMPTY_HASH
38
+ end
39
+ end
40
+
41
+ def _roda_handle_main_route_with_tracing(*args)
42
+ perform_action_with_newrelic_trace(
43
+ category: :roda,
44
+ name: TransactionNamer.transaction_name(request),
45
+ params: ::NewRelic::Agent::ParameterFiltering::apply_filters(request.env, rack_request_params)
46
+ ) do
47
+ yield
48
+ end
49
+ end
50
+ end
51
+ end
52
+ 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,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
+ module NewRelic
6
+ module Agent
7
+ module Instrumentation
8
+ module Roda
9
+ module TransactionNamer
10
+ extend self
11
+
12
+ ROOT = '/'.freeze
13
+ REGEX_MULTIPLE_SLASHES = %r{^[/^\A]*(.*?)[/$?\z]*$}.freeze
14
+
15
+ def transaction_name(request)
16
+ path = request.path || ::NewRelic::Agent::UNKNOWN_METRIC
17
+ name = path.gsub(REGEX_MULTIPLE_SLASHES, '\1') # remove any rogue slashes
18
+ name = ROOT if name.empty?
19
+ name = "#{request.request_method} #{name}" if request.respond_to?(:request_method)
20
+
21
+ name
22
+ rescue => e
23
+ ::NewRelic::Agent.logger.debug("#{e.class} : #{e.message} - Error encountered trying to identify Roda transaction name")
24
+ ::NewRelic::Agent::UNKNOWN_METRIC
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,33 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ require_relative 'roda/instrumentation'
6
+
7
+ DependencyDetection.defer do
8
+ named :roda
9
+
10
+ depends_on do
11
+ defined?(Roda) &&
12
+ Gem::Version.new(Roda::RodaVersion) >= Gem::Version.new('3.19.0') &&
13
+ Roda::RodaPlugins::Base::ClassMethods.private_method_defined?(:build_rack_app) &&
14
+ Roda::RodaPlugins::Base::InstanceMethods.method_defined?(:_roda_handle_main_route)
15
+ end
16
+
17
+ executes do
18
+ require_relative '../../rack/agent_hooks'
19
+ require_relative '../../rack/browser_monitoring'
20
+
21
+ NewRelic::Agent.logger.info('Installing Roda instrumentation')
22
+
23
+ if use_prepend?
24
+ require_relative 'roda/prepend'
25
+ prepend_instrument Roda.singleton_class, NewRelic::Agent::Instrumentation::Roda::Build::Prepend
26
+ prepend_instrument Roda, NewRelic::Agent::Instrumentation::Roda::Prepend
27
+ else
28
+ require_relative 'roda/chain'
29
+ chain_instrument NewRelic::Agent::Instrumentation::Roda::Build::Chain
30
+ chain_instrument NewRelic::Agent::Instrumentation::Roda::Chain
31
+ end
32
+ end
33
+ 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|
@@ -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)
@@ -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
 
@@ -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