newrelic_rpm 9.9.0 → 9.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ad2c3da566c3fda3369af14dd1d25b82a582c3db88c910474634b1b8169648fc
4
- data.tar.gz: 1ebe2637f6cef4b3b3e70afb157b91516cc6bf37511f1acb1f3ec5e1caf917e5
3
+ metadata.gz: d3793bb498826b000ad9e00e7d57de0e95988c4ba213e341a6a8c18f90df772e
4
+ data.tar.gz: 6cb26b15c2faace4a7e1fd6775a3f69f965beaad10f395e0fb618cb411dbacfe
5
5
  SHA512:
6
- metadata.gz: d86c1de9e30e3952b7d5dbec62845693795e6c3b0273b5f34a19a0a550e208314774d3da08246c26c8e903657c36b71b91ae170911869f3e801879e8c8ee4e05
7
- data.tar.gz: bb5732481d984d24366be27b1186e35b753b7dff7613774b8f4f50749e516db6556edd93b1017e656535cf83ef306e31199e44b03d677ea8c249f472f7f30222
6
+ metadata.gz: acb8dd0c767f40796fa1afb9cc26c0a57a9bdd83a4cbf550589a094f5cf48da32caf1d4c0f10e154633b754086bd62aa17d393bffa37eee5a0128e72c3bd6160
7
+ data.tar.gz: 6ce06fe8f1506405b7696089bf366e1aa0ccd60ab0d5034b22db87ac3c4523bd9d8d4dc4a6b568515cd516cd5c64babf853cdfed4af1839fd45cbed0450994f5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # New Relic Ruby Agent Release Notes
2
2
 
