Skip to content

Commit 90c44f5

Browse files
Merge pull request #2699 from newrelic/dev
Release 9.10.2
2 parents 968c118 + 7db0713 commit 90c44f5

File tree

12 files changed

+117
-60
lines changed

12 files changed

+117
-60
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,4 +357,4 @@ jobs:
357357
token: ${{ secrets.GITHUB_TOKEN }}
358358
resultPath: lib/coverage_results/.last_run.json
359359
failedThreshold: 93.5
360-
failedThresholdBranch: 71.5
360+
failedThresholdBranch: 50

CHANGELOG.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
# New Relic Ruby Agent Release Notes
22

3+
## v9.10.2
4+
5+
Version 9.10.2 fixes a bug related to the new DynamoDB instrumentation and removes `Rails::Command::RakeCommand` from the default list of denylisted constants.
6+
7+
- **Bugfix: DynamoDB instrumentation logging errors when trying to get account_id**
8+
9+
When trying to access data needed to add the `account_id` to the DynamoDB span, the agent encountered an error when certain credentials classes were used. This has been fixed. Thanks to [@kichik](https://github.com/kichik) for bringing this to our attention. [PR#2864](https://github.com/newrelic/newrelic-ruby-agent/pull/2684)
10+
11+
- **Bugfix: Remove Rails::Command::RakeCommand from the default list of autostart.denylisted_constants**
12+
13+
The default value for the `autostart.denylisted_constants` configuration was changed in 9.10.0 to include `Rails::Command::RunnerCommand` and `Rails::Command::RakeCommand`. The inclusion of `Rails::Command::RakeCommand` prevented the agent from starting automatically when Solid Queue was started using `bin/rails solid_queue:start`. We recognize there are many commands nested within `Rails::Command::RakeCommand` and have decided to remove it from the default list. We encourage users who do not want the agent to run on `Rails::Command::RakeCommand` to add the constant to their configuration. This can be accomplished by adding the following to your `newrelic.yml` file:
14+
15+
```yaml
16+
autostart.denylisted_constants: "Rails::Command::ConsoleCommand,Rails::Command::CredentialsCommand,Rails::Command::Db::System::ChangeCommand,Rails::Command::DbConsoleCommand,Rails::Command::DestroyCommand,Rails::Command::DevCommand,Rails::Command::EncryptedCommand,Rails::Command::GenerateCommand,Rails::Command::InitializersCommand,Rails::Command::NotesCommand,Rails::Command::RakeCommand,Rails::Command::RoutesCommand,Rails::Command::RunnerCommand,Rails::Command::SecretsCommand,Rails::Console,Rails::DBConsole"
17+
```
18+
19+
Thank you, [@edariedl](https://github.com/edariedl), for reporting this issue. [Issue#2677](https://github.com/newrelic/newrelic-ruby-agent/issues/2677) [PR#2694](https://github.com/newrelic/newrelic-ruby-agent/pull/2694)
20+
321
## v9.10.1
422
523
- **Bugfix: Incompatibility with Bootstrap**
@@ -11,7 +29,7 @@ Version 9.10.1 fixes an incompatibility between the agent and the [Bootstrap](ht
1129
Version 9.10.0 introduces instrumentation for DynamoDB, adds a new feature to automatically apply nonces from the Rails content security policy, fixes a bug that would cause an expected error to negatively impact a transaction's Apdex, and fixes the agent's autostart logic so that by default `rails runner` and `rails db` commands will not cause the agent to start.
1230

1331
- **Feature: Add instrumentation for DynamoDB**
14-
32+
1533
The agent has added instrumentation for the aws-sdk-dynamodb gem. The agent will now record datastore spans for DynamoDB client calls made with the aws-sdk-dynamodb gem. [PR#2642](https://github.com/newrelic/newrelic-ruby-agent/pull/2642)
1634

1735
- **Feature: Automatically apply nonces from the Rails content security policy**

lib/new_relic/agent/aws.rb

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,21 @@ module Aws
88
CHARACTERS = %w[A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 2 3 4 5 6 7].freeze
99
HEX_MASK = '7fffffffff80'
1010

11-
def self.create_arn(service, resource, config)
12-
region = config.region
13-
account_id = NewRelic::Agent::Aws.convert_access_key_to_account_id(config.credentials.access_key_id)
14-
11+
def self.create_arn(service, resource, region, account_id)
1512
"arn:aws:#{service}:#{region}:#{account_id}:#{resource}"
1613
rescue => e
1714
NewRelic::Agent.logger.warn("Failed to create ARN: #{e}")
1815
end
1916

17+
def self.get_account_id(config)
18+
access_key_id = config.credentials.credentials.access_key_id if config&.credentials&.credentials&.respond_to?(:access_key_id)
19+
return unless access_key_id
20+
21+
NewRelic::Agent::Aws.convert_access_key_to_account_id(access_key_id)
22+
rescue => e
23+
NewRelic::Agent.logger.debug("Failed to create account id: #{e}")
24+
end
25+
2026
def self.convert_access_key_to_account_id(access_key)
2127
decoded_key = Integer(decode_to_hex(access_key[4..-1]), 16)
2228
mask = Integer(HEX_MASK, 16)

lib/new_relic/agent/configuration/default_source.rb

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,12 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil)
480480
:type => Boolean,
481481
:allowed_from_server => false,
482482
:description => <<~DESC
483-
Forces the exit handler that sends all cached data to collector before shutting down to be installed regardless of detecting scenarios where it generally should not be. Known use-case for this option is where Sinatra is running as an embedded service within another framework and the agent is detecting the Sinatra app and skipping the `at_exit` handler as a result. Sinatra classically runs the entire application in an `at_exit` block and would otherwise misbehave if the Agent's `at_exit` handler was also installed in those circumstances. Note: `send_data_on_exit` should also be set to `true` in tandem with this setting."
483+
The exit handler that sends all cached data to the collector before shutting down is forcibly installed. \
484+
This is true even when it detects scenarios where it generally should not be. The known use case for this \
485+
option is when Sinatra runs as an embedded service within another framework. The agent detects the Sinatra \
486+
app and skips the `at_exit` handler as a result. Sinatra classically runs the entire application in an \
487+
`at_exit` block and would otherwise misbehave if the agent's `at_exit` handler was also installed in those \
488+
circumstances. Note: `send_data_on_exit` should also be set to `true` in tandem with this setting.
484489
DESC
485490
},
486491
:high_security => {
@@ -1077,7 +1082,6 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil)
10771082
Rails::Command::GenerateCommand
10781083
Rails::Command::InitializersCommand
10791084
Rails::Command::NotesCommand
1080-
Rails::Command::RakeCommand
10811085
Rails::Command::RoutesCommand
10821086
Rails::Command::RunnerCommand
10831087
Rails::Command::SecretsCommand
@@ -1144,8 +1148,12 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil)
11441148
:public => true,
11451149
:type => Integer,
11461150
:allowed_from_server => true,
1147-
:description => 'Specify a maximum number of custom events to buffer in memory at a time.',
1148-
:dynamic_name => true
1151+
:dynamic_name => true,
1152+
:description => <<~DESC
1153+
* Specify a maximum number of custom events to buffer in memory at a time.'
1154+
* When configuring the agent for [AI monitoring](/docs/ai-monitoring/intro-to-ai-monitoring), \
1155+
set to max value `100000`. This ensures the agent captures the maximum amount of LLM events.
1156+
DESC
11491157
},
11501158
# Datastore tracer
11511159
:'datastore_tracer.database_name_reporting.enabled' => {
@@ -1983,8 +1991,8 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil)
19831991
:allowed_from_server => true,
19841992
:description => <<~DESC
19851993
* Defines the maximum number of span events reported from a single harvest. Any Integer between `1` and `10000` is valid.'
1986-
* When configuring the agent for [AI monitoring](/docs/ai-monitoring/intro-to-ai-monitoring), set to max value `10000`.\
1987-
This ensures that the agent captures the maximum amount of distributed traces.
1994+
* When configuring the agent for [AI monitoring](/docs/ai-monitoring/intro-to-ai-monitoring), set to max value `10000`.\
1995+
This ensures the agent captures the maximum amount of distributed traces.
19881996
DESC
19891997
},
19901998
# Strip exception messages

