newrelic_rpm 9.16.1 → 9.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -1
  3. data/CONTRIBUTING.md +2 -2
  4. data/lib/boot/strap.rb +4 -3
  5. data/lib/new_relic/agent/agent.rb +4 -0
  6. data/lib/new_relic/agent/agent_helpers/connect.rb +3 -0
  7. data/lib/new_relic/agent/agent_helpers/harvest.rb +3 -0
  8. data/lib/new_relic/agent/agent_helpers/shutdown.rb +3 -0
  9. data/lib/new_relic/agent/agent_helpers/start_worker_thread.rb +1 -0
  10. data/lib/new_relic/agent/agent_helpers/startup.rb +7 -0
  11. data/lib/new_relic/agent/configuration/default_source.rb +45 -4
  12. data/lib/new_relic/agent/configuration/yaml_source.rb +6 -1
  13. data/lib/new_relic/agent/database.rb +2 -1
  14. data/lib/new_relic/agent/distributed_tracing.rb +2 -2
  15. data/lib/new_relic/agent/health_check.rb +136 -0
  16. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +2 -1
  17. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +8 -4
  18. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/chain.rb +21 -0
  19. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/instrumentation.rb +66 -0
  20. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/prepend.rb +15 -0
  21. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose.rb +22 -0
  22. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/chain.rb +21 -0
  23. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/instrumentation.rb +91 -0
  24. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/prepend.rb +15 -0
  25. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis.rb +22 -0
  26. data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +0 -3
  27. data/lib/new_relic/agent/instrumentation/resque.rb +7 -1
  28. data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delayed_class.rb +1 -1
  29. data/lib/new_relic/agent/local_log_decorator.rb +12 -2
  30. data/lib/new_relic/agent/new_relic_service.rb +8 -2
  31. data/lib/new_relic/agent/threading/backtrace_node.rb +10 -1
  32. data/lib/new_relic/agent/transaction/message_broker_segment.rb +3 -0
  33. data/lib/new_relic/dependency_detection.rb +1 -8
  34. data/lib/new_relic/version.rb +2 -2
  35. data/newrelic.yml +12 -4
  36. data/test/agent_helper.rb +7 -0
  37. metadata +12 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4188543c2c5d39ce13735a832e955f9ec211bdce6e83b29a37414cd78d23ff84
4
- data.tar.gz: 84431c682fb000ddcd0b520c39b3a8b358535fb580af32d41520d26471b02944
3
+ metadata.gz: c16c3149d187e88f60c408712fa5da2209c4cac08769477b951df4dfb780e95b
4
+ data.tar.gz: d6a0c36115e0b2f9db2ceeb806435737865615dc9043b669376bab20f443dce9
5
5
  SHA512:
6
- metadata.gz: 6994d2922b5a327883c2143b3deb22e01eafb8b0e78bca60a71c6a8726ed29e48b391fdb2e2e60ee86681ffe88c8782c5cd4975ab169247fd9b61527e0090149
7
- data.tar.gz: c10cf492bd247b12fe47203e8fb5a8d17e067a7d2807e39ec144dda958101e0d334fcd29234d3657cf2d6d73bd3f67f9cb89847252d08be178caadc236e46d70
6
+ metadata.gz: fc16046f04498bc268cfe08839f9a98580fede0d249c87bd9000d00a8560b0a99ffb2d504f018bc4a752a2008e1339a106a8dc38e46687ed2ddbf76aef839abf
7
+ data.tar.gz: 1b704cc45064a6ccbea20474f1537379b113bdf38788d2a0f7b283e885e0d9cc54c3ea5f935a8d41a81017a416f14adec7a814351c89dbf89d6072c044fb31ff
data/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # New Relic Ruby Agent Release Notes
2
2
 