3
+ ## v9.10.0
4
+
5
+ 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.
6
+
7
+ - **Feature: Add instrumentation for DynamoDB**
8
+
9
+ 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)
10
+
11
+ - **Feature: Automatically apply nonces from the Rails content security policy**
12
+
13
+ To auto-inject browser monitoring with the New Relic Ruby agent, you either need to set your content security policy to 'unsafe-inline' or provide a nonce. Previously, the only way to provide a nonce was by using the [`NewRelic::Agent.browser_timing_header`](https://rubydoc.info/gems/newrelic_rpm/NewRelic/Agent#browser_timing_header-instance_method) API. Now, when a Rails application uses [the content security policy configuration to add a nonce](https://guides.rubyonrails.org/security.html#adding-a-nonce), the nonce will be automatically applied to the browser agent. A new configuration option, [`browser_monitoring.content_security_policy_nonce`](https://docs.newrelic.com/docs/apm/agents/ruby-agent/configuration/ruby-agent-configuration/#browser_monitoring-content_security_policy_nonce), toggles this feature. It is on by default. Thank you [@baldarn](https://github.com/baldarn) for submitting this feature! [PR#2544](https://github.com/newrelic/newrelic-ruby-agent/pull/2544)
14
+
15
+ - **Bugfix: Expected errors related to HTTP status code, class, and message won't impact Apdex**
16
+
17
+ The agent is supposed to prevent observed application errors from negatively impacting Apdex if the errors are either ignored or expected. There are two ways for the agent to expect an error: via the `notice_error` API receiving an `expected: true` argument or via matches made against user-configured lists for expected HTTP status codes (`:'error_collector.expected_status_codes'`), expected error classes (`:'error_collector.expected_classes'`), or expected error messages (`:'error_collector.expected_messages'`). Previously, only errors expected via the `notice_error` API were correctly prevented from impacting Apdex. Expected errors set by configuration incorrectly impacted Apdex. This behavior has been fixed and now both types of expected errors will correctly not impact Apdex. Thanks very much to [@florianpilz](https://github.com/florianpilz) for bringing this issue to our attention. [PR#2619](https://github.com/newrelic/newrelic-ruby-agent/pull/2619)
18
+
19
+ - **Bugfix: Do not start the agent automatically when `rails runner` or `rails db` commands are ran**
20
+
21
+ [PR#2239](https://github.com/newrelic/newrelic-ruby-agent/pull/2239) taught the agent how to recognize `bin/rails` based contexts that it should not automatically start up in. But `bin/rails runner` and `bin/rails db` commands would still see the agent start automatically. Those 2 contexts will now no longer see the agent start automatically. Thank you to [@jdelStrother](https://github.com/jdelStrother) for both bringing the `bin/rails` context to our attention and for letting us know about the `bin/rails runner` and `bin/rails db` outliers that still needed fixing. [PR#2623](https://github.com/newrelic/newrelic-ruby-agent/pull/2623)
22
+
23
+ Older agent versions that are still supported by New Relic can update to the new list of denylisted constants by having the following line added to the `newrelic.yml` configuration file:
24
+
25
+ ```yaml
26
+ 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"
27
+ ```
28
+
3
29
  ## v9.9.0
4
30
 
5
31
  Version 9.9.0 introduces support for AWS Lambda serverless function observability, adds support for Elasticsearch 8.13.0, and adds the 'request.temperature' attribute to chat completion summaries in ruby-openai instrumentation.
@@ -8,6 +34,8 @@ Version 9.9.0 introduces support for AWS Lambda serverless function observabilit
8
34
 
9
35
  The Ruby agent is now capable of operating in a quick and light serverless mode suitable for observing AWS Lambda function invocations. For serverless use, the agent is delivered by a New Relic Lambda [layer](https://github.com/newrelic/newrelic-lambda-layers) that can be associated with a Lambda function. All reported data will appear in New Relic's dedicated serverless UI views. Only AWS based Lambda functions are supported for now, though support for other cloud hosted serverless offerings may be added in future depending on Ruby customer demand. The serverless functionality is only intended for use with the official New Relic Ruby layers for Lambda. Any existing workflows that involve the manual use of the Ruby agent in an AWS Lambda context without a New Relic layer should not be impacted.
10
36
 
37
+ For more details, see our [getting started guide](https://docs.newrelic.com/docs/serverless-function-monitoring/aws-lambda-monitoring/get-started/monitoring-aws-lambda-serverless-monitoring/).
38
+
11
39
  - **Feature: Add support for Elasticsearch 8.13.0**
12
40
 
13
41
  Elasticsearch 8.13.0 increased the number of arguments used in the method the agent instruments, `Elastic::Transport::Client#perform_request`. Now, the agent supports a variable number of arguments for the instrumented method to prevent future `ArgumentError`s.
data/README.md CHANGED
@@ -23,6 +23,9 @@ can be found on [our docs site](http://docs.newrelic.com/docs/ruby/supported-fra
23
23
  You can also monitor non-web applications. Refer to the "Other
24
24
  Environments" section below.
25
25
 
26
+ We offer an AWS Lambda layer for instrumenting your serverless Ruby functions.
27
+ Details can be found on our [getting started guide](https://docs.newrelic.com/docs/serverless-function-monitoring/aws-lambda-monitoring/get-started/monitoring-aws-lambda-serverless-monitoring/).
28
+
26
29
  ## Installing and Using
27
30
 
28
31
  The latest released gem for the Ruby agent can be found at [RubyGems.org](https://rubygems.org/gems/newrelic_rpm)
data/Rakefile CHANGED
@@ -134,5 +134,5 @@ task :console do
134
134
  require 'pry' if ENV['ENABLE_PRY']
135
135
  require 'newrelic_rpm'
136
136
  ARGV.clear
137
- Pry.start
137
+ ENV['ENABLE_PRY'] ? Pry.start : binding.irb # rubocop:disable Lint/Debugger
138
138
  end
data/lib/bootstrap.rb ADDED
@@ -0,0 +1,105 @@
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
+ # This file is designed to bootstrap a `Bundler.require`-based Ruby app (such as
6
+ # a Ruby on Rails app) so the app can be instrumented and observed by the
7
+ # New Relic Ruby agent without the agent being added to the app as a dependency.
8
+ # NOTE: introducing the agent into your application via bootstrap is in beta.
9
+ # Use at your own risk.
10
+ #
11
+ # Given a production-ready Ruby app that optionally has a pre-packaged "frozen"
12
+ # or "deployment"–gem bundle, the New Relic Ruby agent can be introduced
13
+ # to the app without modifying the app and keeping all of the app's content
14
+ # read-only.
15
+ #
16
+ # Prerequisites:
17
+ # - Ruby (tested v2.4+)
18
+ # - Bundler (included with Ruby, tested v1.17+)
19
+ #
20
+ # Instructions:
21
+ # - First, make sure the New Relic Ruby agent exists on disk. For these
22
+ # instructions, we'll assume the agent exists at `/newrelic`.
23
+ # - The agent can be downloaded as the "newrelic_rpm" gem from RubyGems.org
24
+ # and unpacked with "gem unpack"
25
+ # - The agent can be cloned from the New Relic public GitHub repo:
26
+ # https://github.com/newrelic/newrelic-ruby-agent
27
+ # - Next, use the "RUBYOPT" environment variable to require ("-r") this
28
+ # file (note that the ".rb" extension is dropped):
29
+ # ```
30
+ # export RUBYOPT="-r /newrelic/lib/bootstrap"
31
+ # ```
32
+ # - Add your New Relic license key as an environment variable.
33
+ # ```
34
+ # export NEW_RELIC_LICENSE_KEY=1a2b3c4d5e67f8g9h0i
35
+ # ```
36
+ # - Launch an existing Ruby app as usual. For a Ruby on Rails app, this might
37
+ # involve running `bin/rails server`.
38
+ # - In the Ruby app's directory, look for and inspect
39
+ # `log/newrelic_agent.log`. If this file exists and there are no "WARN" or
40
+ # "ERROR" entries within it, then the agent was successfully introduced to
41
+ # the Ruby application.
42
+
43
+ module NRBundlerPatch
44
+ NR_AGENT_GEM = 'newrelic_rpm'
45
+
46
+ def require(*_groups)
47
+ super
48
+
49
+ require_newrelic
50
+ end
51
+
52
+ def require_newrelic
53
+ lib = File.dirname(__FILE__)
54
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
55
+ Kernel.require NR_AGENT_GEM
56
+ end
57
+ end
58
+
59
+ class NRBundlerPatcher
60
+ BUNDLER = 'bundler'
61
+ RUBYOPT = 'RUBYOPT'
62
+
63
+ def self.patch
64
+ check_for_require
65
+ check_for_rubyopt
66
+ check_for_bundler
67
+ Bundler::Runtime.prepend(NRBundlerPatch)
68
+ end
69
+
70
+ private
71
+
72
+ def self.check_for_require
73
+ warn_and_exit "#{__FILE__} is meant to be required, not invoked directly" if $PROGRAM_NAME == __FILE__
74
+ end
75
+
76
+ def self.check_for_rubyopt
77
+ unless ENV[RUBYOPT].to_s.match?("-r #{__FILE__.rpartition('.').first}")
78
+ warn_and_exit "#{__FILE__} is meant to be required via the RUBYOPT env var"
79
+ end
80
+ end
81
+
82
+ def self.check_for_bundler
83
+ require_bundler
84
+
85
+ warn_and_exit 'Required Ruby Bundler class Bundler::Runtime not defined!' unless defined?(Bundler::Runtime)
86
+
87
+ unless Bundler::Runtime.method_defined?(:require)
88
+ warn_and_exit "The active Ruby Bundler instance doesn't offer Bundler::Runtime#require"
89
+ end
90
+ end
91
+
92
+ def self.require_bundler
93
+ require BUNDLER
94
+ rescue LoadError => e
95
+ warn_and_exit "Required Ruby library '#{BUNDLER}' could not be required - #{e}"
96
+ end
97
+
98
+ def self.warn_and_exit(msg)
99
+ warn "New Relic entrypoint at #{__FILE__} encountered an issue:\n\t#{msg}"
100
+
101
+ exit 1
102
+ end
103
+ end
104
+
105
+ NRBundlerPatcher.patch
@@ -0,0 +1,56 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic
6
+ module Agent
7
+ module Aws
8
+ 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
9
+ HEX_MASK = '7fffffffff80'
10
+
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
+
15
+ "arn:aws:#{service}:#{region}:#{account_id}:#{resource}"
16
+ rescue => e
17
+ NewRelic::Agent.logger.warn("Failed to create ARN: #{e}")
18
+ end
19
+
20
+ def self.convert_access_key_to_account_id(access_key)
21
+ decoded_key = Integer(decode_to_hex(access_key[4..-1]), 16)
22
+ mask = Integer(HEX_MASK, 16)
23
+ (decoded_key & mask) >> 7
24
+ end
25
+
26
+ def self.decode_to_hex(access_key)
27
+ bytes = access_key.delete('=').each_char.map { |c| CHARACTERS.index(c) }
28
+
29
+ bytes.each_slice(8).map do |section|
30
+ convert_section(section)
31
+ end.flatten[0...6].join
32
+ end
33
+
34
+ def self.convert_section(section)
35
+ buffer = 0
36
+ section.each do |chunk|
37
+ buffer = (buffer << 5) + chunk
38
+ end
39
+
40
+ chunk_count = (section.length * 5.0 / 8.0).floor
41
+
42
+ if section.length < 8
43
+ buffer >>= (5 - (chunk_count * 8)) % 5
44
+ end
45
+
46
+ decoded = []
47
+ chunk_count.times do |i|
48
+ shift = 8 * (chunk_count - 1 - i)
49
+ decoded << ((buffer >> shift) & 255).to_s(16)
50
+ end
51
+
52
+ decoded
53
+ end
54
+ end
55
+ end
56
+ end
@@ -390,9 +390,11 @@ module NewRelic
390
390
  :description => <<~DESCRIPTION
391
391
  If `false`, LLM instrumentation (OpenAI only for now) will not capture input and output content on specific LLM events.
392
392
 
393
- The excluded attributes include:
394
- * `content` from LlmChatCompletionMessage events
395
- * `input` from LlmEmbedding events
393
+ The excluded attributes include:
394
+ * `content` from LlmChatCompletionMessage events
395
+ * `input` from LlmEmbedding events
396
+
397
+ This is an optional security setting to prevent recording sensitive data sent to and received from your LLMs.
396
398
  DESCRIPTION
397
399
  },
398
400
  # this is only set via server side config
@@ -477,12 +479,9 @@ module NewRelic
477
479
  :public => true,
478
480
  :type => Boolean,
479
481
  :allowed_from_server => false,
480
- :description => 'Forces the exit handler that sends all cached data to collector ' \
481
- 'before shutting down to be installed regardless of detecting scenarios where it generally should not be. ' \
482
- 'Known use-case for this option is where Sinatra is running as an embedded service within another framework ' \
483
- 'and the agent is detecting the Sinatra app and skipping the `at_exit` handler as a result. Sinatra classically ' \
484
- 'runs the entire application in an `at_exit` block and would otherwise misbehave if the agent\'s `at_exit` handler ' \
485
- 'was also installed in those circumstances. Note: `send_data_on_exit` should also be set to `true` in tandem with this setting.'
482
+ :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."
484
+ DESC
486
485
  },
487
486
  :high_security => {
488
487
  :default => false,
@@ -780,6 +779,15 @@ module NewRelic
780
779
  :allowed_from_server => true,
781
780
  :description => 'If `true`, enables [auto-injection](/docs/browser/new-relic-browser/installation-configuration/adding-apps-new-relic-browser#select-apm-app) of the JavaScript header for page load timing (sometimes referred to as real user monitoring or RUM).'
782
781
  },
782
+ # CSP nonce
783
+ :'browser_monitoring.content_security_policy_nonce' => {
784
+ :default => value_of(:'rum.enabled'),
785
+ :documentation_default => false,
786
+ :public => true,
787
+ :type => Boolean,
788
+ :allowed_from_server => false,
789
+ :description => 'If `true`, enables auto-injection of [Content Security Policy Nonce](https://content-security-policy.com/nonce/) in browser monitoring scripts. For now, auto-injection only works with Rails 5.2+.'
790
+ },
783
791
  # Transaction events
784
792
  :'transaction_events.enabled' => {
785
793
  :default => true,
@@ -1069,7 +1077,9 @@ module NewRelic
1069
1077
  Rails::Command::GenerateCommand
1070
1078
  Rails::Command::InitializersCommand
1071
1079
  Rails::Command::NotesCommand
1080
+ Rails::Command::RakeCommand
1072
1081
  Rails::Command::RoutesCommand
1082
+ Rails::Command::RunnerCommand
1073
1083
  Rails::Command::SecretsCommand
1074
1084
  Rails::Console
1075
1085
  Rails::DBConsole].join(','),
@@ -1440,6 +1450,14 @@ module NewRelic
1440
1450
  :allowed_from_server => false,
1441
1451
  :description => 'Controls auto-instrumentation of bunny at start-up. May be one of: `auto`, `prepend`, `chain`, `disabled`.'
1442
1452
  },
1453
+ :'instrumentation.dynamodb' => {
1454
+ :default => 'auto',
1455
+ :public => true,
1456
+ :type => String,
1457
+ :dynamic_name => true,
1458
+ :allowed_from_server => false,
1459
+ :description => 'Controls auto-instrumentation of the aws-sdk-dynamodb library at start-up. May be one of `auto`, `prepend`, `chain`, `disabled`.'
1460
+ },
1443
1461
  :'instrumentation.fiber' => {
1444
1462
  :default => 'auto',
1445
1463
  :public => true,
@@ -1488,7 +1506,7 @@ module NewRelic
1488
1506
  :type => String,
1489
1507
  :dynamic_name => true,
1490
1508
  :allowed_from_server => false,
1491
- :description => 'Controls auto-instrumentation of ethon at start up. May be one of [auto|prepend|chain|disabled]'
1509
+ :description => 'Controls auto-instrumentation of ethon at start up. May be one of `auto`, `prepend`, `chain`, `disabled`'
1492
1510
  },
1493
1511
  :'instrumentation.excon' => {
1494
1512
  :default => 'enabled',
@@ -1558,7 +1576,7 @@ module NewRelic
1558
1576
  :type => String,
1559
1577
  :dynamic_name => true,
1560
1578
  :allowed_from_server => false,
1561
- :description => 'Controls auto-instrumentation of httpx at start up. May be one of [auto|prepend|chain|disabled]'
1579
+ :description => 'Controls auto-instrumentation of httpx at start up. May be one of `auto`, `prepend`, `chain`, `disabled`'
1562
1580
  },
1563
1581
  :'instrumentation.logger' => {
1564
1582
  :default => instrumentation_value_from_boolean(:'application_logging.enabled'),
@@ -1620,7 +1638,7 @@ module NewRelic
1620
1638
  :type => String,
1621
1639
  :dynamic_name => true,
1622
1640
  :allowed_from_server => false,
1623
- :description => 'Controls auto-instrumentation of the ruby-openai gem at start-up. May be one of: `auto`, `prepend`, `chain`, `disabled`.'
1641
+ :description => 'Controls auto-instrumentation of the ruby-openai gem at start-up. May be one of: `auto`, `prepend`, `chain`, `disabled`. Defaults to `disabled` in high security mode.'
1624
1642
  },
1625
1643
  :'instrumentation.puma_rack' => {
1626
1644
  :default => value_of(:'instrumentation.rack'),
@@ -1963,7 +1981,11 @@ module NewRelic
1963
1981
  :public => true,
1964
1982
  :type => Integer,
1965
1983
  :allowed_from_server => true,
1966
- :description => 'Defines the maximum number of span events reported from a single harvest. Any Integer between `1` and `10000` is valid.'
1984
+ :description => <<~DESC
1985
+ * 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.
1988
+ DESC
1967
1989
  },
1968
1990
  # Strip exception messages
1969
1991
  :'strip_exception_messages.enabled' => {
@@ -110,6 +110,29 @@ module NewRelic
110
110
  false
111
111
  end
112
112
 
113
+ # Neither ignored nor expected errors impact apdex.
114
+ #
115
+ # Ignored errors are checked via `#error_is_ignored?`
116
+ # Expected errors are checked in 2 separate ways:
117
+ # 1. The presence of an `expected: true` attribute key/value pair in the
118
+ # options hash, which will be set if that key/value pair was used in
119
+ # the `notice_error` public API.
120
+ # 2. By calling `#expected?` which in turn calls `ErrorFilter#expected?`
121
+ # which checks for 3 things:
122
+ # - A match for user-defined HTTP status codes to expect
123
+ # - A match for user-defined error classes to expect
124
+ # - A match for user-defined error messages to expect
125
+ def error_affects_apdex?(error, options)
126
+ return false if error_is_ignored?(error)
127
+ return false if options[:expected]
128
+
129
+ !expected?(error, ::NewRelic::Agent::Tracer.state.current_transaction&.http_response_code)
130
+ rescue => e
131
+ NewRelic::Agent.logger.error("Could not determine if error '#{error}' should impact Apdex - " \
132
+ "#{e.class}: #{e.message}. Defaulting to 'true' (it should impact Apdex).")
133
+ true
134
+ end
135
+
113
136
  # Calling instance_variable_set on a wrapped Java object in JRuby will
114
137
  # generate a warning unless that object's class has already been marked
115
138
  # as persistent, so we skip tagging of exception objects that are actually
@@ -0,0 +1,27 @@
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 DynamoDB::Chain
7
+ def self.instrument!
8
+ ::Aws::DynamoDB::Client.class_eval do
9
+ include NewRelic::Agent::Instrumentation::DynamoDB
10
+
11
+ NewRelic::Agent::Instrumentation::DynamoDB::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
+
19
+ alias_method(:build_request_without_new_relic, :build_request)
20
+
21
+ def build_request(*args)
22
+ build_request_with_new_relic(*args) { build_request_without_new_relic(*args) }
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,58 @@
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 DynamoDB
7
+ INSTRUMENTED_METHODS = %w[
8
+ create_table
9
+ delete_item
10
+ delete_table
11
+ get_item
12
+ put_item
13
+ query
14
+ scan
15
+ update_item
16
+ ].freeze
17
+
18
+ PRODUCT = 'DynamoDB'
19
+ DEFAULT_HOST = 'dynamodb.amazonaws.com'
20
+
21
+ def instrument_method_with_new_relic(method_name, *args)
22
+ return yield unless NewRelic::Agent::Tracer.tracing_enabled?
23
+
24
+ NewRelic::Agent.record_instrumentation_invocation(PRODUCT)
25
+
26
+ segment = NewRelic::Agent::Tracer.start_datastore_segment(
27
+ product: PRODUCT,
28
+ operation: method_name,
29
+ host: config&.endpoint&.host || DEFAULT_HOST,
30
+ port_path_or_id: config&.endpoint&.port,
31
+ collection: args[0][:table_name]
32
+ )
33
+
34
+ arn = get_arn(args[0])
35
+ segment&.add_agent_attribute('cloud.resource_id', arn) if arn
36
+
37
+ @nr_captured_request = nil # clear request just in case
38
+ begin
39
+ NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
40
+ ensure
41
+ segment&.add_agent_attribute('aws.operation', method_name)
42
+ segment&.add_agent_attribute('aws.requestId', @nr_captured_request&.context&.http_response&.headers&.[]('x-amzn-requestid'))
43
+ segment&.add_agent_attribute('aws.region', config&.region)
44
+ segment&.finish
45
+ end
46
+ end
47
+
48
+ def build_request_with_new_relic(*args)
49
+ @nr_captured_request = yield
50
+ end
51
+
52
+ def get_arn(params)
53
+ return unless params[:table_name]
54
+
55
+ NewRelic::Agent::Aws.create_arn(PRODUCT.downcase, "table/#{params[:table_name]}", config)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,19 @@
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 DynamoDB::Prepend
7
+ include NewRelic::Agent::Instrumentation::DynamoDB
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
+
15
+ def build_request(*args)
16
+ build_request_with_new_relic(*args) { super }
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
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 'dynamodb/instrumentation'
6
+ require_relative 'dynamodb/chain'
7
+ require_relative 'dynamodb/prepend'
8
+
9
+ DependencyDetection.defer do
10
+ named :dynamodb
11
+
12
+ depends_on do
13
+ defined?(Aws::DynamoDB::Client)
14
+ end
15
+
16
+ executes do
17
+ NewRelic::Agent.logger.info('Installing DynamoDB instrumentation')
18
+
19
+ if use_prepend?
20
+ prepend_instrument Aws::DynamoDB::Client, NewRelic::Agent::Instrumentation::DynamoDB::Prepend
21
+ else
22
+ chain_instrument NewRelic::Agent::Instrumentation::DynamoDB::Chain
23
+ end
24
+ end
25
+ end
@@ -50,7 +50,6 @@ module NewRelic
50
50
  attributes_hash.each do |attr, value|
51
51
  segment.add_agent_attribute(attr, value)
52
52
  end
53
- segment.record_agent_attributes = true
54
53
  end
55
54
 
56
55
  def grpc_status_and_message_from_exception(exception)
@@ -79,17 +79,13 @@ module NewRelic
79
79
  intrinsics[SPAN_KIND_KEY] = CLIENT
80
80
  intrinsics[SERVER_ADDRESS_KEY] = segment.uri.host
81
81
  intrinsics[SERVER_PORT_KEY] = segment.uri.port
82
- agent_attributes = error_attributes(segment) || {}
82
+ agent_attributes = {}
83
83
 
84
84
  if allowed?(HTTP_URL_KEY)
85
85
  agent_attributes[HTTP_URL_KEY] = truncate(segment.uri)
86
86
  end
87
87
 
88
- if segment.respond_to?(:record_agent_attributes?) && segment.record_agent_attributes?
89
- agent_attributes.merge!(agent_attributes(segment))
90
- end
91
-
92
- [intrinsics, custom_attributes(segment), agent_attributes]
88
+ [intrinsics, custom_attributes(segment), agent_attributes.merge(agent_attributes(segment))]
93
89
  end
94
90
 
95
91
  def for_datastore_segment(segment) # rubocop:disable Metrics/AbcSize
@@ -99,7 +95,7 @@ module NewRelic
99
95
  intrinsics[SPAN_KIND_KEY] = CLIENT
100
96
  intrinsics[CATEGORY_KEY] = DATASTORE_CATEGORY
101
97
 
102
- agent_attributes = error_attributes(segment) || {}
98
+ agent_attributes = {}
103
99
 
104
100
  if segment.database_name && allowed?(DB_INSTANCE_KEY)
105
101
  agent_attributes[DB_INSTANCE_KEY] = truncate(segment.database_name)
@@ -123,7 +119,7 @@ module NewRelic
123
119
  agent_attributes[DB_STATEMENT_KEY] = truncate(segment.nosql_statement, 2000)
124
120
  end
125
121
 
126
- [intrinsics, custom_attributes(segment), agent_attributes]
122
+ [intrinsics, custom_attributes(segment), agent_attributes.merge(agent_attributes(segment))]
127
123
  end
128
124
 
129
125
  private
@@ -23,7 +23,6 @@ module NewRelic
23
23
  MISSING_STATUS_CODE = 'MissingHTTPStatusCode'
24
24
 
25
25
  attr_reader :library, :uri, :procedure, :http_status_code
26
- attr_writer :record_agent_attributes
27
26
 
28
27
  def initialize(library, uri, procedure, start_time = nil) # :nodoc:
29
28
  @library = library
@@ -32,7 +31,6 @@ module NewRelic
32
31
  @host_header = nil
33
32
  @app_data = nil
34
33
  @http_status_code = nil
35
- @record_agent_attributes = false
36
34
  super(nil, nil, start_time)
37
35
  end
38
36
 
@@ -44,14 +42,6 @@ module NewRelic
44
42
  @host_header || uri.host
45
43
  end
46
44
 
47
- # By default external request segments only have errors and the http
48
- # url recorded as agent attributes. To have all the agent attributes
49
- # recorded, use the attr_writer like so `segment.record_agent_attributes = true`
50
- # See: SpanEventPrimitive#for_external_request_segment
51
- def record_agent_attributes?
52
- @record_agent_attributes
53
- end
54
-
55
45
  # This method adds New Relic request headers to a given request made to an
56
46
  # external API and checks to see if a host header is used for the request.
57
47
  # If a host header is used, it updates the segment name to match the host
@@ -816,13 +816,9 @@ module NewRelic
816
816
  end
817
817
 
818
818
  def had_error_affecting_apdex?
819
- @exceptions.each do |exception, options|
820
- ignored = NewRelic::Agent.instance.error_collector.error_is_ignored?(exception)
821
- expected = options[:expected]
822
-
823
- return true unless ignored || expected
819
+ @exceptions.each.any? do |exception, options|
820
+ NewRelic::Agent.instance.error_collector.error_affects_apdex?(exception, options)
824
821
  end
825
- false
826
822
  end
827
823
 
828
824
  def apdex_bucket(duration, current_apdex_t)
@@ -64,6 +64,7 @@ module NewRelic
64
64
  require 'new_relic/agent/linking_metadata'
65
65
  require 'new_relic/agent/local_log_decorator'
66
66
  require 'new_relic/agent/llm'
67
+ require 'new_relic/agent/aws'
67
68
 
68
69
  require 'new_relic/agent/instrumentation/controller_instrumentation'
69
70
 
@@ -38,7 +38,7 @@ module NewRelic
38
38
  result = @app.call(env)
39
39
  (status, headers, response) = result
40
40
 
41
- js_to_inject = NewRelic::Agent.browser_timing_header
41
+ js_to_inject = NewRelic::Agent.browser_timing_header(nonce(env))
42
42
  if (js_to_inject != NewRelic::EMPTY_STR) && should_instrument?(env, status, headers)
43
43
  response_string = autoinstrument_source(response, js_to_inject)
44
44
  if headers.key?(CONTENT_LENGTH)
@@ -58,6 +58,14 @@ module NewRelic
58
58
  end
59
59
  end
60
60
 
61
+ def nonce(env)
62
+ return unless NewRelic::Agent.config[:'browser_monitoring.content_security_policy_nonce']
63
+ return unless NewRelic::Agent.config[:framework] == :rails_notifications
64
+ return unless defined?(ActionDispatch::ContentSecurityPolicy::Request)
65
+
66
+ env[ActionDispatch::ContentSecurityPolicy::Request::NONCE]
67
+ end
68
+
61
69
  def should_instrument?(env, status, headers)
62
70
  NewRelic::Agent.config[:'browser_monitoring.auto_instrument'] &&
63
71
  status == 200 &&
@@ -6,7 +6,7 @@
6
6
  module NewRelic
7
7
  module VERSION # :nodoc:
8
8
  MAJOR = 9
9
- MINOR = 9
9
+ MINOR = 10
10
10
  TINY = 0
11
11
 
12
12
  STRING = "#{MAJOR}.#{MINOR}.#{TINY}"
@@ -20,7 +20,7 @@ namespace :newrelic do
20
20
  ATTRIBUTES => '[Attributes](/docs/features/agent-attributes) are key-value pairs containing information that determines the properties of an event or transaction. These key-value pairs can be viewed within transaction traces in APM, traced errors in APM, transaction events in dashboards, and page views in dashboards. You can customize exactly which attributes will be sent to each of these destinations',
21
21
  'transaction_tracer' => 'The [transaction traces](/docs/apm/traces/transaction-traces/transaction-traces) feature collects detailed information from a selection of transactions, including a summary of the calling sequence, a breakdown of time spent, and a list of SQL queries and their query plans (on mysql and postgresql). Available features depend on your New Relic subscription level.',
22
22
  'error_collector' => "The agent collects and reports all uncaught exceptions by default. These configuration options allow you to customize the error collection.\n\nFor information on ignored and expected errors, [see this page on Error Analytics in APM](/docs/agents/manage-apm-agents/agent-data/manage-errors-apm-collect-ignore-or-mark-expected/). To set expected errors via the `NewRelic::Agent.notice_error` Ruby method, [consult the Ruby agent API](/docs/agents/ruby-agent/api-guides/sending-handled-errors-new-relic/).",
23
- 'browser_monitoring' => "The browser monitoring [page load timing](/docs/browser/new-relic-browser/page-load-timing/page-load-timing-process) feature (sometimes referred to as real user monitoring or RUM) gives you insight into the performance real users are experiencing with your website. This is accomplished by measuring the time it takes for your users' browsers to download and render your web pages by injecting a small amount of JavaScript code into the header and footer of each page.",
23
+ 'browser_monitoring' => "The <InlinePopover type='browser' /> [page load timing](/docs/browser/new-relic-browser/page-load-timing/page-load-timing-process) feature (sometimes referred to as real user monitoring or RUM) gives you insight into the performance real users are experiencing with your website. This is accomplished by measuring the time it takes for your users' browsers to download and render your web pages by injecting a small amount of JavaScript code into the header and footer of each page.",
24
24
  'application_logging' => "The Ruby agent supports [APM logs in context](/docs/apm/new-relic-apm/getting-started/get-started-logs-context). For some tips on configuring logs for the Ruby agent, see [Configure Ruby logs in context](/docs/logs/logs-context/configure-logs-context-ruby).\n\nAvailable logging-related config options include:",
25
25
  'analytics_events' => '[New Relic dashboards](/docs/query-your-data/explore-query-data/dashboards/introduction-new-relic-one-dashboards) is a resource to gather and visualize data about your software and what it says about your business. With it you can quickly and easily create real-time dashboards to get immediate answers about end-user experiences, clickstreams, mobile activities, and server transactions.',
26
26
  'ai_monitoring' => "This section includes Ruby agent configurations for setting up AI monitoring.\n\n<Callout variant='important'>You need to enable distributed tracing to capture trace and feedback data. It is turned on by default in Ruby agents 8.0.0 and higher.</Callout>"
@@ -28,7 +28,8 @@ namespace :newrelic do
28
28
 
29
29
  NAME_OVERRIDES = {
30
30
  'slow_sql' => 'Slow SQL [#slow-sql]',
31
- 'custom_insights_events' => 'Custom Events [#custom-events]'
31
+ 'custom_insights_events' => 'Custom Events [#custom-events]',
32
+ 'ai_monitoring' => 'AI Monitoring [#ai-monitoring]'
32
33
  }
33
34
 
34
35
  desc 'Describe available New Relic configuration settings'
@@ -10,6 +10,7 @@ redirects:
10
10
  - /docs/ruby/ruby-agent-configuration
11
11
  - /docs/agents/ruby-agent/installation-and-configuration/ruby-agent-configuration
12
12
  - /docs/agents/ruby-agent/installation-configuration/ruby-agent-configuration
13
+ freshnessValidatedDate: never
13
14
  ---
14
15
 
15
16
  <CONTRIBUTOR_NOTE>
@@ -70,12 +71,12 @@ The Ruby agent looks for the following environment variables, in this order, to
70
71
 
71
72
  If the Ruby agent doesn't detect values for any of those environment variables, it will default the application environment to `development` and read from the `development` section of the `newrelic.yml` config file.
72
73
 
73
- When running the Ruby agent in a Rails app, the agent first looks for the `NEW_RELIC_ENV` environment variable to determine the application environment and which section of the `newrelic.yml` to use. If `NEW_RELIC_ENV` is not present, the agent uses the Rails environment (`RAILS_ENV`).
74
+ When running the Ruby agent in a Rails app, the agent first looks for the `NEW_RELIC_ENV` environment variable to find the application environment and which section of the `newrelic.yml` to use. If `NEW_RELIC_ENV` is not present, the agent uses the Rails environment (`RAILS_ENV`).
74
75
 
75
76
  When you edit the config file, be sure to:
76
77
 
77
78
  * Indent only with two spaces.
78
- * Indent only where relevant, in stanzas such as **`error_collector`**.
79
+ * Indent only where relevant, in sections such as <DoNotTranslate>**`error_collector`**</DoNotTranslate>.
79
80
 
80
81
  If you do not indent correctly, the agent may throw an `Unable to parse configuration file` error on startup.
81
82
 
@@ -69,7 +69,7 @@ module Format
69
69
 
70
70
  def format_description(value)
71
71
  description = ''
72
- description += '**DEPRECATED** ' if value[:deprecated]
72
+ description += '<DoNotTranslate>**DEPRECATED**</DoNotTranslate>' if value[:deprecated]
73
73
  description += value[:description]
74
74
  description
75
75
  end
data/newrelic.yml CHANGED
@@ -114,7 +114,7 @@ common: &default_settings
114
114
  # Specify a list of constants that should prevent the agent from starting
115
115
  # automatically. Separate individual constants with a comma ,. For example,
116
116
  # "Rails::Console,UninstrumentedBackgroundJob".
117
- # 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::SecretsCommand,Rails::Console,Rails::DBConsole
117
+ # 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
118
118
 
119
119
  # Defines a comma-delimited list of executables that the agent should not
120
120
  # instrument. For example, "rake,my_ruby_script.rb".
@@ -144,6 +144,10 @@ common: &default_settings
144
144
  # (sometimes referred to as real user monitoring or RUM).
145
145
  # browser_monitoring.auto_instrument: true
146
146
 
147
+ # If true, enables auto-injection of Content Security Policy Nonce in browser
148
+ # monitoring scripts. For now, auto-injection only works with Rails 5.2+.
149
+ # browser_monitoring.content_security_policy_nonce: false
150
+
147
151
  # Manual override for the path to your local CA bundle. This CA bundle will be
148
152
  # used to validate the SSL certificate presented by New Relic's data collection
149
153
  # service.
@@ -415,6 +419,10 @@ common: &default_settings
415
419
  # prepend, chain, disabled.
416
420
  # instrumentation.delayed_job: auto
417
421
 
422
+ # Controls auto-instrumentation of the aws-sdk-dynamodb library at start-up. May
423
+ # be one of [auto|prepend|chain|disabled].
424
+ # instrumentation.dynamodb: auto
425
+
418
426
  # Controls auto-instrumentation of the elasticsearch library at start-up. May be
419
427
  # one of: auto, prepend, chain, disabled.
420
428
  # instrumentation.elasticsearch: auto
data/test/agent_helper.rb CHANGED
@@ -228,7 +228,9 @@ def assert_metrics_recorded(expected)
228
228
  expected.each do |specish, expected_attrs|
229
229
  expected_spec = metric_spec_from_specish(specish)
230
230
  actual_stats = NewRelic::Agent.instance.stats_engine.to_h[expected_spec]
231
- if !actual_stats
231
+ if actual_stats
232
+ assert(actual_stats)
233
+ else
232
234
  all_specs = NewRelic::Agent.instance.stats_engine.to_h.keys.sort
233
235
  matches = all_specs.select { |spec| spec.name == expected_spec.name }
234
236
  matches.map! { |m| " #{m.inspect}" }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: newrelic_rpm
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.9.0
4
+ version: 9.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tanna McClure
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2024-04-17 00:00:00.000000000 Z
14
+ date: 2024-05-29 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -243,6 +243,7 @@ files:
243
243
  - bin/nrdebug
244
244
  - init.rb
245
245
  - install.rb
246
+ - lib/bootstrap.rb
246
247
  - lib/new_relic/agent.rb
247
248
  - lib/new_relic/agent/adaptive_sampler.rb
248
249
  - lib/new_relic/agent/agent.rb
@@ -260,6 +261,7 @@ files:
260
261
  - lib/new_relic/agent/attributes.rb
261
262
  - lib/new_relic/agent/audit_logger.rb
262
263
  - lib/new_relic/agent/autostart.rb
264
+ - lib/new_relic/agent/aws.rb
263
265
  - lib/new_relic/agent/chained_call.rb
264
266
  - lib/new_relic/agent/commands/agent_command.rb
265
267
  - lib/new_relic/agent/commands/agent_command_router.rb
@@ -381,6 +383,10 @@ files:
381
383
  - lib/new_relic/agent/instrumentation/delayed_job/instrumentation.rb
382
384
  - lib/new_relic/agent/instrumentation/delayed_job/prepend.rb
383
385
  - lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb
386
+ - lib/new_relic/agent/instrumentation/dynamodb.rb
387
+ - lib/new_relic/agent/instrumentation/dynamodb/chain.rb
388
+ - lib/new_relic/agent/instrumentation/dynamodb/instrumentation.rb
389
+ - lib/new_relic/agent/instrumentation/dynamodb/prepend.rb
384
390
  - lib/new_relic/agent/instrumentation/elasticsearch.rb
385
391
  - lib/new_relic/agent/instrumentation/elasticsearch/chain.rb
386
392
  - lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb
@@ -717,7 +723,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
717
723
  - !ruby/object:Gem::Version
718
724
  version: 1.3.1
719
725
  requirements: []
720
- rubygems_version: 3.4.10
726
+ rubygems_version: 3.5.9
721
727
  signing_key:
722
728
  specification_version: 4
723
729
  summary: New Relic Ruby Agent