lib/new_relic/agent/instrumentation/dynamodb/instrumentation.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,16 @@ def build_request_with_new_relic(*args)
4949
@nr_captured_request = yield
5050
end
5151

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+
5258
def get_arn(params)
53-
return unless params[:table_name]
59+
return unless params[:table_name] && nr_account_id
5460

55-
NewRelic::Agent::Aws.create_arn(PRODUCT.downcase, "table/#{params[:table_name]}", config)
61+
NewRelic::Agent::Aws.create_arn(PRODUCT.downcase, "table/#{params[:table_name]}", config&.region, nr_account_id)
5662
end
5763
end
5864
end

lib/new_relic/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module NewRelic
77
module VERSION # :nodoc:
88
MAJOR = 9
99
MINOR = 10
10-
TINY = 1
10+
TINY = 2
1111

1212
STRING = "#{MAJOR}.#{MINOR}.#{TINY}"
1313
end

lib/tasks/instrumentation_generator/instrumentation.thor

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,16 @@ class Instrumentation < Thor
3131

3232
def scaffold(name)
3333
@name = name
34+
@snake_name = snake_name(@name)
3435
@method = options[:method] if options[:method]
3536
@args = options[:args] if options[:args]
3637
@class_name = ::NewRelic::LanguageSupport.camelize(name)
37-
base_path = "#{INSTRUMENTATION_ROOT}#{name.downcase}"
38+
base_path = "#{INSTRUMENTATION_ROOT}#{@snake_name}"
3839