3
+ ## v9.17.0
4
+
5
+ - **Feature: Support Ruby 3.4.0**
6
+
7
+ The agent now supports Ruby 3.4.0. We've made incremental changes throughout the preview stage to reach compatibility. This release includes an update to the Thread Profiler for compatibility with Ruby 3.4.0's new backtrace format. [Issue#2992](https://github.com/newrelic/newrelic-ruby-agent/issues/2992) [PR#2997](https://github.com/newrelic/newrelic-ruby-agent/pull/2997)
8
+
9
+ - **Feature: Add instrumentation for aws-sdk-firehose**
10
+
11
+ The agent now has instrumentation for the [aws-sdk-firehose](https://rubygems.org/gems/aws-sdk-firehose) gem. [PR#2973](https://github.com/newrelic/newrelic-ruby-agent/pull/2973)
12
+
13
+ - **Feature: Kubernetes APM auto-attach - new agent version precedent**
14
+
15
+ Previously, when a customer installed the Ruby agent via [Kubernetes APM auto-attach](https://docs.newrelic.com/docs/kubernetes-pixie/kubernetes-integration/installation/k8s-agent-operator/) and also had the Ruby agent listed in their `Gemfile`, the agent version in `Gemfile` would take precedence. Now, the agent version installed by auto-attach takes priority. [PR#3018](https://github.com/newrelic/newrelic-ruby-agent/pull/3018)
16
+
17
+ - **Feature: Add health checks when the agent runs within Agent Control**
18
+
19
+ When the agent is started within an [Agent Control](https://docs-preview.newrelic.com/docs/new-relic-agent-control) environment, a health check file will be created at the configured file location for every agent process. By default, this location is: '/newrelic/apm/health'. The health check files will be updated at the configured frequency, which defaults to every five seconds. [PR#2995](https://github.com/newrelic/newrelic-ruby-agent/pull/2995)
20
+
21
+ - **Feature: Add Redshift as recognized ActiveRecord adapter**
22
+
23
+ When the agent does not recognize an ActiveRecord adapter, the host, port, and database name information is not added to the datastore span. Redshift will now be treated like PostgreSQL, and the agent will save the host, port, and database name on the span. [PR#3032](https://github.com/newrelic/newrelic-ruby-agent/pull/3032)
24
+
25
+ - **Feature: Add instrumentation for aws-sdk-kinesis**
26
+
27
+ The agent now has instrumentation for the [aws-sdk-kinesis](https://rubygems.org/gems/aws-sdk-kinesis) gem. It will record message broker segments for `get_records`, `put_record`, and `put_records` operations. All other operations will record standard segments. [PR#2974](https://github.com/newrelic/newrelic-ruby-agent/pull/2974)
28
+
29
+ - **Bugfix: Stop emitting inaccurate debug-level log about deprecated configuration options**
30
+
31
+ In the previous major release, we dropped support for `disable_<library_name>` configuration options in favor of `instrumentation.<library_name>`. Previously, a DEBUG level log warning appeared whenever `disable_*` options were set to `true`, even for libraries (e.g. Action Dispatch) without equivalent `instrumentation.*` options:
32
+
33
+ >DEBUG : [DEPRECATED] configuration disable_<library_name> for <library_name> will be removed in the next major release. Use instrumentation.<library_name> with one of ["auto", "disabled", "prepend", "chain"]
34
+
35
+ This inaccurate warning has been removed. If you are disabling instrumentation using `instrumentation.<library_name>: disabled` or `NEW_RELIC_INSTRUMENTATION_<LIBRARY_NAME>=disabled`, please verify the option exists by consulting our [configuration documentation](https://docs.newrelic.com/docs/apm/agents/ruby-agent/configuration/ruby-agent-configuration/#instrumentation). If the option does not exist, check the ['Disabling' section](https://docs.newrelic.com/docs/apm/agents/ruby-agent/configuration/ruby-agent-configuration/#disabling) to see if there is a related option. We apologize for the confusion. [PR#3005](https://github.com/newrelic/newrelic-ruby-agent/pull/3005)
36
+
37
+ - **Bugfix: Do not attempt to decorate logs with `nil` messages**
38
+
39
+ The agent no longer attempts to add New Relic linking metadata to logs with `nil` messages. Thank you, [@arlando](https://github.com/arlando) for bringing this to our attention! [Issue#2985](https://github.com/newrelic/newrelic-ruby-agent/issues/2985) [PR#2986](https://github.com/newrelic/newrelic-ruby-agent/pull/2986)
40
+
41
+ - **Bugfix: Stop renaming final Grape segment**
42
+
43
+ Previously, the agent renamed the final segment in Grape transactions to `"Middleware/Grape/#{class_name}/call"`. This was a part of an old instrumentation pattern that is no longer relevant. Many thanks to [@seriousdev-gh](https://github.com/seriousdev-gh) for bringing this issue to our attention and along with a great reproduction and suggested fix. [PR#2987](https://github.com/newrelic/newrelic-ruby-agent/pull/2987).
44
+
3
45
  ## v9.16.1
4
46
 
5
47
  - **Bugfix: Add support for Trilogy database adapter**
@@ -604,7 +646,7 @@ Version 9.3.0 of the agent adds log-level filtering, adds custom attributes for
604
646
  | --------------------------- | ------- | ------------------------------------------------------ | ------ |
605
647
  | `application_logging.forwarding.log_level` | `debug` | Sets the minimum log level for events forwarded to New Relic | `debug`, `info`, `warn`, `error`, `fatal`, `unknown` |
606
648
 
607
- This setting uses [Ruby's Logger::Severity constants integer values](https://github.com/ruby/ruby/blob/master/lib/logger/severity.rb#L6-L17) to determine precedence.
649
+ This setting uses [Ruby's Logger::Severity constants integer values](https://github.com/ruby/logger/blob/113b82a06b3076b93a71cd467e1605b23afb3088/lib/logger/severity.rb#L6-L17) to determine precedence.
608
650
 
609
651
  - **Feature: Custom attributes for logs**
610
652
 
data/CONTRIBUTING.md CHANGED
@@ -184,9 +184,9 @@ New Relic hosts and moderates an online forum where customers can interact with
184
184
  New Relic employees as well as other customers to get help and share best
185
185
  practices. Like all official New Relic open source projects, there's a related
186
186
  Community topic in the New Relic Explorers Hub. You can find this project's
187
- topic/threads here:
187
+ topic/threads under the "Ruby Agent" category here:
188
188
 
189
- [Explorer's Hub](https://discuss.newrelic.com/tags/rubyagent)
189
+ [Explorer's Hub](https://forum.newrelic.com/s/category/Category__c/Default)
190
190
 
191
191
  ## And Finally...
192
192
 
data/lib/boot/strap.rb CHANGED
@@ -44,14 +44,15 @@ module NRBundlerPatch
44
44
  NR_AGENT_GEM = 'newrelic_rpm'
45
45
 
46
46
  def require(*_groups)
47
- super
48
-
49
47
  require_newrelic
48
+
49
+ super
50
50
  end
51
51
 
52
52
  def require_newrelic
53
53
  lib = File.expand_path('../..', __FILE__)
54
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
54
+ $LOAD_PATH.reject! { |path| path.include?('newrelic_rpm') }
55
+ $LOAD_PATH.unshift(lib)
55
56
  Kernel.require NR_AGENT_GEM
56
57
  end
57
58
  end
@@ -13,6 +13,7 @@ require 'new_relic/traced_thread'
13
13
  require 'new_relic/coerce'
14
14
  require 'new_relic/agent/autostart'
15
15
  require 'new_relic/agent/harvester'
16
+ require 'new_relic/agent/health_check'
16
17
  require 'new_relic/agent/hostname'
17
18
  require 'new_relic/agent/new_relic_service'
18
19
  require 'new_relic/agent/pipe_service'
@@ -88,6 +89,7 @@ module NewRelic
88
89
  end
89
90
 
90
91
  def init_components
92
+ @health_check = HealthCheck.new
91
93
  @service = NewRelicService.new
92
94
  @events = EventListener.new
93
95
  @stats_engine = StatsEngine.new
@@ -139,6 +141,8 @@ module NewRelic
139
141
  # Holds all the methods defined on NewRelic::Agent::Agent
140
142
  # instances
141
143
  module InstanceMethods
144
+ # the agent control health check file generator
145
+ attr_reader :health_check
142
146
  # the statistics engine that holds all the timeslice data
143
147
  attr_reader :stats_engine
144
148
  # the transaction sampler that handles recording transactions
@@ -68,6 +68,7 @@ module NewRelic
68
68
  def handle_license_error(error)
69
69
  ::NewRelic::Agent.logger.error(error.message,
70
70
  'Visit newrelic.com to obtain a valid license key, or to upgrade your account.')
71
+ NewRelic::Agent.agent.health_check.update_status(NewRelic::Agent::HealthCheck::INVALID_LICENSE_KEY)
71
72
  disconnect
72
73
  end
73
74
 
@@ -191,6 +192,7 @@ module NewRelic
191
192
  @connected_pid = $$
192
193
  @connect_state = :connected
193
194
  signal_connected
195
+ NewRelic::Agent.agent.health_check.update_status(NewRelic::Agent::HealthCheck::HEALTHY)
194
196
  rescue NewRelic::Agent::ForceDisconnectException => e
195
197
  handle_force_disconnect(e)
196
198
  rescue NewRelic::Agent::LicenseException => e
@@ -198,6 +200,7 @@ module NewRelic
198
200
  rescue NewRelic::Agent::UnrecoverableAgentException => e
199
201
  handle_unrecoverable_agent_error(e)
200
202
  rescue StandardError, Timeout::Error, NewRelic::Agent::ServerConnectionException => e
203
+ NewRelic::Agent.agent.health_check.update_status(NewRelic::Agent::HealthCheck::FAILED_TO_CONNECT)
201
204
  retry if retry_from_error?(e, opts)
202
205
  rescue Exception => e
203
206
  ::NewRelic::Agent.logger.error('Exception of unexpected type during Agent#connect():', e)
@@ -119,6 +119,7 @@ module NewRelic
119
119
  rescue UnrecoverableServerException => e
120
120
  NewRelic::Agent.logger.warn("#{endpoint} data was rejected by remote service, discarding. Error: ", e)
121
121
  rescue ServerConnectionException => e
122
+ NewRelic::Agent.agent.health_check.update_status(NewRelic::Agent::HealthCheck::FAILED_TO_CONNECT)
122
123
  log_remote_unavailable(endpoint, e)
123
124
  container.merge!(payload)
124
125
  rescue => e
@@ -133,9 +134,11 @@ module NewRelic
133
134
  rescue ForceRestartException, ForceDisconnectException
134
135
  raise
135
136
  rescue UnrecoverableServerException => e
137
+ NewRelic::Agent.agent.health_check.update_status(NewRelic::Agent::HealthCheck::FAILED_TO_CONNECT)
136
138
  NewRelic::Agent.logger.warn('get_agent_commands message was rejected by remote service, discarding. ' \
137
139
  'Error: ', e)
138
140
  rescue ServerConnectionException => e
141
+ NewRelic::Agent.health_check.update_status(NewRelic::Agent::HealthCheck::FAILED_TO_CONNECT)
139
142
  log_remote_unavailable(:get_agent_commands, e)
140
143
  rescue => e
141
144
  NewRelic::Agent.logger.info('Error during check_for_and_handle_agent_commands, will retry later: ', e)
@@ -19,6 +19,9 @@ module NewRelic
19
19
  revert_to_default_configuration
20
20
 
21
21
  @started = nil
22
+
23
+ NewRelic::Agent.agent.health_check.update_status(NewRelic::Agent::HealthCheck::SHUTDOWN) if NewRelic::Agent.agent.health_check.healthy?
24
+
22
25
  Control.reset
23
26
  end
24
27
 
@@ -86,6 +86,7 @@ module NewRelic
86
86
  # is the worker thread that gathers data and talks to the
87
87
  # server.
88
88
  def handle_force_disconnect(error)
89
+ NewRelic::Agent.agent.health_check.update_status(NewRelic::Agent::HealthCheck::FORCED_DISCONNECT)
89
90
  ::NewRelic::Agent.logger.warn('Agent received a ForceDisconnectException from the server, disconnecting. ' \
90
91
  "(#{error.message})")
91
92
  disconnect
@@ -36,6 +36,9 @@ module NewRelic
36
36
  # setting up the worker thread and the exit handler to shut
37
37
  # down the agent
38
38
  def check_config_and_start_agent
39
+ # some health statuses, such as invalid license key, are ran before
40
+ # the agent officially starts
41
+ @health_check.create_and_run_health_check_loop
39
42
  return unless monitoring? && has_correct_license_key?
40
43
  return if using_forking_dispatcher?
41
44
 
@@ -129,6 +132,7 @@ module NewRelic
129
132
  if Agent.config[:monitor_mode]
130
133
  true
131
134
  else
135
+ NewRelic::Agent.agent.health_check.update_status(NewRelic::Agent::HealthCheck::AGENT_DISABLED)
132
136
  ::NewRelic::Agent.logger.warn('Agent configured not to send data in this environment.')
133
137
  false
134
138
  end
@@ -140,6 +144,7 @@ module NewRelic
140
144
  if Agent.config[:license_key] && Agent.config[:license_key].length > 0
141
145
  true
142
146
  else
147
+ NewRelic::Agent.agent.health_check.update_status(NewRelic::Agent::HealthCheck::MISSING_LICENSE_KEY)
143
148
  ::NewRelic::Agent.logger.warn('No license key found. ' +
144
149
  'This often means your newrelic.yml file was not found, or it lacks a section for the running ' \
145
150
  "environment, '#{NewRelic::Control.instance.env}'. You may also want to try linting your newrelic.yml " \
@@ -160,6 +165,7 @@ module NewRelic
160
165
  if key.length == 40
161
166
  true
162
167
  else
168
+ NewRelic::Agent.agent.health_check.update_status(NewRelic::Agent::HealthCheck::INVALID_LICENSE_KEY)
163
169
  ::NewRelic::Agent.logger.error("Invalid license key: #{key}")
164
170
  false
165
171
  end
@@ -180,6 +186,7 @@ module NewRelic
180
186
  end
181
187
 
182
188
  unless app_name_configured?
189
+ NewRelic::Agent.agent.health_check.update_status(NewRelic::Agent::HealthCheck::MISSING_APP_NAME)
183
190
  NewRelic::Agent.logger.error('No application name configured.',
184
191
  'The agent cannot start without at least one. Please check your ',
185
192
  'newrelic.yml and ensure that it is valid and has at least one ',
@@ -139,7 +139,7 @@ module NewRelic
139
139
  case Rails::VERSION::MAJOR
140
140
  when 3
141
141
  :rails3
142
- when 4..7
142
+ when 4..8
143
143
  :rails_notifications
144
144
  else
145
145
  ::NewRelic::Agent.logger.warn("Detected untested Rails version #{Rails::VERSION::STRING}")
@@ -858,7 +858,7 @@ module NewRelic
858
858
  :description => <<~DESCRIPTION
859
859
  Sets the minimum level a log event must have to be forwarded to New Relic.
860
860
 
861
- This is based on the integer values of Ruby's `Logger::Severity` constants: https://github.com/ruby/ruby/blob/master/lib/logger/severity.rb
861
+ This is based on the integer values of [Ruby's `Logger::Severity` constants](https://github.com/ruby/logger/blob/113b82a06b3076b93a71cd467e1605b23afb3088/lib/logger/severity.rb).
862
862
 
863
863
  The intention is to forward logs with the level given to the configuration, as well as any logs with a higher level of severity.
864
864
 
@@ -1310,6 +1310,7 @@ module NewRelic
1310
1310
  :default => false,
1311
1311
  :public => true,
1312
1312
  :type => Boolean,
1313
+ :aliases => %i[disable_active_job],
1313
1314
  :allowed_from_server => false,
1314
1315
  :description => 'If `true`, disables Active Job instrumentation.'
1315
1316
  },
@@ -1552,6 +1553,15 @@ module NewRelic
1552
1553
  :allowed_from_server => false,
1553
1554
  :description => 'Controls auto-instrumentation of bunny at start-up. May be one of: `auto`, `prepend`, `chain`, `disabled`.'
1554
1555
  },
1556
+ :'instrumentation.aws_sdk_firehose' => {
1557
+ :default => 'auto',
1558
+ :documentation_default => 'auto',
1559
+ :public => true,
1560
+ :type => String,
1561
+ :dynamic_name => true,
1562
+ :allowed_from_server => false,
1563
+ :description => 'Controls auto-instrumentation of the aws-sdk-firehose library at start-up. May be one of `auto`, `prepend`, `chain`, `disabled`.'
1564
+ },
1555
1565
  :'instrumentation.aws_sdk_lambda' => {
1556
1566
  :default => 'auto',
1557
1567
  :documentation_default => 'auto',
@@ -1561,6 +1571,15 @@ module NewRelic
1561
1571
  :allowed_from_server => false,
1562
1572
  :description => 'Controls auto-instrumentation of the aws_sdk_lambda library at start-up. May be one of `auto`, `prepend`, `chain`, `disabled`.'
1563
1573
  },
1574
+ :'instrumentation.aws_sdk_kinesis' => {
1575
+ :default => 'auto',
1576
+ :documentation_default => 'auto',
1577
+ :public => true,
1578
+ :type => String,
1579
+ :dynamic_name => true,
1580
+ :allowed_from_server => false,
1581
+ :description => 'Controls auto-instrumentation of the aws-sdk-kinesis library at start-up. May be one of `auto`, `prepend`, `chain`, `disabled`.'
1582
+ },
1564
1583
  :'instrumentation.ruby_kafka' => {
1565
1584
  :default => 'auto',
1566
1585
  :public => true,
@@ -2177,7 +2196,7 @@ module NewRelic
2177
2196
  :public => true,
2178
2197
  :type => Boolean,
2179
2198
  :allowed_from_server => false,
2180
- :description => 'If true, the agent strips messages from all exceptions except those in the [allowlist](#strip_exception_messages-allowlist). Enabled automatically in [high security mode](/docs/accounts-partnerships/accounts/security/high-security).'
2199
+ :description => 'If true, the agent strips messages from all exceptions except those in the [allowed classes list](#strip_exception_messages-allowed_classes). Enabled automatically in [high security mode](/docs/accounts-partnerships/accounts/security/high-security).'
2181
2200
  },
2182
2201
  :'strip_exception_messages.allowed_classes' => {
2183
2202
  :default => '',
@@ -2187,6 +2206,28 @@ module NewRelic
2187
2206
  :transform => DefaultSource.method(:convert_to_constant_list),
2188
2207
  :description => 'Specify a list of exceptions you do not want the agent to strip when [strip_exception_messages](#strip_exception_messages-enabled) is `true`. Separate exceptions with a comma. For example, `"ImportantException,PreserveMessageException"`.'
2189
2208
  },
2209
+ # Agent Control
2210
+ :'agent_control.enabled' => {
2211
+ :default => false,
2212
+ :public => false,
2213
+ :type => Boolean,
2214
+ :allowed_from_server => false,
2215
+ :description => 'Boolean value that denotes whether Agent Control functionality should be enabled. At the moment, this functionality is limited to whether agent health should be reported. This configuration will be set using an environment variable by Agent Control, or one of its components, prior to agent startup.'
2216
+ },
2217
+ :'agent_control.health.delivery_location' => {
2218
+ :default => '/newrelic/apm/health',
2219
+ :public => false,
2220
+ :type => String,
2221
+ :allowed_from_server => false,
2222
+ :description => 'A `file:` URI that specifies the fully qualified directory path for health file(s) to be written to. This defaults to: `file:///newrelic/apm/health`. This configuration will be set using an environment variable by Agent Control, or one of its components, prior to agent startup.'
2223
+ },
2224
+ :'agent_control.health.frequency' => {
2225
+ :default => 5,
2226
+ :public => false,
2227
+ :type => Integer,
2228
+ :allowed_from_server => false,
2229
+ :description => 'The interval, in seconds, of how often the health file(s) will be written to. This configuration will be set using an environment variable by Agent Control, or one of its components, prior to agent startup.'
2230
+ },
2190
2231
  # Thread profiler
2191
2232
  :'thread_profiler.enabled' => {
2192
2233
  :default => DefaultSource.thread_profiler_enabled,
@@ -2689,7 +2730,7 @@ module NewRelic
2689
2730
  :public => true,
2690
2731
  :type => Boolean,
2691
2732
  :allowed_from_server => false,
2692
- :description => "If `true`, the security agent loads (the agent performs a Ruby 'require')"
2733
+ :description => "If `true`, the security agent is loaded (a Ruby 'require' is performed)"
2693
2734
  },
2694
2735
  :'security.enabled' => {
2695
2736
  :default => false,
@@ -36,6 +36,7 @@ module NewRelic
36
36
  erb_file = process_erb(raw_file)
37
37
  config = process_yaml(erb_file, env, config, @file_path)
38
38
  rescue ScriptError, StandardError => e
39
+ NewRelic::Agent.agent.health_check.update_status(NewRelic::Agent::HealthCheck::FAILED_TO_PARSE_CONFIG)
39
40
  log_failure("Failed to read or parse configuration file at #{path}", e)
40
41
  end
41
42
 
@@ -99,7 +100,11 @@ module NewRelic
99
100
  file.gsub!(/^\s*#.*$/, '#')
100
101
  ERB.new(file).result(binding)
101
102
  rescue ScriptError, StandardError => e
102
- log_failure('Failed ERB processing configuration file. This is typically caused by a Ruby error in <% %> templating blocks in your newrelic.yml file.', e)
103
+ NewRelic::Agent.agent.health_check.update_status(NewRelic::Agent::HealthCheck::FAILED_TO_PARSE_CONFIG)
104
+ message = 'Failed ERB processing configuration file. This is typically caused by a Ruby error in <% %> templating blocks in your newrelic.yml file.'
105
+ failure_array = [message, e]
106
+ failure_array << e.backtrace[0] if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.4.0')
107
+ log_failure(*failure_array)
103
108
  nil
104
109
  end
105
110
  end
@@ -278,9 +278,10 @@ module NewRelic
278
278
  MYSQL2_PREFIX = 'mysql2'.freeze
279
279
  SQLITE_PREFIX = 'sqlite'.freeze
280
280
  TRILOGY_PREFIX = 'trilogy'.freeze
281
+ REDSHIFT_PREFIX = 'redshift'.freeze
281
282
 
282
283
  def symbolized_adapter(adapter)
283
- if adapter.start_with?(POSTGRES_PREFIX) || adapter == POSTGIS_PREFIX
284
+ if adapter.start_with?(POSTGRES_PREFIX) || adapter == POSTGIS_PREFIX || adapter == REDSHIFT_PREFIX
284
285
  :postgres
285
286
  elsif adapter == MYSQL_PREFIX
286
287
  :mysql
@@ -45,7 +45,7 @@ module NewRelic
45
45
  record_api_supportability_metric(:insert_distributed_trace_headers)
46
46
 
47
47
  unless Agent.config[:'distributed_tracing.enabled']
48
- NewRelic::Agent.logger.warn('Not configured to insert distributed trace headers')
48
+ NewRelic::Agent.logger.debug('Not configured to insert distributed trace headers')
49
49
  return nil
50
50
  end
51
51
 
@@ -99,7 +99,7 @@ module NewRelic
99
99
  record_api_supportability_metric(:accept_distributed_trace_headers)
100
100
 
101
101
  unless Agent.config[:'distributed_tracing.enabled']
102
- NewRelic::Agent.logger.warn('Not configured to accept distributed trace headers')
102
+ NewRelic::Agent.logger.debug('Not configured to accept distributed trace headers')
103
103
  return nil
104
104
  end
105
105
 
@@ -0,0 +1,136 @@
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
+ class HealthCheck
8
+ def initialize
9
+ @start_time = nano_time
10
+ @continue = true
11
+ @status = HEALTHY
12
+ # the following assignments may set @continue = false if they are invalid
13
+ set_enabled
14
+ set_delivery_location
15
+ set_frequency
16
+ end
17
+
18
+ HEALTHY = {healthy: true, last_error: 'NR-APM-000', message: 'Healthy'}.freeze
19
+ INVALID_LICENSE_KEY = {healthy: false, last_error: 'NR-APM-001', message: 'Invalid license key (HTTP status code 401)'}.freeze
20
+ MISSING_LICENSE_KEY = {healthy: false, last_error: 'NR-APM-002', message: 'License key missing in configuration'}.freeze
21
+ FORCED_DISCONNECT = {healthy: false, last_error: 'NR-APM-003', message: 'Forced disconnect received from New Relic (HTTP status code 410)'}.freeze
22
+ HTTP_ERROR = {healthy: false, last_error: 'NR-APM-004', message: 'HTTP error response code [%s] recevied from New Relic while sending data type [%s]'}.freeze
23
+ MISSING_APP_NAME = {healthy: false, last_error: 'NR-APM-005', message: 'Missing application name in agent configuration'}.freeze
24
+ APP_NAME_EXCEEDED = {healthy: false, last_error: 'NR-APM-006', message: 'The maximum number of configured app names (3) exceeded'}.freeze
25
+ PROXY_CONFIG_ERROR = {healthy: false, last_error: 'NR-APM-007', message: 'HTTP Proxy configuration error; response code [%s]'}.freeze
26
+ AGENT_DISABLED = {healthy: false, last_error: 'NR-APM-008', message: 'Agent is disabled via configuration'}.freeze
27
+ FAILED_TO_CONNECT = {healthy: false, last_error: 'NR-APM-009', message: 'Failed to connect to New Relic data collector'}.freeze
28
+ FAILED_TO_PARSE_CONFIG = {healthy: false, last_error: 'NR-APM-010', message: 'Agent config file is not able to be parsed'}.freeze
29
+ SHUTDOWN = {healthy: true, last_error: 'NR-APM-099', message: 'Agent has shutdown'}.freeze
30
+
31
+ def create_and_run_health_check_loop
32
+ return unless health_checks_enabled? && @continue
33
+
34
+ NewRelic::Agent.logger.debug('Agent Control health check conditions met. Starting health checks.')
35
+ NewRelic::Agent.record_metric('Supportability/AgentControl/Health/enabled', 1)
36
+
37
+ Thread.new do
38
+ while @continue
39
+ begin
40
+ sleep @frequency
41
+ write_file
42
+ @continue = false if @status == SHUTDOWN
43
+ rescue StandardError => e
44
+ NewRelic::Agent.logger.error("Aborting Agent Control health check. Error raised: #{e}")
45
+ @continue = false
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ def update_status(status, options = [])
52
+ return unless @continue
53
+
54
+ @status = status.dup
55
+ update_message(options) unless options.empty?
56
+ end
57
+
58
+ def healthy?
59
+ @status == HEALTHY
60
+ end
61
+
62
+ private
63
+
64
+ def set_enabled
65
+ @enabled = if ENV['NEW_RELIC_AGENT_CONTROL_ENABLED'] == 'true'
66
+ true
67
+ else
68
+ NewRelic::Agent.logger.debug('NEW_RELIC_AGENT_CONTROL_ENABLED not true, disabling health checks')
69
+ @continue = false
70
+ false
71
+ end
72
+ end
73
+
74
+ def set_delivery_location
75
+ @delivery_location = if ENV['NEW_RELIC_AGENT_CONTROL_HEALTH_DELIVERY_LOCATION']
76
+ # The spec states file paths for the delivery location will begin with file://
77
+ # This does not create a valid path in Ruby, so remove the prefix when present
78
+ ENV['NEW_RELIC_AGENT_CONTROL_HEALTH_DELIVERY_LOCATION']&.gsub('file://', '')
79
+ else
80
+ # The spec default is 'file:///newrelic/apm/health', but since we're just going to remove it anyway...
81
+ '/newrelic/apm/health'
82
+ end
83
+ end
84
+
85
+ def set_frequency
86
+ @frequency = ENV['NEW_RELIC_AGENT_CONTROL_HEALTH_FREQUENCY'] ? ENV['NEW_RELIC_AGENT_CONTROL_HEALTH_FREQUENCY'].to_i : 5
87
+
88
+ if @frequency <= 0
89
+ NewRelic::Agent.logger.debug('NEW_RELIC_AGENT_CONTROL_HEALTH_FREQUENCY zero or less, disabling health checks')
90
+ @continue = false
91
+ end
92
+ end
93
+
94
+ def contents
95
+ <<~CONTENTS
96
+ healthy: #{@status[:healthy]}
97
+ status: #{@status[:message]}#{last_error}
98
+ start_time_unix_nano: #{@start_time}
99
+ status_time_unix_nano: #{nano_time}
100
+ CONTENTS
101
+ end
102
+
103
+ def last_error
104
+ @status[:healthy] ? '' : "\nlast_error: #{@status[:last_error]}"
105
+ end
106
+
107
+ def nano_time
108
+ Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
109
+ end
110
+
111
+ def file_name
112
+ "health-#{NewRelic::Agent::GuidGenerator.generate_guid(32)}.yml"
113
+ end
114
+
115
+ def write_file
116
+ @file ||= "#{@delivery_location}/#{file_name}"
117
+
118
+ File.write(@file, contents)
119
+ rescue StandardError => e
120
+ NewRelic::Agent.logger.error("Agent Control health check raised an error while writing a file: #{e}")
121
+ @continue = false
122
+ end
123
+
124
+ def health_checks_enabled?
125
+ @enabled && @delivery_location && @frequency > 0
126
+ end
127
+
128
+ def update_message(options)
129
+ @status[:message] = sprintf(@status[:message], *options)
130
+ rescue StandardError => e
131
+ NewRelic::Agent.logger.debug("Error raised while updating Agent Control health check message: #{e}." \
132
+ "options = #{options}, @status[:message] = #{@status[:message]}")
133
+ end
134
+ end
135
+ end
136
+ end
@@ -225,7 +225,8 @@ module NewRelic
225
225
 
226
226
  'postgresql' => :postgres,
227
227
  'jdbcpostgresql' => :postgres,
228
- 'postgis' => :postgres
228
+ 'postgis' => :postgres,
229
+ 'redshift' => :postgres
229
230
  }.freeze
230
231
 
231
232
  DATASTORE_DEFAULT_PORTS = {
@@ -116,10 +116,14 @@ module NewRelic
116
116
  port_path_or_id = nil
117
117
  database = nil
118
118
 
119
- if ActiveRecordHelper::InstanceIdentification.supported_adapter?(config)
120
- host = ActiveRecordHelper::InstanceIdentification.host(config)
121
- port_path_or_id = ActiveRecordHelper::InstanceIdentification.port_path_or_id(config)
122
- database = config && config[:database]
119
+ begin
120
+ if ActiveRecordHelper::InstanceIdentification.supported_adapter?(config)
121
+ host = ActiveRecordHelper::InstanceIdentification.host(config)
122
+ port_path_or_id = ActiveRecordHelper::InstanceIdentification.port_path_or_id(config)
123
+ database = config && config[:database]
124
+ end
125
+ rescue
126
+ NewRelic::Agent.logger.debug("Failed to retrieve ActiveRecord host, port, and database details for adapter: #{config && config[:adapter]}")
123
127
  end
124
128
 
125
129
  segment = Tracer.start_datastore_segment(product: product,
@@ -0,0 +1,21 @@
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 Firehose::Chain
7
+ def self.instrument!
8
+ ::Aws::Firehose::Client.class_eval do
9
+ include NewRelic::Agent::Instrumentation::Firehose
10
+
11
+ NewRelic::Agent::Instrumentation::Firehose::INSTRUMENTED_METHODS.each do |method_name|
12
+ alias_method("#{method_name}_without_new_relic".to_sym, method_name.to_sym)
13
+
14
+ define_method(method_name) do |*args|
15
+ instrument_method_with_new_relic(method_name, *args) { send("#{method_name}_without_new_relic".to_sym, *args) }
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,66 @@
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 Firehose
7
+ INSTRUMENTED_METHODS = %w[
8
+ create_delivery_stream
9
+ delete_delivery_stream
10
+ describe_delivery_stream
11
+ list_delivery_streams
12
+ list_tags_for_delivery_stream
13
+ put_record
14
+ put_record_batch
15
+ start_delivery_stream_encryption
16
+ stop_delivery_stream_encryption
17
+ tag_delivery_stream
18
+ untag_delivery_stream
19
+ update_destination
20
+ ].freeze
21
+
22
+ FIREHOSE = 'Firehose'
23
+ AWS_KINESIS_DELIVERY_STREAMS = 'aws_kinesis_delivery_streams'
24
+
25
+ def instrument_method_with_new_relic(method_name, *args)
26
+ return yield unless NewRelic::Agent::Tracer.tracing_enabled?
27
+
28
+ NewRelic::Agent.record_instrumentation_invocation(FIREHOSE)
29
+
30
+ params = args[0]
31
+ segment = NewRelic::Agent::Tracer.start_segment(name: get_segment_name(method_name, params))
32
+ arn = get_arn(params) if params
33
+ segment&.add_agent_attribute('cloud.resource_id', arn) if arn
34
+
35
+ begin
36
+ NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
37
+ ensure
38
+ segment&.add_agent_attribute('cloud.platform', AWS_KINESIS_DELIVERY_STREAMS)
39
+ segment&.finish
40
+ end
41
+ end
42
+
43
+ def get_segment_name(method_name, params)
44
+ stream_name = params&.dig(:delivery_stream_name)
45
+ return "#{FIREHOSE}/#{method_name}/#{stream_name}" if stream_name
46
+
47
+ "#{FIREHOSE}/#{method_name}"
48
+ rescue => e
49
+ NewRelic::Agent.logger.warn("Failed to create segment name: #{e}")
50
+ end
51
+
52
+ def nr_account_id
53
+ return @nr_account_id if defined?(@nr_account_id)
54
+
55
+ @nr_account_id = NewRelic::Agent::Aws.get_account_id(config)
56
+ end
57
+
58
+ def get_arn(params)
59
+ stream_arn = params&.dig(:delivery_stream_arn)
60
+ return stream_arn if stream_arn
61
+
62
+ stream_name = params&.dig(:delivery_stream_name)
63
+ NewRelic::Agent::Aws.create_arn(FIREHOSE.downcase, "deliverystream/#{stream_name}", config&.region, nr_account_id) if stream_name
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,15 @@
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 Firehose::Prepend
7
+ include NewRelic::Agent::Instrumentation::Firehose
8
+
9
+ INSTRUMENTED_METHODS.each do |method_name|
10
+ define_method(method_name) do |*args|
11
+ instrument_method_with_new_relic(method_name, *args) { super(*args) }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,22 @@
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 'aws_sdk_firehose/instrumentation'
6
+ require_relative 'aws_sdk_firehose/chain'
7
+ require_relative 'aws_sdk_firehose/prepend'
8
+
9
+ DependencyDetection.defer do
10
+ named :aws_sdk_firehose
11
+
12
+ depends_on do
13
+ defined?(Aws::Firehose::Client)
14
+ end
15
+ executes do
16
+ if use_prepend?
17
+ prepend_instrument Aws::Firehose::Client, NewRelic::Agent::Instrumentation::Firehose::Prepend
18
+ else
19
+ chain_instrument NewRelic::Agent::Instrumentation::Firehose::Chain
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,21 @@
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 Kinesis::Chain
7
+ def self.instrument!
8
+ ::Aws::Kinesis::Client.class_eval do
9
+ include NewRelic::Agent::Instrumentation::Kinesis
10
+
11
+ NewRelic::Agent::Instrumentation::Kinesis::INSTRUMENTED_METHODS.each do |method_name|
12
+ alias_method("#{method_name}_without_new_relic".to_sym, method_name.to_sym)
13
+
14
+ define_method(method_name) do |*args|
15
+ instrument_method_with_new_relic(method_name, *args) { send("#{method_name}_without_new_relic".to_sym, *args) }
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,91 @@
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 Kinesis
7
+ INSTRUMENTED_METHODS = %w[
8
+ add_tags_to_stream
9
+ create_stream
10
+ decrease_stream_retention_period
11
+ delete_stream
12
+ describe_limits
13
+ describe_stream
14
+ disable_enhanced_monitoring
15
+ enable_enhanced_monitoring
16
+ get_records
17
+ get_shard_iterator
18
+ increase_stream_retention_period
19
+ list_streams
20
+ list_tags_for_stream
21
+ merge_shards
22
+ put_record
23
+ put_records
24
+ remove_tags_from_stream
25
+ split_shard
26
+ update_shard_count
27
+ ].freeze
28
+
29
+ KINESIS = 'Kinesis'
30
+ AWS_KINESIS_DATA_STREAMS = 'aws_kinesis_data_streams'
31
+ MESSAGE_BROKER_SEGMENT_METHODS = %w[put_record put_records get_records].freeze
32
+
33
+ def instrument_method_with_new_relic(method_name, *args)
34
+ return yield unless NewRelic::Agent::Tracer.tracing_enabled?
35
+
36
+ NewRelic::Agent.record_instrumentation_invocation(KINESIS)
37
+ params = args[0]
38
+ arn = get_arn(params) if params
39
+
40
+ if MESSAGE_BROKER_SEGMENT_METHODS.include?(method_name)
41
+ stream_name = get_stream_name(params, arn)
42
+ segment = NewRelic::Agent::Tracer.start_message_broker_segment(
43
+ action: method_name == 'get_records' ? :consume : :produce,
44
+ library: KINESIS,
45
+ destination_type: :stream,
46
+ destination_name: stream_name
47
+ )
48
+ else
49
+ segment = NewRelic::Agent::Tracer.start_segment(name: get_segment_name(method_name, params))
50
+ end
51
+
52
+ segment&.add_agent_attribute('cloud.resource_id', arn) if arn
53
+
54
+ begin
55
+ NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
56
+ ensure
57
+ segment&.add_agent_attribute('cloud.platform', AWS_KINESIS_DATA_STREAMS)
58
+ segment&.finish
59
+ end
60
+ end
61
+
62
+ def get_segment_name(method_name, params)
63
+ stream_name = params&.dig(:stream_name)
64
+ return "#{KINESIS}/#{method_name}/#{stream_name}" if stream_name
65
+
66
+ "#{KINESIS}/#{method_name}"
67
+ rescue => e
68
+ NewRelic::Agent.logger.warn("Failed to create segment name: #{e}")
69
+ end
70
+
71
+ def get_stream_name(params, arn)
72
+ params&.dig(:stream_name) || arn.split('/').last || 'unknown'
73
+ rescue => e
74
+ NewRelic::Agent.logger.warn("Failed to get stream name: #{e}")
75
+ end
76
+
77
+ def nr_account_id
78
+ return @nr_account_id if defined?(@nr_account_id)
79
+
80
+ @nr_account_id = NewRelic::Agent::Aws.get_account_id(config)
81
+ end
82
+
83
+ def get_arn(params)
84
+ stream_arn = params&.dig(:stream_arn)
85
+ return stream_arn if stream_arn
86
+
87
+ stream_name = params&.dig(:stream_name)
88
+ NewRelic::Agent::Aws.create_arn(KINESIS.downcase, "stream/#{stream_name}", config&.region, nr_account_id) if stream_name
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,15 @@
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 Kinesis::Prepend
7
+ include NewRelic::Agent::Instrumentation::Kinesis
8
+
9
+ INSTRUMENTED_METHODS.each do |method_name|
10
+ define_method(method_name) do |*args|
11
+ instrument_method_with_new_relic(method_name, *args) { super(*args) }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,22 @@
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 'aws_sdk_kinesis/instrumentation'
6
+ require_relative 'aws_sdk_kinesis/chain'
7
+ require_relative 'aws_sdk_kinesis/prepend'
8
+
9
+ DependencyDetection.defer do
10
+ named :aws_sdk_kinesis
11
+
12
+ depends_on do
13
+ defined?(Aws::Kinesis::Client)
14
+ end
15
+ executes do
16
+ if use_prepend?
17
+ prepend_instrument Aws::Kinesis::Client, NewRelic::Agent::Instrumentation::Kinesis::Prepend
18
+ else
19
+ chain_instrument NewRelic::Agent::Instrumentation::Kinesis::Chain
20
+ end
21
+ end
22
+ end
@@ -56,10 +56,7 @@ module NewRelic::Agent::Instrumentation
56
56
 
57
57
  def name_transaction(route, class_name, version)
58
58
  txn_name = name_for_transaction(route, class_name, version)
59
- segment_name = "Middleware/Grape/#{class_name}/call"
60
59
  NewRelic::Agent::Transaction.set_default_transaction_name(txn_name, :grape)
61
- txn = NewRelic::Agent::Transaction.tl_current
62
- txn.segments.last.name = segment_name
63
60
  end
64
61
 
65
62
  def name_for_transaction(route, class_name, version)
@@ -19,7 +19,13 @@ DependencyDetection.defer do
19
19
  end
20
20
 
21
21
  executes do
22
- if NewRelic::Agent.config[:'resque.use_ruby_dns'] && NewRelic::Agent.config[:dispatcher] == :resque
22
+ if NewRelic::Agent.config[:'resque.use_ruby_dns'] &&
23
+ NewRelic::Agent.config[:dispatcher] == :resque &&
24
+ # resolv-replace is no longer part of the language in Ruby 3.4.
25
+ # we don't believe this lib is still necessary for Ruby 3.4 users.
26
+ # however, if we receive customer feedback to the contrary, we can find
27
+ # an alternate approach.
28
+ Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.4')
23
29
  NewRelic::Agent.logger.info('Requiring resolv-replace')
24
30
  require 'resolv'
25
31
  require 'resolv-replace'
@@ -6,7 +6,7 @@
6
6
  # Delayed extensions are disabled by default in Sidekiq 5 and 6 and
7
7
  # were removed entirely in Sidekiq 7.
8
8
  #
9
- # see https://github.com/mperham/sidekiq/issues/5076 for the discussion
9
+ # see https://github.com/sidekiq/sidekiq/issues/5076 for the discussion
10
10
  # of the removal, which includes mentions of alternatives
11
11
  if defined?(Sidekiq::VERSION) && Sidekiq::VERSION < '7.0.0'
12
12
  class Sidekiq::Extensions::DelayedClass
@@ -9,7 +9,7 @@ module NewRelic
9
9
  extend self
10
10
 
11
11
  def decorate(message)
12
- return message unless decorating_enabled?
12
+ return message if !decorating_enabled? || message.nil?
13
13
 
14
14
  metadata = NewRelic::Agent.linking_metadata
15
15
 
@@ -37,7 +37,17 @@ module NewRelic
37
37
  def escape_entity_name(entity_name)
38
38
  return unless entity_name
39
39
 
40
- URI::DEFAULT_PARSER.escape(entity_name)
40
+ # TODO: OLD RUBIES 3.3
41
+ # URI version 1.0 marked URI::RFC3986_PARSER.escape as obsolete,
42
+ # which URI::DEFAULT_PARSER is an alias for.
43
+ # URI version 1.0+ will ship with Ruby 3.4
44
+ # Once we drop support for Rubies below 3.4, we can use the
45
+ # URI::RFC2396 parser exclusively.
46
+ if Gem::Version.new(URI::VERSION) >= Gem::Version.new('1.0')
47
+ URI::RFC2396_PARSER.escape(entity_name)
48
+ else
49
+ URI::DEFAULT_PARSER.escape(entity_name)
50
+ end
41
51
  end
42
52
  end
43
53
  end
@@ -455,6 +455,8 @@ module NewRelic
455
455
  end
456
456
 
457
457
  def handle_error_response(response, endpoint)
458
+ NewRelic::Agent.agent.health_check.update_status(NewRelic::Agent::HealthCheck::HTTP_ERROR, [response.code, endpoint])
459
+
458
460
  case response
459
461
  when Net::HTTPRequestTimeOut,
460
462
  Net::HTTPTooManyRequests,
@@ -637,9 +639,13 @@ module NewRelic
637
639
  def send_request(opts)
638
640
  request = prep_request(opts)
639
641
  response = relay_request(request, opts)
640
- return response if response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPAccepted)
641
642
 
642
- handle_error_response(response, opts[:endpoint])
643
+ if response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPAccepted)
644
+ NewRelic::Agent.agent.health_check.update_status(NewRelic::Agent::HealthCheck::HEALTHY)
645
+ response
646
+ else
647
+ handle_error_response(response, opts[:endpoint])
648
+ end
643
649
  end
644
650
 
645
651
  def log_response(response)
@@ -125,7 +125,16 @@ module NewRelic
125
125
 
126
126
  # Returns [filename, method, line number]
127
127
  def parse_backtrace_frame(frame)
128
- frame =~ /([^:]*)(\:(\d+))?\:in `(.*)'/
128
+ # TODO: OLD RUBIES - Ruby 3.3
129
+ # The (?:`|') non-capturing group can be removed when the agent
130
+ # drops support for Ruby 3.3
131
+ # This group is used to capture the pre-Ruby 3.4.0 backtrace syntax.
132
+ # Example frame:
133
+ # Ruby 3.3.0 and below
134
+ # "irb.rb:69:in `catch'"
135
+ # Ruby 3.4.0+
136
+ # "irb.rb:69:in 'Kernel#catch'"
137
+ frame =~ /([^:]*)(\:(\d+))?\:in (?:`|')(.*)'/
129
138
  [$1, $4, $3] # sic
130
139
  end
131
140
  end
@@ -15,6 +15,7 @@ module NewRelic
15
15
  PRODUCE = 'Produce'.freeze
16
16
  QUEUE = 'Queue'.freeze
17
17
  PURGE = 'Purge'.freeze
18
+ STREAM = 'Stream'.freeze
18
19
  TEMP = 'Temp'.freeze
19
20
  TOPIC = 'Topic'.freeze
20
21
  UNKNOWN = 'Unknown'.freeze
@@ -22,6 +23,7 @@ module NewRelic
22
23
  DESTINATION_TYPES = [
23
24
  :exchange,
24
25
  :queue,
26
+ :stream,
25
27
  :topic,
26
28
  :temporary_queue,
27
29
  :temporary_topic,
@@ -37,6 +39,7 @@ module NewRelic
37
39
  TYPES = {
38
40
  exchange: EXCHANGE,
39
41
  temporary_queue: QUEUE,
42
+ stream: STREAM,
40
43
  queue: QUEUE,
41
44
  temporary_topic: TOPIC,
42
45
  topic: TOPIC,
@@ -144,8 +144,6 @@ module DependencyDetection
144
144
  !(disabled_configured? || deprecated_disabled_configured?)
145
145
  end
146
146
 
147
- # TODO: MAJOR VERSION
148
- # will only return true if a disabled key is found and is truthy
149
147
  def deprecated_disabled_configured?
150
148
  return false if self.name.nil?
151
149
 
@@ -153,12 +151,7 @@ module DependencyDetection
153
151
  return false unless ::NewRelic::Agent.config[key] == true
154
152
 
155
153
  ::NewRelic::Agent.logger.debug("Not installing #{self.name} instrumentation because of configuration #{key}")
156
- ::NewRelic::Agent.logger.debug( \
157
- "[DEPRECATED] configuration #{key} for #{self.name} will be removed in the next major release. " \
158
- "Use `#{config_key}` with one of `#{VALID_CONFIG_VALUES.map(&:to_s).inspect}`"
159
- )
160
-
161
- return true
154
+ true
162
155
  end
163
156
 
164
157
  def config_key
@@ -6,8 +6,8 @@
6
6
  module NewRelic
7
7
  module VERSION # :nodoc:
8
8
  MAJOR = 9
9
- MINOR = 16
10
- TINY = 1
9
+ MINOR = 17
10
+ TINY = 0
11
11
 
12
12
  STRING = "#{MAJOR}.#{MINOR}.#{TINY}"
13
13
  end
data/newrelic.yml CHANGED
@@ -74,7 +74,7 @@ common: &default_settings
74
74
 
75
75
  # Sets the minimum level a log event must have to be forwarded to New Relic.
76
76
  # This is based on the integer values of Ruby's Logger::Severity constants:
77
- # https://github.com/ruby/ruby/blob/master/lib/logger/severity.rb
77
+ # https://github.com/ruby/logger/blob/113b82a06b3076b93a71cd467e1605b23afb3088/lib/logger/severity.rb
78
78
  # The intention is to forward logs with the level given to the configuration, as
79
79
  # well as any logs with a higher level of severity.
80
80
  # For example, setting this value to "debug" will forward all log events to New
@@ -453,6 +453,14 @@ common: &default_settings
453
453
  # prepend, chain, disabled.
454
454
  # instrumentation.async_http: auto
455
455
 
456
+ # Controls auto-instrumentation of the aws-sdk-firehose library at start-up. May
457
+ # be one of auto, prepend, chain, disabled.
458
+ # instrumentation.aws_sdk_firehose: auto
459
+
460
+ # Controls auto-instrumentation of the aws-sdk-kinesis library at start-up. May
461
+ # be one of auto, prepend, chain, disabled.
462
+ # instrumentation.aws_sdk_kinesis: auto
463
+
456
464
  # Controls auto-instrumentation of the aws_sdk_lambda library at start-up. May
457
465
  # be one of auto, prepend, chain, disabled.
458
466
  # instrumentation.aws_sdk_lambda: auto
@@ -793,7 +801,7 @@ common: &default_settings
793
801
  # strip_exception_messages.allowed_classes: ""
794
802
 
795
803
  # If true, the agent strips messages from all exceptions except those in the
796
- # allowlist. Enabled automatically in high security mode.
804
+ # allowed classes list. Enabled automatically in high security mode.
797
805
  # strip_exception_messages.enabled: false
798
806
 
799
807
  # An array of strings to specify which keys and/or values inside a Stripe
@@ -949,8 +957,8 @@ common: &default_settings
949
957
  # NOTE: All "security.*" configuration parameters are related only to the
950
958
  # security agent, and all other configuration parameters that may
951
959
  # have "security" in the name somewhere are related to the APM agent.
952
-
953
- # If true, the security agent loads (the agent performs a Ruby 'require')
960
+
961
+ # If true, the security agent is loaded (a Ruby 'require' is performed)
954
962
  # security.agent.enabled: false
955
963
 
956
964
  # The port the application is listening on. This setting is mandatory for
data/test/agent_helper.rb CHANGED
@@ -115,6 +115,13 @@ def assert_log_contains(log, message)
115
115
  "Could not find message: '#{message.inspect}'. Log contained: #{lines.join("\n")}"
116
116
  end
117
117
 
118
+ def refute_log_contains(log, message)
119
+ lines = log.array
120
+
121
+ refute (lines.any? { |line| line.match(message) }),
122
+ "Found message: '#{message.inspect}'. Log contained: #{lines.join("\n")}"
123
+ end
124
+
118
125
  def assert_audit_log_contains(audit_log_contents, needle)
119
126
  # Original request bodies dumped to the log have symbol keys, but once
120
127
  # they go through a dump/load, they're strings again, so we strip
metadata CHANGED
@@ -1,17 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: newrelic_rpm
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.16.1
4
+ version: 9.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tanna McClure
8
8
  - Kayla Reopelle
9
9
  - James Bunch
10
10
  - Hannah Ramadan
11
- autorequire:
12
11
  bindir: bin
13
12
  cert_chain: []
14
- date: 2024-12-04 00:00:00.000000000 Z
13
+ date: 2025-01-29 00:00:00.000000000 Z
15
14
  dependencies:
16
15
  - !ruby/object:Gem::Dependency
17
16
  name: bundler
@@ -344,6 +343,7 @@ files:
344
343
  - lib/new_relic/agent/external.rb
345
344
  - lib/new_relic/agent/guid_generator.rb
346
345
  - lib/new_relic/agent/harvester.rb
346
+ - lib/new_relic/agent/health_check.rb
347
347
  - lib/new_relic/agent/heap.rb
348
348
  - lib/new_relic/agent/hostname.rb
349
349
  - lib/new_relic/agent/http_clients/abstract.rb
@@ -392,6 +392,14 @@ files:
392
392
  - lib/new_relic/agent/instrumentation/async_http/chain.rb
393
393
  - lib/new_relic/agent/instrumentation/async_http/instrumentation.rb
394
394
  - lib/new_relic/agent/instrumentation/async_http/prepend.rb
395
+ - lib/new_relic/agent/instrumentation/aws_sdk_firehose.rb
396
+ - lib/new_relic/agent/instrumentation/aws_sdk_firehose/chain.rb
397
+ - lib/new_relic/agent/instrumentation/aws_sdk_firehose/instrumentation.rb
398
+ - lib/new_relic/agent/instrumentation/aws_sdk_firehose/prepend.rb
399
+ - lib/new_relic/agent/instrumentation/aws_sdk_kinesis.rb
400
+ - lib/new_relic/agent/instrumentation/aws_sdk_kinesis/chain.rb
401
+ - lib/new_relic/agent/instrumentation/aws_sdk_kinesis/instrumentation.rb
402
+ - lib/new_relic/agent/instrumentation/aws_sdk_kinesis/prepend.rb
395
403
  - lib/new_relic/agent/instrumentation/aws_sdk_lambda.rb
396
404
  - lib/new_relic/agent/instrumentation/aws_sdk_lambda/chain.rb
397
405
  - lib/new_relic/agent/instrumentation/aws_sdk_lambda/instrumentation.rb
@@ -767,7 +775,6 @@ metadata:
767
775
  documentation_uri: https://docs.newrelic.com/docs/agents/ruby-agent
768
776
  source_code_uri: https://github.com/newrelic/newrelic-ruby-agent
769
777
  homepage_uri: https://newrelic.com/ruby
770
- post_install_message:
771
778
  rdoc_options: []
772
779
  require_paths:
773
780
  - lib
@@ -782,8 +789,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
782
789
  - !ruby/object:Gem::Version
783
790
  version: 1.3.1
784
791
  requirements: []
785
- rubygems_version: 3.5.22
786
- signing_key:
792
+ rubygems_version: 3.6.2
787
793
  specification_version: 4
788
794
  summary: New Relic Ruby Agent
789
795
  test_files: []