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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +43 -1
- data/CONTRIBUTING.md +2 -2
- data/lib/boot/strap.rb +4 -3
- data/lib/new_relic/agent/agent.rb +4 -0
- data/lib/new_relic/agent/agent_helpers/connect.rb +3 -0
- data/lib/new_relic/agent/agent_helpers/harvest.rb +3 -0
- data/lib/new_relic/agent/agent_helpers/shutdown.rb +3 -0
- data/lib/new_relic/agent/agent_helpers/start_worker_thread.rb +1 -0
- data/lib/new_relic/agent/agent_helpers/startup.rb +7 -0
- data/lib/new_relic/agent/configuration/default_source.rb +45 -4
- data/lib/new_relic/agent/configuration/yaml_source.rb +6 -1
- data/lib/new_relic/agent/database.rb +2 -1
- data/lib/new_relic/agent/distributed_tracing.rb +2 -2
- data/lib/new_relic/agent/health_check.rb +136 -0
- data/lib/new_relic/agent/instrumentation/active_record_helper.rb +2 -1
- data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +8 -4
- data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/chain.rb +21 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/instrumentation.rb +66 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/prepend.rb +15 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_firehose.rb +22 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/chain.rb +21 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/instrumentation.rb +91 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/prepend.rb +15 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis.rb +22 -0
- data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +0 -3
- data/lib/new_relic/agent/instrumentation/resque.rb +7 -1
- data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delayed_class.rb +1 -1
- data/lib/new_relic/agent/local_log_decorator.rb +12 -2
- data/lib/new_relic/agent/new_relic_service.rb +8 -2
- data/lib/new_relic/agent/threading/backtrace_node.rb +10 -1
- data/lib/new_relic/agent/transaction/message_broker_segment.rb +3 -0
- data/lib/new_relic/dependency_detection.rb +1 -8
- data/lib/new_relic/version.rb +2 -2
- data/newrelic.yml +12 -4
- data/test/agent_helper.rb +7 -0
- metadata +12 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c16c3149d187e88f60c408712fa5da2209c4cac08769477b951df4dfb780e95b
|
4
|
+
data.tar.gz: d6a0c36115e0b2f9db2ceeb806435737865615dc9043b669376bab20f443dce9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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/
|
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://
|
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.
|
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)
|
@@ -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..
|
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
|
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 [
|
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
|
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
|
-
|
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.
|
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.
|
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
|
@@ -116,10 +116,14 @@ module NewRelic
|
|
116
116
|
port_path_or_id = nil
|
117
117
|
database = nil
|
118
118
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
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'] &&
|
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/
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/new_relic/version.rb
CHANGED
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/
|
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
|
-
#
|
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
|
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.
|
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:
|
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.
|
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: []
|