3940
empty_directory(base_path)
4041
create_instrumentation_files(base_path)
41-
append_to_default_source(name)
42-
append_to_newrelic_yml(name)
42+
append_to_default_source(@name, @snake_name)
43+
# append_to_newrelic_yml(@name, @snake_name) # This is now done on release, we don't need it anymore, but leaving it to be sure.
4344
create_tests(name)
4445
end
4546

@@ -69,53 +70,60 @@ class Instrumentation < Thor
6970
def create_tests(name)
7071
@name = name
7172
@instrumentation_method_global_erb_snippet = '<%= $instrumentation_method %>'
72-
base_path = "#{MULTIVERSE_SUITE_ROOT}#{@name.downcase}"
73+
@snake_name = snake_name(@name)
74+
base_path = "#{MULTIVERSE_SUITE_ROOT}#{@snake_name}"
7375
empty_directory(base_path)
7476
template('templates/Envfile.tt', "#{base_path}/Envfile")
75-
template('templates/test.tt', "#{base_path}/#{@name.downcase}_instrumentation_test.rb")
77+
template('templates/test.tt', "#{base_path}/#{@snake_name}_instrumentation_test.rb")
7678

7779
empty_directory("#{base_path}/config")
7880
template('templates/newrelic.yml.tt', "#{base_path}/config/newrelic.yml")
7981
end
8082

81-
def append_to_default_source(name)
83+
def append_to_default_source(name, snake_name)
8284
insert_into_file(
8385
DEFAULT_SOURCE_LOCATION,
84-
config_block(name.downcase),
86+
config_block(name, snake_name),
8587
after: ":description => 'Controls auto-instrumentation of bunny at start-up. May be one of: `auto`, `prepend`, `chain`, `disabled`.'
8688
},\n"
8789
)
8890
end
8991

90-
def append_to_newrelic_yml(name)
92+
def append_to_newrelic_yml(name, snake_name)
9193
insert_into_file(
9294
NEWRELIC_YML_LOCATION,
93-
yaml_block(name),
95+
yaml_block(name, snake_name),
9496
after: "# instrumentation.bunny: auto\n"
9597
)
9698
end
9799

98-
def config_block(name)
99-
<<~CONFIG
100-
:'instrumentation.#{name.downcase}' => {
101-
:default => 'auto',
102-
:public => true,
103-
:type => String,
104-
:dynamic_name => true,
105-
:allowed_from_server => false,
106-
:description => 'Controls auto-instrumentation of the #{name} library at start-up. May be one of [auto|prepend|chain|disabled].'
107-
},
100+
def config_block(name, snake_name)
101+
# Don't change to <<~
102+
# We want to preserve the whitespace so the config is correctly indented
103+
<<-CONFIG
104+
:'instrumentation.#{snake_name}' => {
105+
:default => 'auto',
106+
:public => true,
107+
:type => String,
108+
:dynamic_name => true,
109+
:allowed_from_server => false,
110+
:description => 'Controls auto-instrumentation of the #{name} library at start-up. May be one of `auto`, `prepend`, `chain`, `disabled`.'
111+
},
108112
CONFIG
109113
end
110114

111-
def yaml_block(name)
115+
def yaml_block(name, snake_name)
112116
<<~HEREDOC
113117
114118
# Controls auto-instrumentation of #{name} at start-up.
115119
# May be one of [auto|prepend|chain|disabled]
116-
# instrumentation.#{name.downcase}: auto
120+
# instrumentation.#{snake_name}: auto
117121
HEREDOC
118122
end
123+
124+
def snake_name(name)
125+
name.downcase.tr('-', '_')
126+
end
119127
end
120128

121129
Instrumentation.start(ARGV)

lib/tasks/instrumentation_generator/templates/dependency_detection.tt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
33
# frozen_string_literal: true
44

5-
require_relative '<%= @name.downcase %>/instrumentation'
6-
require_relative '<%= @name.downcase %>/chain'
7-
require_relative '<%= @name.downcase %>/prepend'
5+
require_relative '<%= @snake_name.downcase %>/instrumentation'
6+
require_relative '<%= @snake_name.downcase %>/chain'
7+
require_relative '<%= @snake_name.downcase %>/prepend'
88

99
DependencyDetection.defer do
10-
named :<%= @name.match?(/\-|\_/) ? "'#{@name.downcase}'" : @name.downcase %>
10+
named :<%= @name.match?(/\-|\_/) ? "'#{@snake_name}'" : @name.downcase %>
1111

1212
depends_on do
1313
# The class that needs to be defined to prepend/chain onto. This can be used

lib/tasks/instrumentation_generator/templates/newrelic.yml.tt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ development:
66
monitor_mode: true
77
license_key: bootstrap_newrelic_admin_license_key_000
88
instrumentation:
9-
<%= @name.downcase %>: <%= @instrumentation_method_global_erb_snippet %>
9+
<%= @snake_name %>: <%= @instrumentation_method_global_erb_snippet %>
1010
app_name: test
1111
log_level: debug
1212
host: 127.0.0.1

newrelic.yml

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ common: &default_settings
116116
# Specify a list of constants that should prevent the agent from starting
117117
# automatically. Separate individual constants with a comma ,. For example,
118118
# "Rails::Console,UninstrumentedBackgroundJob".
119-
# autostart.denylisted_constants: Rails::Command::ConsoleCommand,Rails::Command::CredentialsCommand,Rails::Command::Db::System::ChangeCommand,Rails::Command::DbConsoleCommand,Rails::Command::DestroyCommand,Rails::Command::DevCommand,Rails::Command::EncryptedCommand,Rails::Command::GenerateCommand,Rails::Command::InitializersCommand,Rails::Command::NotesCommand,Rails::Command::RakeCommand,Rails::Command::RoutesCommand,Rails::Command::RunnerCommand,Rails::Command::SecretsCommand,Rails::Console,Rails::DBConsole
119+
# autostart.denylisted_constants: Rails::Command::ConsoleCommand,Rails::Command::CredentialsCommand,Rails::Command::Db::System::ChangeCommand,Rails::Command::DbConsoleCommand,Rails::Command::DestroyCommand,Rails::Command::DevCommand,Rails::Command::EncryptedCommand,Rails::Command::GenerateCommand,Rails::Command::InitializersCommand,Rails::Command::NotesCommand,Rails::Command::RoutesCommand,Rails::Command::RunnerCommand,Rails::Command::SecretsCommand,Rails::Console,Rails::DBConsole
120120

121121
# Defines a comma-delimited list of executables that the agent should not
122122
# instrument. For example, "rake,my_ruby_script.rb".
@@ -188,7 +188,9 @@ common: &default_settings
188188
# If true, the agent captures custom events.
189189
# custom_insights_events.enabled: true
190190

191-
# Specify a maximum number of custom events to buffer in memory at a time.
191+
# * Specify a maximum number of custom events to buffer in memory at a time.'
192+
# * When configuring the agent for AI monitoring, set to max value 100000. This
193+
# ensures the agent captures the maximum amount of LLM events.
192194
# custom_insights_events.max_samples_stored: 3000
193195

194196
# If false, the agent will not add database_name parameter to transaction or slow
@@ -354,14 +356,14 @@ common: &default_settings
354356
# requests.
355357
# exclude_newrelic_header: false
356358

357-
# Forces the exit handler that sends all cached data to collector before shutting
358-
# down to be installed regardless of detecting scenarios where it generally should
359-
# not be. Known use-case for this option is where Sinatra is running as an
360-
# embedded service within another framework and the agent is detecting the Sinatra
361-
# app and skipping the at_exit handler as a result. Sinatra classically runs the
359+
# The exit handler that sends all cached data to the collector before shutting
360+
# down is forcibly installed. This is true even when it detects scenarios where it
361+
# generally should not be. The known use case for this option is when Sinatra runs
362+
# as an embedded service within another framework. The agent detects the Sinatra
363+
# app and skips the at_exit handler as a result. Sinatra classically runs the
362364
# entire application in an at_exit block and would otherwise misbehave if the
363-
# Agent's at_exit handler was also installed in those circumstances. Note:
364-
# send_data_on_exit should also be set to true in tandem with this setting."
365+
# agent's at_exit handler was also installed in those circumstances. Note:
366+
# send_data_on_exit should also be set to true in tandem with this setting.
365367
# force_install_exit_handler: false
366368

367369
# Ordinarily the agent reports dyno names with a trailing dot and process ID (for
@@ -699,8 +701,8 @@ common: &default_settings
699701

700702
# * Defines the maximum number of span events reported from a single harvest. Any
701703
# Integer between 1 and 10000 is valid.'
702-
# * When configuring the agent for AI monitoring, set to max value 10000. This
703-
# ensures that the agent captures the maximum amount of distributed traces.
704+
# * When configuring the agent for AI monitoring, set to max value 10000.This
705+
# ensures the agent captures the maximum amount of distributed traces.
704706
# span_events.max_samples_stored: 2000
705707

706708
# Sets the maximum number of span events to buffer when streaming to the trace

test/multiverse/suites/dynamodb/dynamodb_instrumentation_test.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
class DynamodbInstrumentationTest < Minitest::Test
88
def setup
99
Aws.config.update(stub_responses: true)
10+
NewRelic::Agent::Aws.stubs(:create_arn).returns('test-arn')
11+
NewRelic::Agent::Aws.stubs(:get_account_id).returns('123456789')
1012
@stats_engine = NewRelic::Agent.instance.stats_engine
1113
end
1214

@@ -22,7 +24,6 @@ def create_client
2224
def test_all_attributes_added_to_segment
2325
client = create_client
2426
Seahorse::Client::Http::Response.any_instance.stubs(:headers).returns({'x-amzn-requestid' => '1234321'})
25-
NewRelic::Agent::Aws.stubs(:create_arn).returns('test-arn')
2627

2728
in_transaction do |txn|
2829
client.query({

test/new_relic/agent/aws_test.rb

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,26 @@
66

77
class AwsTest < Minitest::Test
88
def test_create_arn
9+
service = 'test-service'
10+
region = 'us-test-region-1'
11+
account_id = '123456789'
12+
resource = 'test/test-resource'
13+
arn = NewRelic::Agent::Aws.create_arn(service, resource, region, account_id)
14+
15+
expected = 'arn:aws:test-service:us-test-region-1:123456789:test/test-resource'
16+
17+
assert_equal expected, arn
18+
end
19+
20+
def test_get_account_id
921
config = mock
10-
config.stubs(:region).returns('us-test-region-1')
1122
mock_credentials = mock
23+
mock_credentials.stubs(:credentials).returns(mock_credentials)
1224
mock_credentials.stubs(:access_key_id).returns('AKIAIOSFODNN7EXAMPLE') # this is a fake access key id from aws docs
1325
config.stubs(:credentials).returns(mock_credentials)
1426

15-
service = 'test-service'
16-
resource = 'test/test-resource'
17-
arn = NewRelic::Agent::Aws.create_arn(service, resource, config)
27+
account_id = NewRelic::Agent::Aws.get_account_id(config)
1828

19-
expected = 'arn:aws:test-service:us-test-region-1:36315003739:test/test-resource'
20-
21-
assert_equal expected, arn
29+
assert_equal 36315003739, account_id
2230
end
2331
end

0 commit comments

Comments
 (0)