From d04d5ac2c13d040bf310172fa19eb8e571411bef Mon Sep 17 00:00:00 2001 From: fallwith Date: Thu, 27 Apr 2023 22:02:18 -0700 Subject: [PATCH 001/109] k2 k2 --- .gitignore | 1 + .../agent/configuration/default_source.rb | 59 +++++++++++++++++++ lib/new_relic/control/instance_methods.rb | 1 + .../control/private_instance_methods.rb | 13 ++++ newrelic.yml | 25 ++++++++ newrelic_rpm.gemspec | 3 + 6 files changed, 102 insertions(+) diff --git a/.gitignore b/.gitignore index e9b456f626..89f3c8dc30 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,4 @@ Brewfile.lock.json .github/actions/simplecov-report/lib/ test/minitest/minitest_time_report gem_manifest_*.json +nr-security-home diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index 397944f272..de31b140be 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -2210,6 +2210,65 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Integer, :allowed_from_server => false, :description => 'This value represents the total amount of memory available to the host (not the process), in mebibytes (1024 squared or 1,048,576 bytes).' + }, + # security agent + :'security.agent.enabled' => { + :default => false, + :external => true, + :public => true, + :type => Boolean, + :allowed_from_server => false, + :description => 'If `true`, the security agent is loaded' + }, + :'security.enabled' => { + :default => false, + :external => true, + :public => true, + :type => Boolean, + :allowed_from_server => false, + :description => 'If `true`, the security agent is activated' + }, + :'security.mode' => { + :default => 'IAST', + :external => true, + :public => true, + :type => String, + :allowed_from_server => true, + :description => 'Defines the mode for the security agent to operate in. Currently only `IAST` is supported', + :dynamic_name => true + }, + :'security.validator_service_url' => { + :default => 'wss://csec.nr-data.net', + :external => true, + :public => true, + :type => String, + :allowed_from_server => true, + :description => 'Defines the end point URL for posting security related data', + :dynamic_name => true + }, + :'security.detection.rci.enabled' => { + :default => true, + :external => true, + :public => true, + :type => Boolean, + :allowed_from_server => false, + :description => 'If `true`, enables rci detection' + }, + :'security.detection.rxss.enabled' => { + :default => true, + :external => true, + :public => true, + :type => Boolean, + :allowed_from_server => false, + :description => 'If `true`, enables rxss detection' + }, + :'security.detection.deserialization.enabled' => { + :default => true, + :external => true, + :public => true, + :type => Boolean, + :allowed_from_server => false, + :description => 'If `true`, enables deserialization detection' } }.freeze end diff --git a/lib/new_relic/control/instance_methods.rb b/lib/new_relic/control/instance_methods.rb index 44e8f1dd47..ffba1f335d 100644 --- a/lib/new_relic/control/instance_methods.rb +++ b/lib/new_relic/control/instance_methods.rb @@ -116,6 +116,7 @@ def handle_invalid_security_settings def start_agent @started_in_env = self.env NewRelic::Agent.agent.start + init_security_agent end def app diff --git a/lib/new_relic/control/private_instance_methods.rb b/lib/new_relic/control/private_instance_methods.rb index bcd14c7a81..7f28f88baa 100644 --- a/lib/new_relic/control/private_instance_methods.rb +++ b/lib/new_relic/control/private_instance_methods.rb @@ -43,6 +43,19 @@ def init_instrumentation DependencyDetection.detect! end end + + def init_security_agent + if Agent.config[:'security.agent.enabled'] + Agent.logger.info('Invoking K2 security module') + require 'newrelic_security' + else + Agent.logger.info('K2 security module is disabled.') + end + rescue LoadError + Agent.logger.info('K2 security agent not found - skipping') + rescue StandardError => exception + Agent.logger.error("Exception in K2 Agent module loading: #{exception} #{exception.backtrace}") + end end end end diff --git a/newrelic.yml b/newrelic.yml index 691109eff5..8e75d4ef9c 100644 --- a/newrelic.yml +++ b/newrelic.yml @@ -692,6 +692,31 @@ common: &default_settings # If true, the agent automatically detects that it is running in a Pivotal Cloud Foundry environment. # utilization.detect_pcf: true + # BEGIN security agent + + # If true, the security agent is loaded + # security.agent.enabled: false + + # If true, the security agent is activated + # security.enabled: false + + # The mode for the security agent to operate in. Currently only 'IAST' is supported + # security.mode: IAST + + # Defines the end point URL for posting security related data + # security.validator_service_url: wss://csec.nr-data.net + + # If `true`, enables rci detection + # security.detection.rci.enabled: true + + # If `true`, enables rxss detection + # security.detection.rxss.enabled: true + + # If `true`, enables deserialization detection + # security.detection.deserialization.enabled: true + + # END security agent + # Environment-specific settings are in this section. # RAILS_ENV or RACK_ENV (as appropriate) is used to determine the environment. # If your application has other named environments, configure them here. diff --git a/newrelic_rpm.gemspec b/newrelic_rpm.gemspec index 9cb2889314..32dbacd932 100644 --- a/newrelic_rpm.gemspec +++ b/newrelic_rpm.gemspec @@ -46,6 +46,9 @@ Gem::Specification.new do |s| s.homepage = 'https://github.com/newrelic/rpm' s.require_paths = ['lib'] s.summary = 'New Relic Ruby Agent' + +# s.add_dependency 'newrelic_security', '1.0.0-limited-preview' + s.add_development_dependency 'bundler' s.add_development_dependency 'feedjira', '3.2.1' unless ENV['CI'] || RUBY_VERSION < '2.5' # for Gabby s.add_development_dependency 'httparty' unless ENV['CI'] # for perf tests and Gabby From b930ca7408fcf26f22874b62e3428ec19ca41210 Mon Sep 17 00:00:00 2001 From: fallwith Date: Fri, 28 Apr 2023 09:31:38 -0700 Subject: [PATCH 002/109] New Relic name updates --- lib/new_relic/control/private_instance_methods.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/new_relic/control/private_instance_methods.rb b/lib/new_relic/control/private_instance_methods.rb index 7f28f88baa..73771752d5 100644 --- a/lib/new_relic/control/private_instance_methods.rb +++ b/lib/new_relic/control/private_instance_methods.rb @@ -46,15 +46,15 @@ def init_instrumentation def init_security_agent if Agent.config[:'security.agent.enabled'] - Agent.logger.info('Invoking K2 security module') + Agent.logger.info('Invoking New Relic security module') require 'newrelic_security' else - Agent.logger.info('K2 security module is disabled.') + Agent.logger.info('New Relic security module is disabled.') end rescue LoadError - Agent.logger.info('K2 security agent not found - skipping') + Agent.logger.info('New Relic security agent not found - skipping') rescue StandardError => exception - Agent.logger.error("Exception in K2 Agent module loading: #{exception} #{exception.backtrace}") + Agent.logger.error("Exception in New Relic security module loading: #{exception} #{exception.backtrace}") end end end From fcd86040bd1642322e0caccf7811b07f2374f333 Mon Sep 17 00:00:00 2001 From: fallwith Date: Tue, 9 May 2023 08:29:19 -0700 Subject: [PATCH 003/109] add security.applicationinfo.port a manual port value can be passed to the security agent when needed --- lib/new_relic/agent/configuration/default_source.rb | 8 ++++++++ newrelic.yml | 3 +++ 2 files changed, 11 insertions(+) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index de31b140be..a68b66d144 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -2269,6 +2269,14 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Boolean, :allowed_from_server => false, :description => 'If `true`, enables deserialization detection' + }, + :'security.applicationinfo.port' => { + :default => -1, + :public => true, + :type => Integer, + :external => true, + :allowed_from_server => false, + :description => 'The port the application listens on (guessed by default, may be needed for Passenger)' } }.freeze end diff --git a/newrelic.yml b/newrelic.yml index 8e75d4ef9c..114ddea394 100644 --- a/newrelic.yml +++ b/newrelic.yml @@ -715,6 +715,9 @@ common: &default_settings # If `true`, enables deserialization detection # security.detection.deserialization.enabled: true + # The port the application listens on (guessed by default, may be needed for Passenger) + # security.applicationinfo.port: -1 + # END security agent # Environment-specific settings are in this section. From 9d56dfe4d0e0d9daed2f9e1eb1c499c18a9d2646 Mon Sep 17 00:00:00 2001 From: fallwith Date: Tue, 9 May 2023 10:58:37 -0700 Subject: [PATCH 004/109] description for security.applicationinfo.port update description for security.applicationinfo.port --- lib/new_relic/agent/configuration/default_source.rb | 2 +- newrelic.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index a68b66d144..efaf9a9283 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -2276,7 +2276,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Integer, :external => true, :allowed_from_server => false, - :description => 'The port the application listens on (guessed by default, may be needed for Passenger)' + :description => 'The port the application listens on (Mandatory for Passenger, for other servers detected by default)' } }.freeze end diff --git a/newrelic.yml b/newrelic.yml index 114ddea394..459bab6518 100644 --- a/newrelic.yml +++ b/newrelic.yml @@ -715,7 +715,7 @@ common: &default_settings # If `true`, enables deserialization detection # security.detection.deserialization.enabled: true - # The port the application listens on (guessed by default, may be needed for Passenger) + # The port the application listens on (Mandatory for Passenger, for other servers detected by default) # security.applicationinfo.port: -1 # END security agent From 2e8db5d6e66584530e461d6f79a3ba032aa39d03 Mon Sep 17 00:00:00 2001 From: fallwith Date: Wed, 10 May 2023 20:50:18 -0700 Subject: [PATCH 005/109] NewRelic::Control::SecurityInterface - introduce NewRelic::Control::SecurityInterface singleton class - leverage the singleton class to ensure the security agent is only ever initialized once - leverage the singleton class to defer security agent initialization in lockstep with dependency detection deference - have each singleton class perform its own `require` of the singleton library so that it's not necessary to understand that the library is coming in from the `Control` class that might seem to have nothing to do with the singleton class --- lib/new_relic/agent/agent_logger.rb | 1 + lib/new_relic/agent/database/obfuscator.rb | 1 + .../instrumentation/rack/instrumentation.rb | 3 ++ lib/new_relic/control.rb | 2 +- lib/new_relic/control/instance_methods.rb | 2 +- .../control/private_instance_methods.rb | 11 +----- lib/new_relic/control/security_interface.rb | 36 +++++++++++++++++++ .../suites/sidekiq/sidekiq_server.rb | 1 + 8 files changed, 45 insertions(+), 12 deletions(-) create mode 100644 lib/new_relic/control/security_interface.rb diff --git a/lib/new_relic/agent/agent_logger.rb b/lib/new_relic/agent/agent_logger.rb index e5fe2fa1e9..60a411887b 100644 --- a/lib/new_relic/agent/agent_logger.rb +++ b/lib/new_relic/agent/agent_logger.rb @@ -4,6 +4,7 @@ require 'thread' require 'logger' +require 'singleton' require 'new_relic/agent/hostname' require 'new_relic/agent/log_once' require 'new_relic/agent/instrumentation/logger/instrumentation' diff --git a/lib/new_relic/agent/database/obfuscator.rb b/lib/new_relic/agent/database/obfuscator.rb index 0a90dcdb6c..5063fdcfa0 100644 --- a/lib/new_relic/agent/database/obfuscator.rb +++ b/lib/new_relic/agent/database/obfuscator.rb @@ -2,6 +2,7 @@ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. # frozen_string_literal: true +require 'singleton' require 'new_relic/agent/database/obfuscation_helpers' module NewRelic diff --git a/lib/new_relic/agent/instrumentation/rack/instrumentation.rb b/lib/new_relic/agent/instrumentation/rack/instrumentation.rb index f72bbb176f..3439275653 100644 --- a/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +++ b/lib/new_relic/agent/instrumentation/rack/instrumentation.rb @@ -11,6 +11,7 @@ class << builder_class attr_accessor :_nr_deferred_detection_ran end builder_class._nr_deferred_detection_ran = false + NewRelic::Control::SecurityInterface.instance.wait = true end def deferred_dependency_check @@ -19,6 +20,8 @@ def deferred_dependency_check NewRelic::Agent.logger.info('Doing deferred dependency-detection before Rack startup') DependencyDetection.detect! self.class._nr_deferred_detection_ran = true + NewRelic::Control::SecurityInterface.instance.wait = false + NewRelic::Control::SecurityInterface.instance.init_agent end def check_for_late_instrumentation(app) diff --git a/lib/new_relic/control.rb b/lib/new_relic/control.rb index fda4a2fac4..66d4c8ab29 100644 --- a/lib/new_relic/control.rb +++ b/lib/new_relic/control.rb @@ -8,7 +8,6 @@ require 'new_relic/language_support' require 'new_relic/helper' -require 'singleton' require 'erb' require 'socket' require 'net/https' @@ -18,6 +17,7 @@ require 'new_relic/control/instrumentation' require 'new_relic/control/class_methods' require 'new_relic/control/instance_methods' +require 'new_relic/control/security_interface' require 'new_relic/agent' require 'new_relic/delayed_job_injection' diff --git a/lib/new_relic/control/instance_methods.rb b/lib/new_relic/control/instance_methods.rb index ffba1f335d..eb04398277 100644 --- a/lib/new_relic/control/instance_methods.rb +++ b/lib/new_relic/control/instance_methods.rb @@ -73,6 +73,7 @@ def init_plugin(options = {}) init_config(options) NewRelic::Agent.agent = NewRelic::Agent::Agent.instance init_instrumentation + init_security_agent end def determine_env(options) @@ -116,7 +117,6 @@ def handle_invalid_security_settings def start_agent @started_in_env = self.env NewRelic::Agent.agent.start - init_security_agent end def app diff --git a/lib/new_relic/control/private_instance_methods.rb b/lib/new_relic/control/private_instance_methods.rb index 73771752d5..2cd45cc827 100644 --- a/lib/new_relic/control/private_instance_methods.rb +++ b/lib/new_relic/control/private_instance_methods.rb @@ -45,16 +45,7 @@ def init_instrumentation end def init_security_agent - if Agent.config[:'security.agent.enabled'] - Agent.logger.info('Invoking New Relic security module') - require 'newrelic_security' - else - Agent.logger.info('New Relic security module is disabled.') - end - rescue LoadError - Agent.logger.info('New Relic security agent not found - skipping') - rescue StandardError => exception - Agent.logger.error("Exception in New Relic security module loading: #{exception} #{exception.backtrace}") + SecurityInterface.instance.init_agent end end end diff --git a/lib/new_relic/control/security_interface.rb b/lib/new_relic/control/security_interface.rb new file mode 100644 index 0000000000..dac43257a6 --- /dev/null +++ b/lib/new_relic/control/security_interface.rb @@ -0,0 +1,36 @@ +require 'singleton' + +module NewRelic + class Control + class SecurityInterface + include Singleton + + attr_accessor :wait + + def agent_started? + @agent_started == true + end + + def waiting? + @wait == true + end + + def init_agent + return if agent_started? || waiting? + + if Agent.config[:'security.agent.enabled'] + Agent.logger.info('Invoking New Relic security module') + require 'newrelic_security' + + @agent_started = true + else + Agent.logger.info('New Relic security module is disabled.') + end + rescue LoadError + Agent.logger.info('New Relic security agent not found - skipping') + rescue StandardError => exception + Agent.logger.error("Exception in New Relic security module loading: #{exception} #{exception.backtrace}") + end + end + end +end diff --git a/test/multiverse/suites/sidekiq/sidekiq_server.rb b/test/multiverse/suites/sidekiq/sidekiq_server.rb index 7f33ac403e..371a37ac87 100644 --- a/test/multiverse/suites/sidekiq/sidekiq_server.rb +++ b/test/multiverse/suites/sidekiq/sidekiq_server.rb @@ -4,6 +4,7 @@ require 'sidekiq' require 'sidekiq/cli' +require 'singleton' require_relative '../../../helpers/docker' class SidekiqServer From 27fd636d3186791003355cc6f513494d31c36dd3 Mon Sep 17 00:00:00 2001 From: fallwith Date: Wed, 10 May 2023 20:56:53 -0700 Subject: [PATCH 006/109] security interface and gem dependency - update NewRelic::Control::Security source file with license header and frozen string literal magic comment - remove commented out dev dependency from gemspec, as Gemfile will be used --- lib/new_relic/control/security_interface.rb | 4 ++++ newrelic_rpm.gemspec | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/new_relic/control/security_interface.rb b/lib/new_relic/control/security_interface.rb index dac43257a6..855c615af5 100644 --- a/lib/new_relic/control/security_interface.rb +++ b/lib/new_relic/control/security_interface.rb @@ -1,3 +1,7 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + require 'singleton' module NewRelic diff --git a/newrelic_rpm.gemspec b/newrelic_rpm.gemspec index 32dbacd932..1de0447bc0 100644 --- a/newrelic_rpm.gemspec +++ b/newrelic_rpm.gemspec @@ -47,8 +47,6 @@ Gem::Specification.new do |s| s.require_paths = ['lib'] s.summary = 'New Relic Ruby Agent' -# s.add_dependency 'newrelic_security', '1.0.0-limited-preview' - s.add_development_dependency 'bundler' s.add_development_dependency 'feedjira', '3.2.1' unless ENV['CI'] || RUBY_VERSION < '2.5' # for Gabby s.add_development_dependency 'httparty' unless ENV['CI'] # for perf tests and Gabby From c9c7c06c4ff22c1713fe5396482df64606b61575 Mon Sep 17 00:00:00 2001 From: fallwith Date: Wed, 10 May 2023 21:14:33 -0700 Subject: [PATCH 007/109] gemspec: remove blank line remove blank line left over from testing to cut down on diff noise --- newrelic_rpm.gemspec | 1 - 1 file changed, 1 deletion(-) diff --git a/newrelic_rpm.gemspec b/newrelic_rpm.gemspec index 1de0447bc0..9cb2889314 100644 --- a/newrelic_rpm.gemspec +++ b/newrelic_rpm.gemspec @@ -46,7 +46,6 @@ Gem::Specification.new do |s| s.homepage = 'https://github.com/newrelic/rpm' s.require_paths = ['lib'] s.summary = 'New Relic Ruby Agent' - s.add_development_dependency 'bundler' s.add_development_dependency 'feedjira', '3.2.1' unless ENV['CI'] || RUBY_VERSION < '2.5' # for Gabby s.add_development_dependency 'httparty' unless ENV['CI'] # for perf tests and Gabby From 8caad2d2d40a4d6b02b9c198e34fc4e36815499b Mon Sep 17 00:00:00 2001 From: fallwith Date: Wed, 10 May 2023 21:39:17 -0700 Subject: [PATCH 008/109] SecurityInterface: Ruby <= 2.4 compatibility initialize the instance vars --- lib/new_relic/control/security_interface.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/new_relic/control/security_interface.rb b/lib/new_relic/control/security_interface.rb index 855c615af5..f50b229648 100644 --- a/lib/new_relic/control/security_interface.rb +++ b/lib/new_relic/control/security_interface.rb @@ -12,11 +12,11 @@ class SecurityInterface attr_accessor :wait def agent_started? - @agent_started == true + (@agent_started ||= false) == true end def waiting? - @wait == true + (@wait ||= false) == true end def init_agent From ca1ad1bee84ccb0369616c6e739e0225bf7050b9 Mon Sep 17 00:00:00 2001 From: fallwith Date: Wed, 31 May 2023 22:38:13 -0700 Subject: [PATCH 009/109] unit tests for SecurityInterface make sure the SecurityInterface singleton behaves as expected --- .../control/security_interface_test.rb | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 test/new_relic/control/security_interface_test.rb diff --git a/test/new_relic/control/security_interface_test.rb b/test/new_relic/control/security_interface_test.rb new file mode 100644 index 0000000000..2d06cc1587 --- /dev/null +++ b/test/new_relic/control/security_interface_test.rb @@ -0,0 +1,107 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +require_relative '../../test_helper' +require 'new_relic/control/security_interface' + +class NewRelic::Control::SecurityInterfaceTest < Minitest::Test + def setup + %i[@agent_started @wait].each do |variable| + instance = NewRelic::Control::SecurityInterface.instance + instance.remove_instance_variable(variable) if instance.instance_variable_defined?(variable) + end + end + + def test_initialization_short_circuits_when_the_security_agent_is_disabled + logger = MiniTest::Mock.new + with_config('security.agent.enabled' => false) do + NewRelic::Agent.stub :logger, logger do + logger.expect :info, nil, [/security module is disabled/] + + NewRelic::Control::SecurityInterface.instance.init_agent + end + + refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? + end + logger.verify + end + + def test_initialization_short_circuits_if_the_agent_has_already_been_started + reached = false + with_config('security.agent.enabled' => true) do + NewRelic::Agent.stub :config, -> { reached = true } do + NewRelic::Control::SecurityInterface.instance.instance_variable_set(:@agent_started, true) + NewRelic::Control::SecurityInterface.instance.init_agent + end + end + + refute reached, 'Expected init_agent to short circuit but it reached code within the method instead!' + end + + def test_initialization_short_circuits_if_the_agent_has_been_told_to_wait + reached = false + with_config('security.agent.enabled' => true) do + NewRelic::Agent.stub :config, -> { reached = true } do + NewRelic::Control::SecurityInterface.instance.instance_variable_set(:@wait, true) + NewRelic::Control::SecurityInterface.instance.init_agent + end + end + + refute reached, 'Expected init_agent to short circuit but it reached code within the method instead!' + end + + def test_initialization_requires_the_security_agent + required = false + logger = MiniTest::Mock.new + with_config('security.agent.enabled' => true) do + NewRelic::Agent.stub :logger, logger do + logger.expect :info, nil, [/Invoking New Relic security/] + + NewRelic::Control::SecurityInterface.instance.stub :require, proc { |_gem| required = true }, %w[newrelic_security] do + NewRelic::Control::SecurityInterface.instance.init_agent + end + end + end + logger.verify + + assert required, 'Expected init_agent to perform a require statement' + assert_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? + end + + def test_initialization_anticipates_a_load_error + logger = MiniTest::Mock.new + with_config('security.agent.enabled' => true) do + NewRelic::Agent.stub :logger, logger do + logger.expect :info, nil, [/Invoking New Relic security/] + logger.expect :info, nil, [/security agent not found/] + + error_proc = proc { |_gem| raise LoadError.new } + NewRelic::Control::SecurityInterface.instance.stub :require, error_proc, %w[newrelic_security] do + NewRelic::Control::SecurityInterface.instance.init_agent + end + end + logger.verify + + refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? + end + end + + def test_initialization_handles_errors + logger = MiniTest::Mock.new + with_config('security.agent.enabled' => true) do + NewRelic::Agent.stub :logger, logger do + logger.expect :info, nil, [/Invoking New Relic security/] + logger.expect :error, nil, [/Exception in New Relic security module loading/] + + error_proc = proc { |_gem| raise StandardError } + NewRelic::Control::SecurityInterface.instance.stub :require, error_proc, %w[newrelic_security] do + NewRelic::Control::SecurityInterface.instance.init_agent + end + end + end + logger.verify + + refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? + end +end From 96fa2148079208b62e489cb7bf83ba53bf05003e Mon Sep 17 00:00:00 2001 From: fallwith Date: Wed, 31 May 2023 23:05:35 -0700 Subject: [PATCH 010/109] security interface tests: skip MiniTest 4 when relying on the 3 argument version of `stub`, make sure it's available --- test/new_relic/control/security_interface_test.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/new_relic/control/security_interface_test.rb b/test/new_relic/control/security_interface_test.rb index 2d06cc1587..32df241f89 100644 --- a/test/new_relic/control/security_interface_test.rb +++ b/test/new_relic/control/security_interface_test.rb @@ -52,6 +52,8 @@ def test_initialization_short_circuits_if_the_agent_has_been_told_to_wait end def test_initialization_requires_the_security_agent + skip_unless_minitest5_or_above + required = false logger = MiniTest::Mock.new with_config('security.agent.enabled' => true) do @@ -70,6 +72,8 @@ def test_initialization_requires_the_security_agent end def test_initialization_anticipates_a_load_error + skip_unless_minitest5_or_above + logger = MiniTest::Mock.new with_config('security.agent.enabled' => true) do NewRelic::Agent.stub :logger, logger do @@ -88,6 +92,8 @@ def test_initialization_anticipates_a_load_error end def test_initialization_handles_errors + skip_unless_minitest5_or_above + logger = MiniTest::Mock.new with_config('security.agent.enabled' => true) do NewRelic::Agent.stub :logger, logger do From 561b92a912a0d91662b7ecf87ac5c10646d0ecba Mon Sep 17 00:00:00 2001 From: James Bunch Date: Thu, 1 Jun 2023 19:03:15 -0700 Subject: [PATCH 011/109] Update lib/new_relic/agent/configuration/default_source.rb Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- lib/new_relic/agent/configuration/default_source.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index 95cd8285b1..faa3036e63 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -2228,7 +2228,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :public => true, :type => Boolean, :allowed_from_server => false, - :description => 'If `true`, the security agent is activated' + :description => 'If `true`, the security agent is started' }, :'security.mode' => { :default => 'IAST', From dca3f037f9b383080f77808cf73e85e9984e61b1 Mon Sep 17 00:00:00 2001 From: James Bunch Date: Thu, 1 Jun 2023 19:04:28 -0700 Subject: [PATCH 012/109] Update lib/new_relic/agent/configuration/default_source.rb Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- lib/new_relic/agent/configuration/default_source.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index faa3036e63..cdda868472 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -2245,7 +2245,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :public => true, :type => String, :allowed_from_server => true, - :description => 'Defines the end point URL for posting security related data', + :description => 'Defines the endpoint URL for posting security-related data', :dynamic_name => true }, :'security.detection.rci.enabled' => { From 042017fdcaf5af182a5fa60f922c487c24695761 Mon Sep 17 00:00:00 2001 From: James Bunch Date: Thu, 1 Jun 2023 19:08:43 -0700 Subject: [PATCH 013/109] Update lib/new_relic/agent/configuration/default_source.rb Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- lib/new_relic/agent/configuration/default_source.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index cdda868472..3740e5b959 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -2262,7 +2262,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :public => true, :type => Boolean, :allowed_from_server => false, - :description => 'If `true`, enables rxss detection' + :description => 'If `true`, enables RXSS detection' }, :'security.detection.deserialization.enabled' => { :default => true, From 5ace3bfe87a26b852d083c613c8b744f88f2cc50 Mon Sep 17 00:00:00 2001 From: James Bunch Date: Fri, 2 Jun 2023 10:50:57 -0700 Subject: [PATCH 014/109] Update lib/new_relic/agent/configuration/default_source.rb Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- lib/new_relic/agent/configuration/default_source.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index 3740e5b959..e5b3dca6d1 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -2278,7 +2278,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Integer, :external => true, :allowed_from_server => false, - :description => 'The port the application listens on (Mandatory for Passenger, for other servers detected by default)' + :description => 'The port the application is listening on. This setting is mandatory for Passenger servers. Other servers should be detected by default.' } }.freeze end From 0e7bc167762c14b1c25730a376920a22a06bc77c Mon Sep 17 00:00:00 2001 From: fallwith Date: Fri, 2 Jun 2023 14:58:34 -0700 Subject: [PATCH 015/109] more security agent config descriptions add a security agent note, update descriptions further --- .../agent/configuration/default_source.rb | 8 ++--- newrelic.yml | 33 +++++++++++++++---- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index e5b3dca6d1..182186030d 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -2220,7 +2220,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :public => true, :type => Boolean, :allowed_from_server => false, - :description => 'If `true`, the security agent is loaded' + :description => "If `true`, the security agent is loaded (a Ruby 'require' is performed)" }, :'security.enabled' => { :default => false, @@ -2228,7 +2228,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :public => true, :type => Boolean, :allowed_from_server => false, - :description => 'If `true`, the security agent is started' + :description => 'If `true`, the security agent is started (the agent runs in its event loop)' }, :'security.mode' => { :default => 'IAST', @@ -2254,7 +2254,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :public => true, :type => Boolean, :allowed_from_server => false, - :description => 'If `true`, enables rci detection' + :description => 'If `true`, enables RCI detection' }, :'security.detection.rxss.enabled' => { :default => true, @@ -2278,7 +2278,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Integer, :external => true, :allowed_from_server => false, - :description => 'The port the application is listening on. This setting is mandatory for Passenger servers. Other servers should be detected by default.' + :description => 'The port the application listens on (mandatory for Passenger, for other servers detected by default)' } }.freeze end diff --git a/newrelic.yml b/newrelic.yml index 459bab6518..dcf8a2050f 100644 --- a/newrelic.yml +++ b/newrelic.yml @@ -692,12 +692,33 @@ common: &default_settings # If true, the agent automatically detects that it is running in a Pivotal Cloud Foundry environment. # utilization.detect_pcf: true + # # BEGIN security agent - - # If true, the security agent is loaded + # + # NOTE: At this time, the security agent is intended for use only within + # a dedicated security testing environment with data that can tolerate + # modification or deletion. The security agent is available as a + # separate Ruby gem, newrelic_security. It is recommended that this + # separate gem only be introduced to a security testing environment + # by leveraging Bundler grouping like so: + # + # # Gemfile + # gem 'newrelic_rpm' # New Relic APM observability agent + # gem 'newrelic-infinite_tracing' # New Relic Infinite Tracing + # + # group :security do + # gem 'newrelic_security' # New Relic security agent + # end + # + # NOTE: All "security.*" configuration parameters are related only to the + # security agent, and all other configuration parameters that may + # have "security" in the name some where are related to the APM agent. + # + + # If true, the security agent is loaded (a Ruby 'require' is performed) # security.agent.enabled: false - # If true, the security agent is activated + # If true, the security agent is started (the agent runs in its event loop) # security.enabled: false # The mode for the security agent to operate in. Currently only 'IAST' is supported @@ -706,16 +727,16 @@ common: &default_settings # Defines the end point URL for posting security related data # security.validator_service_url: wss://csec.nr-data.net - # If `true`, enables rci detection + # If `true`, enables RCI detection # security.detection.rci.enabled: true - # If `true`, enables rxss detection + # If `true`, enables RXSS detection # security.detection.rxss.enabled: true # If `true`, enables deserialization detection # security.detection.deserialization.enabled: true - # The port the application listens on (Mandatory for Passenger, for other servers detected by default) + # The port the application listens on (mandatory for Passenger, for other servers detected by default) # security.applicationinfo.port: -1 # END security agent From 075f2ae59e1c130f7a1cfebe80affe8caddb469c Mon Sep 17 00:00:00 2001 From: fallwith Date: Fri, 2 Jun 2023 15:02:00 -0700 Subject: [PATCH 016/109] still more security agent config reconcile .rb and .yml changes from the PR --- lib/new_relic/agent/configuration/default_source.rb | 2 +- newrelic.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index 182186030d..a0fd0207e6 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -2278,7 +2278,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Integer, :external => true, :allowed_from_server => false, - :description => 'The port the application listens on (mandatory for Passenger, for other servers detected by default)' + :description => 'The port the application is listening on. This setting is mandatory for Passenger servers. Other servers should be detected by default.' } }.freeze end diff --git a/newrelic.yml b/newrelic.yml index dcf8a2050f..ad7029473b 100644 --- a/newrelic.yml +++ b/newrelic.yml @@ -721,10 +721,10 @@ common: &default_settings # If true, the security agent is started (the agent runs in its event loop) # security.enabled: false - # The mode for the security agent to operate in. Currently only 'IAST' is supported + # Defines the The mode for the security agent to operate in. Currently only 'IAST' is supported # security.mode: IAST - # Defines the end point URL for posting security related data + # Defines the endpoint URL for posting security related data # security.validator_service_url: wss://csec.nr-data.net # If `true`, enables RCI detection @@ -736,7 +736,7 @@ common: &default_settings # If `true`, enables deserialization detection # security.detection.deserialization.enabled: true - # The port the application listens on (mandatory for Passenger, for other servers detected by default) + # The port the application is listening on. This setting is mandatory for Passenger servers. Other servers should be detected by default. # security.applicationinfo.port: -1 # END security agent From 91b4beb907df35d5dedd4ae5fe16776d3daed06f Mon Sep 17 00:00:00 2001 From: fallwith Date: Fri, 2 Jun 2023 17:10:33 -0700 Subject: [PATCH 017/109] the The typo fix --- newrelic.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/newrelic.yml b/newrelic.yml index ad7029473b..e5c9e6e9a4 100644 --- a/newrelic.yml +++ b/newrelic.yml @@ -721,7 +721,7 @@ common: &default_settings # If true, the security agent is started (the agent runs in its event loop) # security.enabled: false - # Defines the The mode for the security agent to operate in. Currently only 'IAST' is supported + # Defines the mode for the security agent to operate in. Currently only 'IAST' is supported # security.mode: IAST # Defines the endpoint URL for posting security related data From 6567ddcc3ecd3dd634e2c93eb8bb130e2d0c7dd2 Mon Sep 17 00:00:00 2001 From: prateek-ap Date: Mon, 5 Jun 2023 11:46:40 +0530 Subject: [PATCH 018/109] updated security config: application_info --- lib/new_relic/agent/configuration/default_source.rb | 4 ++-- newrelic.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index a0fd0207e6..22834cb940 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -2272,8 +2272,8 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :allowed_from_server => false, :description => 'If `true`, enables deserialization detection' }, - :'security.applicationinfo.port' => { - :default => -1, + :'security.application_info.port' => { + :default => nil, :public => true, :type => Integer, :external => true, diff --git a/newrelic.yml b/newrelic.yml index e5c9e6e9a4..726ddb3b06 100644 --- a/newrelic.yml +++ b/newrelic.yml @@ -737,7 +737,7 @@ common: &default_settings # security.detection.deserialization.enabled: true # The port the application is listening on. This setting is mandatory for Passenger servers. Other servers should be detected by default. - # security.applicationinfo.port: -1 + # security.application_info.port: nil # END security agent From b0a8c86c6a6dfc66081510b4e692cb066fd39386 Mon Sep 17 00:00:00 2001 From: prateek-ap Date: Tue, 6 Jun 2023 11:32:11 +0530 Subject: [PATCH 019/109] set allow_nil to true for security.application_info.port --- lib/new_relic/agent/configuration/default_source.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index 22834cb940..4758b43ddf 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -2274,6 +2274,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'security.application_info.port' => { :default => nil, + :allow_nil => true, :public => true, :type => Integer, :external => true, From 54970dc25377bf6786a965acd3ef8c0f5e9ecf50 Mon Sep 17 00:00:00 2001 From: prateek-ap Date: Thu, 8 Jun 2023 15:39:38 +0530 Subject: [PATCH 020/109] add handling security disable of high security enabled --- lib/new_relic/control/security_interface.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/new_relic/control/security_interface.rb b/lib/new_relic/control/security_interface.rb index f50b229648..045017a1c6 100644 --- a/lib/new_relic/control/security_interface.rb +++ b/lib/new_relic/control/security_interface.rb @@ -22,13 +22,13 @@ def waiting? def init_agent return if agent_started? || waiting? - if Agent.config[:'security.agent.enabled'] + if Agent.config[:'security.agent.enabled'] && Agent.config[:'security.enabled'] && !Agent.config[:high_security] Agent.logger.info('Invoking New Relic security module') require 'newrelic_security' @agent_started = true else - Agent.logger.info('New Relic security module is disabled.') + Agent.logger.info('New Relic Security is completely disabled by one of the user provided config `security.agent.enabled`, `security.enabled`, or `high_security`. Not loading security capabilities.') end rescue LoadError Agent.logger.info('New Relic security agent not found - skipping') From d5dda8ad43ea0ccef507187b86b9ffe630cf037b Mon Sep 17 00:00:00 2001 From: prateek-ap Date: Thu, 8 Jun 2023 17:48:12 +0530 Subject: [PATCH 021/109] update security_interface_test for high_security config changes --- .../control/security_interface_test.rb | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/test/new_relic/control/security_interface_test.rb b/test/new_relic/control/security_interface_test.rb index 32df241f89..1c8c2c6cfb 100644 --- a/test/new_relic/control/security_interface_test.rb +++ b/test/new_relic/control/security_interface_test.rb @@ -17,7 +17,21 @@ def test_initialization_short_circuits_when_the_security_agent_is_disabled logger = MiniTest::Mock.new with_config('security.agent.enabled' => false) do NewRelic::Agent.stub :logger, logger do - logger.expect :info, nil, [/security module is disabled/] + logger.expect :info, nil, [/Security is completely disabled/] + + NewRelic::Control::SecurityInterface.instance.init_agent + end + + refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? + end + logger.verify + end + + def test_initialization_short_circuits_when_the_security_is_disabled + logger = MiniTest::Mock.new + with_config('security.enabled' => false) do + NewRelic::Agent.stub :logger, logger do + logger.expect :info, nil, [/Security is completely disabled/] NewRelic::Control::SecurityInterface.instance.init_agent end @@ -29,7 +43,7 @@ def test_initialization_short_circuits_when_the_security_agent_is_disabled def test_initialization_short_circuits_if_the_agent_has_already_been_started reached = false - with_config('security.agent.enabled' => true) do + with_config('security.agent.enabled' => true, 'security.enabled' => true) do NewRelic::Agent.stub :config, -> { reached = true } do NewRelic::Control::SecurityInterface.instance.instance_variable_set(:@agent_started, true) NewRelic::Control::SecurityInterface.instance.init_agent @@ -41,7 +55,7 @@ def test_initialization_short_circuits_if_the_agent_has_already_been_started def test_initialization_short_circuits_if_the_agent_has_been_told_to_wait reached = false - with_config('security.agent.enabled' => true) do + with_config('security.agent.enabled' => true, 'security.enabled' => true) do NewRelic::Agent.stub :config, -> { reached = true } do NewRelic::Control::SecurityInterface.instance.instance_variable_set(:@wait, true) NewRelic::Control::SecurityInterface.instance.init_agent @@ -56,7 +70,7 @@ def test_initialization_requires_the_security_agent required = false logger = MiniTest::Mock.new - with_config('security.agent.enabled' => true) do + with_config('security.agent.enabled' => true, 'security.enabled' => true) do NewRelic::Agent.stub :logger, logger do logger.expect :info, nil, [/Invoking New Relic security/] @@ -75,7 +89,7 @@ def test_initialization_anticipates_a_load_error skip_unless_minitest5_or_above logger = MiniTest::Mock.new - with_config('security.agent.enabled' => true) do + with_config('security.agent.enabled' => true, 'security.enabled' => true) do NewRelic::Agent.stub :logger, logger do logger.expect :info, nil, [/Invoking New Relic security/] logger.expect :info, nil, [/security agent not found/] @@ -95,7 +109,7 @@ def test_initialization_handles_errors skip_unless_minitest5_or_above logger = MiniTest::Mock.new - with_config('security.agent.enabled' => true) do + with_config('security.agent.enabled' => true, 'security.enabled' => true) do NewRelic::Agent.stub :logger, logger do logger.expect :info, nil, [/Invoking New Relic security/] logger.expect :error, nil, [/Exception in New Relic security module loading/] From 120d6152f4f2b6820a7e201f91b14b02521c2dde Mon Sep 17 00:00:00 2001 From: fallwith Date: Thu, 8 Jun 2023 10:18:31 -0700 Subject: [PATCH 022/109] security agent tests: updates to 3 param checks make it abundantly clear which combinations of the 3 options will disable the security agent --- .../control/security_interface_test.rb | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/test/new_relic/control/security_interface_test.rb b/test/new_relic/control/security_interface_test.rb index 1c8c2c6cfb..79d63efade 100644 --- a/test/new_relic/control/security_interface_test.rb +++ b/test/new_relic/control/security_interface_test.rb @@ -15,7 +15,7 @@ def setup def test_initialization_short_circuits_when_the_security_agent_is_disabled logger = MiniTest::Mock.new - with_config('security.agent.enabled' => false) do + with_config('security.agent.enabled' => false, 'security.enabled' => true, 'high_security' => false) do NewRelic::Agent.stub :logger, logger do logger.expect :info, nil, [/Security is completely disabled/] @@ -29,7 +29,21 @@ def test_initialization_short_circuits_when_the_security_agent_is_disabled def test_initialization_short_circuits_when_the_security_is_disabled logger = MiniTest::Mock.new - with_config('security.enabled' => false) do + with_config('security.agent.enabled' => true, 'security.enabled' => false, 'high_security' => false) do + NewRelic::Agent.stub :logger, logger do + logger.expect :info, nil, [/Security is completely disabled/] + + NewRelic::Control::SecurityInterface.instance.init_agent + end + + refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? + end + logger.verify + end + + def test_initialization_short_circuits_when_high_security_mode_is_enabled + logger = MiniTest::Mock.new + with_config('security.agent.enabled' => true, 'security.enabled' => true, 'high_security' => true) do NewRelic::Agent.stub :logger, logger do logger.expect :info, nil, [/Security is completely disabled/] From 36b3bc47f432d326d1711c47b50d141ebd7ebfdf Mon Sep 17 00:00:00 2001 From: fallwith Date: Thu, 8 Jun 2023 10:50:15 -0700 Subject: [PATCH 023/109] CI: upgrade to setup-ruby v1.151.0 upgrade our GHA workflows to use setup-ruby v1.151.0 so that we can install JRuby 9.4.3.0 --- .github/workflows/ci.yml | 10 +++++----- .github/workflows/ci_cron.yml | 8 ++++---- .github/workflows/ci_jruby.yml | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d584281db6..a473673b3c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: - name: Configure git run: 'git config --global init.defaultBranch main' - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # tag v3.5.0 - - uses: ruby/setup-ruby@7d546f4868fb108ed378764d873683f920672ae2 # tag v1.149.0 + - uses: ruby/setup-ruby@bc1dd263b68cb5626dbb55d5c89777d79372c484 # tag v1.151.0 with: ruby-version: '3.2' - run: bundle @@ -44,7 +44,7 @@ jobs: run: sudo apt-get update; sudo apt-get install -y --no-install-recommends libcurl4-nss-dev libsasl2-dev libxslt1-dev - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@7d546f4868fb108ed378764d873683f920672ae2 # tag v1.149.0 + uses: ruby/setup-ruby@bc1dd263b68cb5626dbb55d5c89777d79372c484 # tag v1.151.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -197,7 +197,7 @@ jobs: run: sudo apt-get update; sudo apt-get install -y --no-install-recommends libcurl4-nss-dev libsasl2-dev libxslt1-dev - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@7d546f4868fb108ed378764d873683f920672ae2 # tag v1.149.0 + uses: ruby/setup-ruby@bc1dd263b68cb5626dbb55d5c89777d79372c484 # tag v1.151.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -289,7 +289,7 @@ jobs: - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # tag v3.5.0 - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@7d546f4868fb108ed378764d873683f920672ae2 # tag v1.149.0 + uses: ruby/setup-ruby@bc1dd263b68cb5626dbb55d5c89777d79372c484 # tag v1.151.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -328,7 +328,7 @@ jobs: - name: Configure git run: 'git config --global init.defaultBranch main' - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # tag v3.5.0 - - uses: ruby/setup-ruby@7d546f4868fb108ed378764d873683f920672ae2 # tag v1.149.0 + - uses: ruby/setup-ruby@bc1dd263b68cb5626dbb55d5c89777d79372c484 # tag v1.151.0 with: ruby-version: '3.1' - run: bundle diff --git a/.github/workflows/ci_cron.yml b/.github/workflows/ci_cron.yml index f8e65ff723..09798f22a6 100644 --- a/.github/workflows/ci_cron.yml +++ b/.github/workflows/ci_cron.yml @@ -16,7 +16,7 @@ jobs: - name: Configure git run: 'git config --global init.defaultBranch main' - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # tag v3.5.0 - - uses: ruby/setup-ruby@7d546f4868fb108ed378764d873683f920672ae2 # tag v1.149.0 + - uses: ruby/setup-ruby@bc1dd263b68cb5626dbb55d5c89777d79372c484 # tag v1.151.0 with: ruby-version: '3.2' - run: bundle @@ -50,7 +50,7 @@ jobs: run: sudo apt-get update; sudo apt-get install -y --no-install-recommends libcurl4-nss-dev libsasl2-dev libxslt1-dev - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@7d546f4868fb108ed378764d873683f920672ae2 # tag v1.149.0 + uses: ruby/setup-ruby@bc1dd263b68cb5626dbb55d5c89777d79372c484 # tag v1.151.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -212,7 +212,7 @@ jobs: run: sudo apt-get update; sudo apt-get install -y --no-install-recommends libcurl4-nss-dev libsasl2-dev libxslt1-dev - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@7d546f4868fb108ed378764d873683f920672ae2 # tag v1.149.0 + uses: ruby/setup-ruby@bc1dd263b68cb5626dbb55d5c89777d79372c484 # tag v1.151.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -284,7 +284,7 @@ jobs: - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # tag v3.5.0 - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@7d546f4868fb108ed378764d873683f920672ae2 # tag v1.149.0 + uses: ruby/setup-ruby@bc1dd263b68cb5626dbb55d5c89777d79372c484 # tag v1.151.0 with: ruby-version: ${{ matrix.ruby-version }} diff --git a/.github/workflows/ci_jruby.yml b/.github/workflows/ci_jruby.yml index 69bf460489..69aaca468f 100644 --- a/.github/workflows/ci_jruby.yml +++ b/.github/workflows/ci_jruby.yml @@ -24,7 +24,7 @@ jobs: - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # tag v3.5.0 - name: Install Ruby jruby-9.4.2.0 - uses: ruby/setup-ruby@7d546f4868fb108ed378764d873683f920672ae2 # tag v1.149.0 + uses: ruby/setup-ruby@bc1dd263b68cb5626dbb55d5c89777d79372c484 # tag v1.151.0 with: ruby-version: jruby-9.4.2.0 @@ -123,7 +123,7 @@ jobs: uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # tag v3.5.0 - name: Install JRuby - uses: ruby/setup-ruby@7d546f4868fb108ed378764d873683f920672ae2 # tag v1.149.0 + uses: ruby/setup-ruby@bc1dd263b68cb5626dbb55d5c89777d79372c484 # tag v1.151.0 with: ruby-version: jruby-9.4.2.0 From d9d66b1be11803412ada84875d1a831c7ff8954e Mon Sep 17 00:00:00 2001 From: hramadan Date: Tue, 24 Oct 2023 11:16:55 -0700 Subject: [PATCH 024/109] Add supportability enabed/disabled metric --- lib/new_relic/control/security_interface.rb | 14 ++++++++++++++ test/new_relic/control/security_interface_test.rb | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/lib/new_relic/control/security_interface.rb b/lib/new_relic/control/security_interface.rb index 045017a1c6..6f412fcdce 100644 --- a/lib/new_relic/control/security_interface.rb +++ b/lib/new_relic/control/security_interface.rb @@ -11,6 +11,8 @@ class SecurityInterface attr_accessor :wait + SUPPORTABILITY_METRIC = 'Supportability/Ruby/SecurityAgent/Enabled/' + def agent_started? (@agent_started ||= false) == true end @@ -24,11 +26,13 @@ def init_agent if Agent.config[:'security.agent.enabled'] && Agent.config[:'security.enabled'] && !Agent.config[:high_security] Agent.logger.info('Invoking New Relic security module') + NewRelic::Agent.record_metric_once(SUPPORTABILITY_METRIC + 'enabled') require 'newrelic_security' @agent_started = true else Agent.logger.info('New Relic Security is completely disabled by one of the user provided config `security.agent.enabled`, `security.enabled`, or `high_security`. Not loading security capabilities.') + NewRelic::Agent.record_metric_once(SUPPORTABILITY_METRIC + 'disabled') end rescue LoadError Agent.logger.info('New Relic security agent not found - skipping') @@ -38,3 +42,13 @@ def init_agent end end end + +# __END__ + +# SUPPORTABILITY_METRIC = 'Supportability/Ruby/SecurityAgent/Agent/Enabled/{enabled|disabled}' + +# NewRelic::Agent.record_metric_once(SUPPORTABILITY_METRIC) + +# record_metric(metric_name, value) + + diff --git a/test/new_relic/control/security_interface_test.rb b/test/new_relic/control/security_interface_test.rb index 79d63efade..306b97a9d8 100644 --- a/test/new_relic/control/security_interface_test.rb +++ b/test/new_relic/control/security_interface_test.rb @@ -23,6 +23,7 @@ def test_initialization_short_circuits_when_the_security_agent_is_disabled end refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/disabled' end logger.verify end @@ -37,6 +38,7 @@ def test_initialization_short_circuits_when_the_security_is_disabled end refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/disabled' end logger.verify end @@ -51,6 +53,7 @@ def test_initialization_short_circuits_when_high_security_mode_is_enabled end refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/disabled' end logger.verify end @@ -65,6 +68,7 @@ def test_initialization_short_circuits_if_the_agent_has_already_been_started end refute reached, 'Expected init_agent to short circuit but it reached code within the method instead!' + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/disabled' end def test_initialization_short_circuits_if_the_agent_has_been_told_to_wait @@ -77,6 +81,7 @@ def test_initialization_short_circuits_if_the_agent_has_been_told_to_wait end refute reached, 'Expected init_agent to short circuit but it reached code within the method instead!' + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/disabled' end def test_initialization_requires_the_security_agent @@ -97,6 +102,7 @@ def test_initialization_requires_the_security_agent assert required, 'Expected init_agent to perform a require statement' assert_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' end def test_initialization_anticipates_a_load_error @@ -116,6 +122,7 @@ def test_initialization_anticipates_a_load_error logger.verify refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' end end @@ -137,5 +144,6 @@ def test_initialization_handles_errors logger.verify refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' end end From 944d421d84ea6be674fae2d48a9d01c29c158ded Mon Sep 17 00:00:00 2001 From: hramadan Date: Tue, 24 Oct 2023 11:18:19 -0700 Subject: [PATCH 025/109] Remove scratch work --- lib/new_relic/control/security_interface.rb | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/new_relic/control/security_interface.rb b/lib/new_relic/control/security_interface.rb index 6f412fcdce..fca406e385 100644 --- a/lib/new_relic/control/security_interface.rb +++ b/lib/new_relic/control/security_interface.rb @@ -42,13 +42,3 @@ def init_agent end end end - -# __END__ - -# SUPPORTABILITY_METRIC = 'Supportability/Ruby/SecurityAgent/Agent/Enabled/{enabled|disabled}' - -# NewRelic::Agent.record_metric_once(SUPPORTABILITY_METRIC) - -# record_metric(metric_name, value) - - From 5546674de8cff7fd7f9282c02dfe47cc1e3c7c99 Mon Sep 17 00:00:00 2001 From: hramadan Date: Tue, 24 Oct 2023 14:04:15 -0700 Subject: [PATCH 026/109] 2 supportability metrics --- lib/new_relic/control/security_interface.rb | 22 ++++++++++++++++--- .../control/security_interface_test.rb | 16 ++++++++++---- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/lib/new_relic/control/security_interface.rb b/lib/new_relic/control/security_interface.rb index fca406e385..630a81ae82 100644 --- a/lib/new_relic/control/security_interface.rb +++ b/lib/new_relic/control/security_interface.rb @@ -11,7 +11,10 @@ class SecurityInterface attr_accessor :wait - SUPPORTABILITY_METRIC = 'Supportability/Ruby/SecurityAgent/Enabled/' + SUPPORTABILITY_PREFIX_SECURITY = 'Supportability/Ruby/SecurityAgent/Enabled/' + SUPPORTABILITY_PREFIX_SECURITY_AGENT = 'Supportability/Ruby/SecurityAgent/Agent/Enabled/' + ENABLED = 'enabled' + DISABLED = 'disabled' def agent_started? (@agent_started ||= false) == true @@ -24,21 +27,34 @@ def waiting? def init_agent return if agent_started? || waiting? + record_supportability_metrics + if Agent.config[:'security.agent.enabled'] && Agent.config[:'security.enabled'] && !Agent.config[:high_security] Agent.logger.info('Invoking New Relic security module') - NewRelic::Agent.record_metric_once(SUPPORTABILITY_METRIC + 'enabled') require 'newrelic_security' @agent_started = true else Agent.logger.info('New Relic Security is completely disabled by one of the user provided config `security.agent.enabled`, `security.enabled`, or `high_security`. Not loading security capabilities.') - NewRelic::Agent.record_metric_once(SUPPORTABILITY_METRIC + 'disabled') end rescue LoadError Agent.logger.info('New Relic security agent not found - skipping') rescue StandardError => exception Agent.logger.error("Exception in New Relic security module loading: #{exception} #{exception.backtrace}") end + + def record_supportability_metrics + Agent.config[:'security.enabled'] ? security_metric(ENABLED) : security_metric(DISABLED) + Agent.config[:'security.agent.enabled'] ? security_agent_metric(ENABLED) : security_agent_metric(DISABLED) + end + + def security_metric(setting) + NewRelic::Agent.record_metric_once(SUPPORTABILITY_PREFIX_SECURITY + setting) + end + + def security_agent_metric(setting) + NewRelic::Agent.record_metric_once(SUPPORTABILITY_PREFIX_SECURITY_AGENT + setting) + end end end end diff --git a/test/new_relic/control/security_interface_test.rb b/test/new_relic/control/security_interface_test.rb index 306b97a9d8..9892c69394 100644 --- a/test/new_relic/control/security_interface_test.rb +++ b/test/new_relic/control/security_interface_test.rb @@ -23,7 +23,8 @@ def test_initialization_short_circuits_when_the_security_agent_is_disabled end refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/disabled' + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Agent/Enabled/disabled' + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' end logger.verify end @@ -38,6 +39,7 @@ def test_initialization_short_circuits_when_the_security_is_disabled end refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Agent/Enabled/enabled' assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/disabled' end logger.verify @@ -53,7 +55,8 @@ def test_initialization_short_circuits_when_high_security_mode_is_enabled end refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/disabled' + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Agent/Enabled/enabled' + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' end logger.verify end @@ -68,7 +71,8 @@ def test_initialization_short_circuits_if_the_agent_has_already_been_started end refute reached, 'Expected init_agent to short circuit but it reached code within the method instead!' - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/disabled' + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Agent/Enabled/enabled' + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' end def test_initialization_short_circuits_if_the_agent_has_been_told_to_wait @@ -81,7 +85,8 @@ def test_initialization_short_circuits_if_the_agent_has_been_told_to_wait end refute reached, 'Expected init_agent to short circuit but it reached code within the method instead!' - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/disabled' + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Agent/Enabled/enabled' + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' end def test_initialization_requires_the_security_agent @@ -102,6 +107,7 @@ def test_initialization_requires_the_security_agent assert required, 'Expected init_agent to perform a require statement' assert_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Agent/Enabled/enabled' assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' end @@ -122,6 +128,7 @@ def test_initialization_anticipates_a_load_error logger.verify refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Agent/Enabled/enabled' assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' end end @@ -144,6 +151,7 @@ def test_initialization_handles_errors logger.verify refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Agent/Enabled/enabled' assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' end end From 92f3b0f85f9f89c1288089ed9151792020ab380c Mon Sep 17 00:00:00 2001 From: hramadan Date: Tue, 24 Oct 2023 14:27:42 -0700 Subject: [PATCH 027/109] Fix test --- test/new_relic/control/security_interface_test.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/new_relic/control/security_interface_test.rb b/test/new_relic/control/security_interface_test.rb index 9892c69394..dfa5d6d15a 100644 --- a/test/new_relic/control/security_interface_test.rb +++ b/test/new_relic/control/security_interface_test.rb @@ -71,8 +71,6 @@ def test_initialization_short_circuits_if_the_agent_has_already_been_started end refute reached, 'Expected init_agent to short circuit but it reached code within the method instead!' - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Agent/Enabled/enabled' - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' end def test_initialization_short_circuits_if_the_agent_has_been_told_to_wait @@ -85,8 +83,6 @@ def test_initialization_short_circuits_if_the_agent_has_been_told_to_wait end refute reached, 'Expected init_agent to short circuit but it reached code within the method instead!' - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Agent/Enabled/enabled' - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' end def test_initialization_requires_the_security_agent From 6d7b4114c694ac415a7e84c820362c9193f70648 Mon Sep 17 00:00:00 2001 From: hramadan Date: Wed, 25 Oct 2023 11:39:04 -0700 Subject: [PATCH 028/109] Reset supportability metrics --- test/new_relic/control/security_interface_test.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/new_relic/control/security_interface_test.rb b/test/new_relic/control/security_interface_test.rb index dfa5d6d15a..5e0aaf7162 100644 --- a/test/new_relic/control/security_interface_test.rb +++ b/test/new_relic/control/security_interface_test.rb @@ -13,7 +13,15 @@ def setup end end + # For testing purposes, clear out the supportability metrics that have already been recorded. + def reset_supportability_metrics + NewRelic::Agent.shutdown + NewRelic::Agent.instance_variable_get(:@metrics_already_recorded)&.clear + end + def test_initialization_short_circuits_when_the_security_agent_is_disabled + reset_supportability_metrics + logger = MiniTest::Mock.new with_config('security.agent.enabled' => false, 'security.enabled' => true, 'high_security' => false) do NewRelic::Agent.stub :logger, logger do @@ -30,6 +38,8 @@ def test_initialization_short_circuits_when_the_security_agent_is_disabled end def test_initialization_short_circuits_when_the_security_is_disabled + reset_supportability_metrics + logger = MiniTest::Mock.new with_config('security.agent.enabled' => true, 'security.enabled' => false, 'high_security' => false) do NewRelic::Agent.stub :logger, logger do From da5b18cabce2aa041e459e8bb7d4f7322437ef94 Mon Sep 17 00:00:00 2001 From: hramadan Date: Wed, 25 Oct 2023 15:43:58 -0700 Subject: [PATCH 029/109] Add supportability metrics enabled method --- .../control/security_interface_test.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/new_relic/control/security_interface_test.rb b/test/new_relic/control/security_interface_test.rb index 5e0aaf7162..f1a77f3001 100644 --- a/test/new_relic/control/security_interface_test.rb +++ b/test/new_relic/control/security_interface_test.rb @@ -15,10 +15,14 @@ def setup # For testing purposes, clear out the supportability metrics that have already been recorded. def reset_supportability_metrics - NewRelic::Agent.shutdown NewRelic::Agent.instance_variable_get(:@metrics_already_recorded)&.clear end + def assert_supportability_metrics_enabled + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Agent/Enabled/enabled' + assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' + end + def test_initialization_short_circuits_when_the_security_agent_is_disabled reset_supportability_metrics @@ -65,8 +69,7 @@ def test_initialization_short_circuits_when_high_security_mode_is_enabled end refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Agent/Enabled/enabled' - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' + assert_supportability_metrics_enabled end logger.verify end @@ -113,8 +116,7 @@ def test_initialization_requires_the_security_agent assert required, 'Expected init_agent to perform a require statement' assert_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Agent/Enabled/enabled' - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' + assert_supportability_metrics_enabled end def test_initialization_anticipates_a_load_error @@ -134,8 +136,7 @@ def test_initialization_anticipates_a_load_error logger.verify refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Agent/Enabled/enabled' - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' + assert_supportability_metrics_enabled end end @@ -157,7 +158,6 @@ def test_initialization_handles_errors logger.verify refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Agent/Enabled/enabled' - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' + assert_supportability_metrics_enabled end end From 51da1f47df4d4ab02a73c2f1e2838b1ffec820f5 Mon Sep 17 00:00:00 2001 From: hramadan Date: Thu, 26 Oct 2023 15:51:01 -0700 Subject: [PATCH 030/109] regenerate rubocop todo --- .rubocop_todo.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index b1f2816be7..09ca734555 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,12 +1,12 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2023-05-18 21:20:20 UTC using RuboCop version 1.51.0. +# on 2023-10-26 22:49:16 UTC using RuboCop version 1.54.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 30 +# Offense count: 31 # Configuration parameters: EnforcedStyle, AllowedGems, Include. # SupportedStyles: Gemfile, gems.rb, gemspec # Include: **/*.gemspec, **/Gemfile, **/gems.rb @@ -15,11 +15,12 @@ Gemspec/DevelopmentDependencies: - 'infinite_tracing/newrelic-infinite_tracing.gemspec' - 'newrelic_rpm.gemspec' -# Offense count: 416 +# Offense count: 443 # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. Metrics/AbcSize: Max: 40 Exclude: + - 'lib/new_relic/agent/configuration/default_source.rb' - infinite_tracing/test/**/* - lib/new_relic/cli/commands/deployments.rb - test/**/* @@ -37,7 +38,7 @@ Minitest/DuplicateTestRun: - 'test/multiverse/suites/rails/error_tracing_test.rb' - 'test/multiverse/suites/sinatra/ignoring_test.rb' -# Offense count: 276 +# Offense count: 284 Minitest/MultipleAssertions: Max: 28 @@ -45,7 +46,7 @@ Minitest/MultipleAssertions: Minitest/TestFileName: Enabled: false -# Offense count: 22 +# Offense count: 20 # This cop supports safe autocorrection (--autocorrect). Minitest/TestMethodName: Enabled: false From c3111766d31cc4325bdd1df73c54db4976b86cf8 Mon Sep 17 00:00:00 2001 From: hramadan Date: Thu, 26 Oct 2023 15:55:25 -0700 Subject: [PATCH 031/109] regenerate todo --- .rubocop_todo.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 09ca734555..a7d2e1dbcd 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2023-10-26 22:49:16 UTC using RuboCop version 1.54.0. +# on 2023-10-26 22:54:31 UTC using RuboCop version 1.54.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -25,6 +25,10 @@ Metrics/AbcSize: - lib/new_relic/cli/commands/deployments.rb - test/**/* +Metrics/CollectionLiteralLength: + Exclude: + - 'lib/new_relic/agent/configuration/default_source.rb' + # Offense count: 7 Minitest/AssertRaisesCompoundBody: Exclude: From ec33d219361697cd07f70e5e9b0266b177d22a9c Mon Sep 17 00:00:00 2001 From: hramadan Date: Thu, 26 Oct 2023 16:03:32 -0700 Subject: [PATCH 032/109] appease rubocop once more --- lib/new_relic/agent/configuration/default_source.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index 5a63a3e4b8..b53ea76743 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -57,7 +57,7 @@ def self.transform_for(key) default_settings[:transform] if default_settings end - def self.config_search_paths # rubocop:disable Metrics/AbcSize + def self.config_search_paths proc { yaml = 'newrelic.yml' config_yaml = File.join('config', yaml) From 78036b94f5549a3468b01e7617426d88c447d416 Mon Sep 17 00:00:00 2001 From: prateek-ap Date: Mon, 15 Apr 2024 17:23:25 +0530 Subject: [PATCH 033/109] add allowlist[IAST RASP] for security.mode & new security config security.request.body_limit --- lib/new_relic/agent/configuration/default_source.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index aade713e69..8419397147 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -2500,6 +2500,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :public => true, :type => String, :allowed_from_server => true, + :allowlist => %w[IAST RASP], :description => 'Defines the mode for the security agent to operate in. Currently only `IAST` is supported', :dynamic_name => true }, @@ -2544,6 +2545,15 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :external => true, :allowed_from_server => false, :description => 'The port the application is listening on. This setting is mandatory for Passenger servers. Other servers should be detected by default.' + }, + :'security.request.body_limit' => { + :default => 300, + :allow_nil => true, + :public => true, + :type => Integer, + :external => true, + :allowed_from_server => false, + :description => 'Defines the request body limit to process in security events(In KB). The default value is 300KB.' } }.freeze # rubocop:enable Metrics/CollectionLiteralLength From 863aeee219d84099239960ab150b2c86a4c1789e Mon Sep 17 00:00:00 2001 From: prateek-ap Date: Mon, 13 May 2024 16:45:40 +0530 Subject: [PATCH 034/109] log security config when IAST is disabled --- lib/new_relic/control/security_interface.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/new_relic/control/security_interface.rb b/lib/new_relic/control/security_interface.rb index 630a81ae82..85cadf0276 100644 --- a/lib/new_relic/control/security_interface.rb +++ b/lib/new_relic/control/security_interface.rb @@ -36,6 +36,9 @@ def init_agent @agent_started = true else Agent.logger.info('New Relic Security is completely disabled by one of the user provided config `security.agent.enabled`, `security.enabled`, or `high_security`. Not loading security capabilities.') + Agent.logger.info("high_security = #{Agent.config[:high_security]}") + Agent.logger.info("security.enabled = #{Agent.config[:'security.enabled']}") + Agent.logger.info("security.agent.enabled = #{Agent.config[:'security.agent.enabled']}") end rescue LoadError Agent.logger.info('New Relic security agent not found - skipping') From 7b0293eead56bb21eae64897b35b115a96f29ca1 Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Fri, 14 Jun 2024 17:02:42 -0700 Subject: [PATCH 035/109] WIP: add support for redis clustering --- lib/new_relic/agent/instrumentation/redis.rb | 4 +-- .../instrumentation/redis/instrumentation.rb | 26 ++++++++++++------- .../agent/instrumentation/redis/middleware.rb | 8 ++++++ test/multiverse/suites/redis/Envfile | 7 ++++- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/lib/new_relic/agent/instrumentation/redis.rb b/lib/new_relic/agent/instrumentation/redis.rb index ef609676ab..a57574cb8a 100644 --- a/lib/new_relic/agent/instrumentation/redis.rb +++ b/lib/new_relic/agent/instrumentation/redis.rb @@ -33,9 +33,7 @@ NewRelic::Agent.logger.info('Installing Redis Instrumentation') if NewRelic::Agent::Instrumentation::Redis::Constants::HAS_REDIS_CLIENT RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::Middleware) - end - - if use_prepend? + elsif use_prepend? prepend_instrument Redis::Client, NewRelic::Agent::Instrumentation::Redis::Prepend else chain_instrument NewRelic::Agent::Instrumentation::Redis::Chain diff --git a/lib/new_relic/agent/instrumentation/redis/instrumentation.rb b/lib/new_relic/agent/instrumentation/redis/instrumentation.rb index f8c02982cc..7d43f94caa 100644 --- a/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +++ b/lib/new_relic/agent/instrumentation/redis/instrumentation.rb @@ -9,14 +9,14 @@ module Redis INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name) def connect_with_tracing - with_tracing(Constants::CONNECT, database: db) { yield } + with_tracing(Constants::CONNECT, database: _nr_db) { yield } end def call_with_tracing(command, &block) operation = command[0] statement = ::NewRelic::Agent::Datastores::Redis.format_command(command) - with_tracing(operation, statement: statement, database: db) { yield } + with_tracing(operation, statement: statement, database: _nr_db) { yield } end # Used for Redis 4.x and 3.x @@ -24,22 +24,16 @@ def call_pipeline_with_tracing(pipeline) operation = pipeline.is_a?(::Redis::Pipeline::Multi) ? Constants::MULTI_OPERATION : Constants::PIPELINE_OPERATION statement = ::NewRelic::Agent::Datastores::Redis.format_pipeline_commands(pipeline.commands) - with_tracing(operation, statement: statement, database: db) { yield } + with_tracing(operation, statement: statement, database: _nr_db) { yield } end # Used for Redis 5.x+ def call_pipelined_with_tracing(pipeline) - db = begin - _nr_redis_client_config.db - rescue StandardError => e - NewRelic::Agent.logger.error("Failed to determine configured Redis db value: #{e.class} - #{e.message}") - nil - end operation = pipeline.flatten.include?('MULTI') ? Constants::MULTI_OPERATION : Constants::PIPELINE_OPERATION statement = ::NewRelic::Agent::Datastores::Redis.format_pipeline_commands(pipeline) - with_tracing(operation, statement: statement, database: db) { yield } + with_tracing(operation, statement: statement, database: _nr_db) { yield } end private @@ -94,5 +88,17 @@ def _nr_redis_client_config config end end + + def _nr_db + # db is a method on the Redis client in versions < 5.x + return db if respond_to?(:db) + + db = begin + _nr_redis_client_config.db + rescue StandardError => e + NewRelic::Agent.logger.error("Failed to determine configured Redis db value: #{e.class} - #{e.message}") + nil + end + end end end diff --git a/lib/new_relic/agent/instrumentation/redis/middleware.rb b/lib/new_relic/agent/instrumentation/redis/middleware.rb index ef55bb8010..6e7154dae7 100644 --- a/lib/new_relic/agent/instrumentation/redis/middleware.rb +++ b/lib/new_relic/agent/instrumentation/redis/middleware.rb @@ -8,9 +8,17 @@ module Middleware # This module is used to instrument Redis 5.x+ include NewRelic::Agent::Instrumentation::Redis + def call(*args, &block) + call_with_tracing(args[0]) { super } + end + def call_pipelined(*args, &block) call_pipelined_with_tracing(args[0]) { super } end + + def connect(*args, &block) + connect_with_tracing { super } + end end end end diff --git a/test/multiverse/suites/redis/Envfile b/test/multiverse/suites/redis/Envfile index 8969c4e42f..748e1c690d 100644 --- a/test/multiverse/suites/redis/Envfile +++ b/test/multiverse/suites/redis/Envfile @@ -4,6 +4,11 @@ instrumentation_methods :chain, :prepend +gemfile <<~RB + gem 'rack' + gem 'redis-clustering' +RB + REDIS_VERSIONS = [ [nil, 2.5], ['4.8.0', 2.4], @@ -14,7 +19,7 @@ def gem_list(redis_version = nil) <<~RB gem 'rack' gem 'redis'#{redis_version} - + RB end From f71a731005f863e77c488db2e8987578db30f4fd Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Fri, 14 Jun 2024 17:06:00 -0700 Subject: [PATCH 036/109] Update config description formatting * Make heredocs adhere to 120 character line length * Remove some extra characters, add spaces, etc. * Set documentation defaults for instrumentation.* configs for consistent display in HTML --- .../agent/configuration/default_source.rb | 103 +++++++++++++----- lib/tasks/helpers/format.rb | 2 +- .../instrumentation.thor | 1 + 3 files changed, 77 insertions(+), 29 deletions(-) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index 5bf878485d..aebb56ad60 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -388,13 +388,14 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Boolean, :allowed_from_server => false, :description => <<~DESCRIPTION - If `false`, LLM instrumentation (OpenAI only for now) will not capture input and output content on specific LLM events. + If `false`, LLM instrumentation (OpenAI only for now) will not capture input and output content on specific + LLM events. The excluded attributes include: * `content` from LlmChatCompletionMessage events * `input` from LlmEmbedding events - This is an optional security setting to prevent recording sensitive data sent to and received from your LLMs. + This is an optional security setting to prevent recording sensitive data sent to and received from your LLMs. DESCRIPTION }, # this is only set via server side config @@ -440,10 +441,16 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Boolean, :allowed_from_server => false, :description => <<~DESCRIPTION - When `true`, the agent captures HTTP request parameters and attaches them to transaction traces, traced errors, and [`TransactionError` events](/attribute-dictionary?attribute_name=&events_tids%5B%5D=8241). + When `true`, the agent captures HTTP request parameters and attaches them to transaction traces, traced + errors, and [`TransactionError` events](/attribute-dictionary?attribute_name=&events_tids%5B%5D=8241). - When using the `capture_params` setting, the Ruby agent will not attempt to filter secret information. `Recommendation:` To filter secret information from request parameters, use the [`attributes.include` setting](/docs/agents/ruby-agent/attributes/enable-disable-attributes-ruby) instead. For more information, see the Ruby attribute examples. + When using the `capture_params` setting, the Ruby agent will not attempt to filter secret information. + `Recommendation:` To filter secret information from request parameters, use the + [`attributes.include` setting](/docs/agents/ruby-agent/attributes/enable-disable-attributes-ruby) + instead. For more information, see the + Ruby attribute + examples. DESCRIPTION }, @@ -480,12 +487,14 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Boolean, :allowed_from_server => false, :description => <<~DESC - The exit handler that sends all cached data to the collector before shutting down is forcibly installed. \ - This is true even when it detects scenarios where it generally should not be. The known use case for this \ - option is when Sinatra runs as an embedded service within another framework. The agent detects the Sinatra \ - app and skips 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. + The exit handler that sends all cached data to the collector before shutting down is forcibly installed. + This is true even when it detects scenarios where it generally should not be. The known use case for this + option is when Sinatra runs as an embedded service within another framework. The agent detects the Sinatra + app and skips 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. DESC }, :high_security => { @@ -723,7 +732,9 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :allowed_from_server => true, :dynamic_name => true, :description => <<~DESCRIPTION - A map of error classes to a list of messages. When an error of one of the classes specified here occurs, if its error message contains one of the strings corresponding to it here, that error will be treated as expected. + A map of error classes to a list of messages. When an error of one of the classes specified here occurs, if + its error message contains one of the strings corresponding to it here, that error will be treated as + expected. This option can't be set via environment variable. @@ -746,7 +757,8 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :allowed_from_server => true, :dynamic_name => true, :description => <<~DESCRIPTION - A map of error classes to a list of messages. When an error of one of the classes specified here occurs, if its error message contains one of the strings corresponding to it here, that error will be ignored. + A map of error classes to a list of messages. When an error of one of the classes specified here occurs, if + its error message contains one of the strings corresponding to it here, that error will be ignored. This option can't be set via environment variable. @@ -832,11 +844,14 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :description => <<~DESCRIPTION Sets the minimum level a log event must have to be forwarded to New Relic. - This is based on the integer values of Ruby's `Logger::Severity` constants: https://github.com/ruby/ruby/blob/master/lib/logger/severity.rb + This is based on the integer values of Ruby's `Logger::Severity` constants: + https://github.com/ruby/ruby/blob/master/lib/logger/severity.rb - The intention is to forward logs with the level given to the configuration, as well as any logs with a higher level of severity. + The intention is to forward logs with the level given to the configuration, as well as any logs with a + higher level of severity. - For example, setting this value to "debug" will forward all log events to New Relic. Setting this value to "error" will only forward log events with the levels "error", "fatal", and "unknown". + For example, setting this value to "debug" will forward all log events to New Relic. Setting this value to + "error" will only forward log events with the levels "error", "fatal", and "unknown". Valid values (ordered lowest to highest): * "debug" @@ -1112,7 +1127,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :public => true, :type => Boolean, :allowed_from_server => true, - :description => "If `true`, the agent will report source code level metrics for traced methods.\nsee: " \ + :description => "If `true`, the agent will report source code level metrics for traced methods.\nSee: " \ 'https://docs.newrelic.com/docs/apm/agents/ruby-agent/features/ruby-codestream-integration/' }, # Cross application tracer @@ -1150,7 +1165,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :allowed_from_server => true, :dynamic_name => true, :description => <<~DESC - * Specify a maximum number of custom events to buffer in memory at a time.' + * Specify a maximum number of custom events to buffer in memory at a time. * When configuring the agent for [AI monitoring](/docs/ai-monitoring/intro-to-ai-monitoring), \ set to max value `100000`. This ensures the agent captures the maximum amount of LLM events. DESC @@ -1290,10 +1305,12 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Boolean, :allowed_from_server => false, :description => <<~DESCRIPTION - If `true`, the agent won't wrap third-party middlewares in instrumentation (regardless of whether they are installed via `Rack::Builder` or Rails). + If `true`, the agent won't wrap third-party middlewares in instrumentation (regardless of whether they are + installed via `Rack::Builder` or Rails). - When middleware instrumentation is disabled, if an application is using middleware that could alter the response code, the HTTP status code reported on the transaction may not reflect the altered value. + When middleware instrumentation is disabled, if an application is using middleware that could alter the + response code, the HTTP status code reported on the transaction may not reflect the altered value. DESCRIPTION }, @@ -1331,12 +1348,20 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Boolean, :allowed_from_server => false, :description => <<~DESCRIPTION - If `true`, disables agent middleware for Sinatra. This middleware is responsible for advanced feature support such as [cross application tracing](/docs/apm/transactions/cross-application-traces/cross-application-tracing), [page load timing](/docs/browser/new-relic-browser/getting-started/new-relic-browser), and [error collection](/docs/apm/applications-menu/events/view-apm-error-analytics). + If `true`, disables agent middleware for Sinatra. This middleware is responsible for advanced feature + support such as + [cross application tracing](/docs/apm/transactions/cross-application-traces/cross-application-tracing), + [page load timing](/docs/browser/new-relic-browser/getting-started/new-relic-browser), and + [error collection](/docs/apm/applications-menu/events/view-apm-error-analytics). - Cross application tracing is deprecated in favor of [distributed tracing](/docs/apm/distributed-tracing/getting-started/introduction-distributed-tracing). Distributed tracing is on by default for Ruby agent versions 8.0.0 and above. Middlewares are not required to support distributed tracing. + Cross application tracing is deprecated in favor of + [distributed tracing](/docs/apm/distributed-tracing/getting-started/introduction-distributed-tracing). + Distributed tracing is on by default for Ruby agent versions 8.0.0 and above. Middlewares are not + required to support distributed tracing. - To continue using cross application tracing, update the following options in your `newrelic.yml` configuration file: + To continue using cross application tracing, update the following options in your `newrelic.yml` + configuration file: ```yaml # newrelic.yml @@ -1444,6 +1469,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'instrumentation.async_http' => { :default => 'auto', + :documentation_default => 'auto', :public => true, :type => String, :dynamic_name => true, @@ -1452,6 +1478,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'instrumentation.bunny' => { :default => 'auto', + :documentation_default => 'auto', :public => true, :type => String, :dynamic_name => true, @@ -1460,6 +1487,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'instrumentation.dynamodb' => { :default => 'auto', + :documentation_default => 'auto', :public => true, :type => String, :dynamic_name => true, @@ -1468,6 +1496,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'instrumentation.fiber' => { :default => 'auto', + :documentation_default => 'auto', :public => true, :type => String, :dynamic_name => true, @@ -1476,6 +1505,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'instrumentation.concurrent_ruby' => { :default => 'auto', + :documentation_default => 'auto', :public => true, :type => String, :dynamic_name => true, @@ -1502,6 +1532,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'instrumentation.elasticsearch' => { :default => 'auto', + :documentation_default => 'auto', :public => true, :type => String, :dynamic_name => true, @@ -1510,6 +1541,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'instrumentation.ethon' => { :default => 'auto', + :documentation_default => 'auto', :public => true, :type => String, :dynamic_name => true, @@ -1527,6 +1559,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'instrumentation.grape' => { :default => 'auto', + :documentation_default => 'auto', :public => true, :type => String, :dynamic_name => true, @@ -1597,6 +1630,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'instrumentation.memcache' => { :default => 'auto', + :documentation_default => 'auto', :public => true, :type => String, :dynamic_name => true, @@ -1690,6 +1724,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'instrumentation.rake' => { :default => 'auto', + :documentation_default => 'auto', :public => true, :type => String, :dynamic_name => true, @@ -1698,6 +1733,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'instrumentation.redis' => { :default => 'auto', + :documentation_default => 'auto', :public => true, :type => String, :dynamic_name => true, @@ -1715,6 +1751,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'instrumentation.roda' => { :default => 'auto', + :documentation_default => 'auto', :public => true, :type => String, :dynamic_name => true, @@ -1723,6 +1760,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'instrumentation.sinatra' => { :default => 'auto', + :documentation_default => 'auto', :public => true, :type => String, :dynamic_name => true, @@ -1731,6 +1769,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'instrumentation.stripe' => { :default => 'enabled', + :documentation_default => 'auto', :public => true, :type => String, :allowed_from_server => false, @@ -1738,6 +1777,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'instrumentation.view_component' => { :default => 'auto', + :documentation_default => 'auto', :public => true, :type => String, :dynamic_name => true, @@ -1774,6 +1814,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'instrumentation.thread' => { :default => 'auto', + :documentation_default => 'auto', :public => true, :type => String, :dynamic_name => true, @@ -1796,6 +1837,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'instrumentation.tilt' => { :default => 'auto', + :documentation_default => 'auto', :public => true, :type => String, :dynamic_name => true, @@ -1893,9 +1935,13 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Boolean, :allowed_from_server => false, :transform => proc { |bool| NewRelic::Agent::ServerlessHandler.env_var_set? || bool }, - :description => 'If `true`, the agent will operate in a streamlined mode suitable for use with short-lived ' \ - 'serverless functions. NOTE: Only AWS Lambda functions are supported currently and this ' \ - "option is not intended for use without [New Relic's Ruby Lambda layer](https://docs.newrelic.com/docs/serverless-function-monitoring/aws-lambda-monitoring/get-started/monitoring-aws-lambda-serverless-monitoring/) offering." + :description => <<~DESC + If `true`, the agent will operate in a streamlined mode suitable for use with short-lived serverless + functions. NOTE: Only AWS Lambda functions are supported currently and this option is not intended for use + without + [New Relic's Ruby Lambda layer](https://docs.newrelic.com/docs/serverless-function-monitoring/aws-lambda-monitoring/get-started/monitoring-aws-lambda-serverless-monitoring/) + offering. + DESC }, # Sidekiq :'sidekiq.args.include' => { @@ -1990,9 +2036,10 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Integer, :allowed_from_server => true, :description => <<~DESC - * Defines the maximum number of span events reported from a single harvest. Any Integer between `1` and `10000` is valid.' - * When configuring the agent for [AI monitoring](/docs/ai-monitoring/intro-to-ai-monitoring), set to max value `10000`.\ - This ensures the agent captures the maximum amount of distributed traces. + * Defines the maximum number of span events reported from a single harvest. Any Integer between `1` and + `10000` is valid. + * When configuring the agent for [AI monitoring](/docs/ai-monitoring/intro-to-ai-monitoring), set to max + value `10000`. This ensures the agent captures the maximum amount of distributed traces. DESC }, # Strip exception messages diff --git a/lib/tasks/helpers/format.rb b/lib/tasks/helpers/format.rb index 2c4a3119df..12dfc8e71b 100644 --- a/lib/tasks/helpers/format.rb +++ b/lib/tasks/helpers/format.rb @@ -69,7 +69,7 @@ def format_default_value(spec) def format_description(value) description = '' - description += '**DEPRECATED**' if value[:deprecated] + description += '**DEPRECATED** ' if value[:deprecated] description += value[:description] description end diff --git a/lib/tasks/instrumentation_generator/instrumentation.thor b/lib/tasks/instrumentation_generator/instrumentation.thor index d2ac0b4170..06305c1074 100644 --- a/lib/tasks/instrumentation_generator/instrumentation.thor +++ b/lib/tasks/instrumentation_generator/instrumentation.thor @@ -103,6 +103,7 @@ class Instrumentation < Thor <<-CONFIG :'instrumentation.#{snake_name}' => { :default => 'auto', + :documentation_default => 'auto' :public => true, :type => String, :dynamic_name => true, From 4d72c54d84cb345f3f30fce6ffb2fd31c84f113c Mon Sep 17 00:00:00 2001 From: fallwith Date: Thu, 20 Jun 2024 15:18:16 -0700 Subject: [PATCH 037/109] yaml formatting: accommodate for indentation When updating `newrelic.yml` via `rake newrelic:update_newrelicyml`, take into account the fact that the description text is indented one level (2 spaces) and therefore needs to be truncated at 78 columns instead of 80. --- lib/tasks/helpers/newrelicyml.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/tasks/helpers/newrelicyml.rb b/lib/tasks/helpers/newrelicyml.rb index f9bc190aa4..1058996881 100644 --- a/lib/tasks/helpers/newrelicyml.rb +++ b/lib/tasks/helpers/newrelicyml.rb @@ -105,8 +105,9 @@ def self.sanitize_description(description) def self.format_description(description) # remove leading and trailing whitespace description.strip! - # wrap text after 80 characters - description.gsub!(/(.{1,80})(\s+|\Z)/, "\\1\n") + # wrap text after 80 characters, assuming we're at one tabstop's (two + # spaces') level of indentation already + description.gsub!(/(.{1,78})(\s+|\Z)/, "\\1\n") # add hashtags to lines description = description.split("\n").map { |line| " # #{line}" }.join("\n") From 2b4c2ffa47cf4292866df6e76fd24d9f8b991e93 Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Thu, 20 Jun 2024 22:09:51 -0700 Subject: [PATCH 038/109] Install cluster middleware --- lib/new_relic/agent/instrumentation/redis.rb | 5 +++++ .../redis/cluster_middleware.rb | 20 +++++++++++++++++++ .../agent/instrumentation/redis/middleware.rb | 11 +++------- 3 files changed, 28 insertions(+), 8 deletions(-) create mode 100644 lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb diff --git a/lib/new_relic/agent/instrumentation/redis.rb b/lib/new_relic/agent/instrumentation/redis.rb index a57574cb8a..fb485a527a 100644 --- a/lib/new_relic/agent/instrumentation/redis.rb +++ b/lib/new_relic/agent/instrumentation/redis.rb @@ -10,6 +10,7 @@ require_relative 'redis/constants' require_relative 'redis/prepend' require_relative 'redis/middleware' +require_relative 'redis/cluster_middleware' DependencyDetection.defer do # Why not :redis? newrelic-redis used that name, so avoid conflicting @@ -33,6 +34,10 @@ NewRelic::Agent.logger.info('Installing Redis Instrumentation') if NewRelic::Agent::Instrumentation::Redis::Constants::HAS_REDIS_CLIENT RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::Middleware) + + if defined?(Redis::Cluster) + RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::ClusterMiddleware) + end elsif use_prepend? prepend_instrument Redis::Client, NewRelic::Agent::Instrumentation::Redis::Prepend else diff --git a/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb b/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb new file mode 100644 index 0000000000..9fe36ec9d5 --- /dev/null +++ b/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb @@ -0,0 +1,20 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +module NewRelic::Agent::Instrumentation + module RedisClient + module ClusterMiddleware + include NewRelic::Agent::Instrumentation::Redis + + # Can't access these in redis-clustering by prepending onto the same methods + def call(*args, &block) + call_with_tracing(args[0]) { super } + end + + def connect(*args, &block) + connect_with_tracing { super } + end + end + end +end diff --git a/lib/new_relic/agent/instrumentation/redis/middleware.rb b/lib/new_relic/agent/instrumentation/redis/middleware.rb index 6e7154dae7..d601fff9fb 100644 --- a/lib/new_relic/agent/instrumentation/redis/middleware.rb +++ b/lib/new_relic/agent/instrumentation/redis/middleware.rb @@ -6,19 +6,14 @@ module NewRelic::Agent::Instrumentation module RedisClient module Middleware # This module is used to instrument Redis 5.x+ + # + # It only instruments call_pipelined because connect and call are accessed + # too late in the stack to capture all errors include NewRelic::Agent::Instrumentation::Redis - def call(*args, &block) - call_with_tracing(args[0]) { super } - end - def call_pipelined(*args, &block) call_pipelined_with_tracing(args[0]) { super } end - - def connect(*args, &block) - connect_with_tracing { super } - end end end end From ac86f4b4d2867c378b1833df523b5437197f3633 Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Fri, 21 Jun 2024 15:18:39 -0700 Subject: [PATCH 039/109] Rubocop --- lib/new_relic/agent/instrumentation/redis/instrumentation.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/new_relic/agent/instrumentation/redis/instrumentation.rb b/lib/new_relic/agent/instrumentation/redis/instrumentation.rb index 7d43f94caa..8337eac124 100644 --- a/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +++ b/lib/new_relic/agent/instrumentation/redis/instrumentation.rb @@ -29,7 +29,6 @@ def call_pipeline_with_tracing(pipeline) # Used for Redis 5.x+ def call_pipelined_with_tracing(pipeline) - operation = pipeline.flatten.include?('MULTI') ? Constants::MULTI_OPERATION : Constants::PIPELINE_OPERATION statement = ::NewRelic::Agent::Datastores::Redis.format_pipeline_commands(pipeline) From bcf6c903000d8092c29b1c3ef7862c3156d149c4 Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Fri, 21 Jun 2024 15:26:14 -0700 Subject: [PATCH 040/109] Remove unused variable --- lib/new_relic/agent/instrumentation/redis/instrumentation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/new_relic/agent/instrumentation/redis/instrumentation.rb b/lib/new_relic/agent/instrumentation/redis/instrumentation.rb index 8337eac124..efa31df989 100644 --- a/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +++ b/lib/new_relic/agent/instrumentation/redis/instrumentation.rb @@ -92,7 +92,7 @@ def _nr_db # db is a method on the Redis client in versions < 5.x return db if respond_to?(:db) - db = begin + begin _nr_redis_client_config.db rescue StandardError => e NewRelic::Agent.logger.error("Failed to determine configured Redis db value: #{e.class} - #{e.message}") From 1ad495e9855ba23eb72ae1bf9ffb8c7abd83c112 Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Wed, 26 Jun 2024 16:56:42 -0700 Subject: [PATCH 041/109] Add some config logging --- lib/new_relic/agent/instrumentation/redis.rb | 1 + lib/new_relic/agent/instrumentation/redis/instrumentation.rb | 2 ++ 2 files changed, 3 insertions(+) diff --git a/lib/new_relic/agent/instrumentation/redis.rb b/lib/new_relic/agent/instrumentation/redis.rb index fb485a527a..246e7a410a 100644 --- a/lib/new_relic/agent/instrumentation/redis.rb +++ b/lib/new_relic/agent/instrumentation/redis.rb @@ -36,6 +36,7 @@ RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::Middleware) if defined?(Redis::Cluster) + puts "REDIS CLUSTER DEFINED!" RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::ClusterMiddleware) end elsif use_prepend? diff --git a/lib/new_relic/agent/instrumentation/redis/instrumentation.rb b/lib/new_relic/agent/instrumentation/redis/instrumentation.rb index efa31df989..afc39ec0fd 100644 --- a/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +++ b/lib/new_relic/agent/instrumentation/redis/instrumentation.rb @@ -38,6 +38,8 @@ def call_pipelined_with_tracing(pipeline) private def with_tracing(operation, statement: nil, database: nil) + puts "WALUIGI - OPERATION: #{operation}" + puts "WALUIGI - CLIENT CONFIG: #{client.config.inspect}" NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME) segment = NewRelic::Agent::Tracer.start_datastore_segment( From c3bcc7e3260cbc374c67184233ef6198a23813da Mon Sep 17 00:00:00 2001 From: Hannah Ramadan Date: Wed, 26 Jun 2024 20:25:41 -0700 Subject: [PATCH 042/109] Replace DoNotTranslate with DNT --- lib/tasks/helpers/config.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tasks/helpers/config.html.erb b/lib/tasks/helpers/config.html.erb index 64ede173b1..06fdab6c17 100644 --- a/lib/tasks/helpers/config.html.erb +++ b/lib/tasks/helpers/config.html.erb @@ -76,7 +76,7 @@ When running the Ruby agent in a Rails app, the agent first looks for the `NEW_R When you edit the config file, be sure to: * Indent only with two spaces. -* Indent only where relevant, in sections such as **`error_collector`**. +* Indent only where relevant, in sections such as **`error_collector`**. If you do not indent correctly, the agent may throw an `Unable to parse configuration file` error on startup. From 3c28650606649098a95e3c0d4ea078b6701a0806 Mon Sep 17 00:00:00 2001 From: Hannah Ramadan Date: Thu, 27 Jun 2024 15:14:18 -0700 Subject: [PATCH 043/109] Remove unncessary tag and update another --- lib/tasks/helpers/config.html.erb | 2 +- lib/tasks/helpers/format.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tasks/helpers/config.html.erb b/lib/tasks/helpers/config.html.erb index 06fdab6c17..fff66a972d 100644 --- a/lib/tasks/helpers/config.html.erb +++ b/lib/tasks/helpers/config.html.erb @@ -76,7 +76,7 @@ When running the Ruby agent in a Rails app, the agent first looks for the `NEW_R When you edit the config file, be sure to: * Indent only with two spaces. -* Indent only where relevant, in sections such as **`error_collector`**. +* Indent only where relevant, in sections such as **`error_collector`**. If you do not indent correctly, the agent may throw an `Unable to parse configuration file` error on startup. diff --git a/lib/tasks/helpers/format.rb b/lib/tasks/helpers/format.rb index 12dfc8e71b..fc4f2e4f22 100644 --- a/lib/tasks/helpers/format.rb +++ b/lib/tasks/helpers/format.rb @@ -69,7 +69,7 @@ def format_default_value(spec) def format_description(value) description = '' - description += '**DEPRECATED** ' if value[:deprecated] + description += '**DEPRECATED** ' if value[:deprecated] description += value[:description] description end From 75e08b9e4458398c5a7ae09b64adc97bc31ac0c5 Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Fri, 28 Jun 2024 17:10:47 -0700 Subject: [PATCH 044/109] Remove logging --- lib/new_relic/agent/instrumentation/redis/instrumentation.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/new_relic/agent/instrumentation/redis/instrumentation.rb b/lib/new_relic/agent/instrumentation/redis/instrumentation.rb index afc39ec0fd..efa31df989 100644 --- a/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +++ b/lib/new_relic/agent/instrumentation/redis/instrumentation.rb @@ -38,8 +38,6 @@ def call_pipelined_with_tracing(pipeline) private def with_tracing(operation, statement: nil, database: nil) - puts "WALUIGI - OPERATION: #{operation}" - puts "WALUIGI - CLIENT CONFIG: #{client.config.inspect}" NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME) segment = NewRelic::Agent::Tracer.start_datastore_segment( From 0bba9347605434aa1701ac66503f567d6b4e9a0f Mon Sep 17 00:00:00 2001 From: Tanna McClure Date: Mon, 1 Jul 2024 13:04:51 -0500 Subject: [PATCH 045/109] add new attributes to bunny instrumentation --- .../agent/instrumentation/bunny/instrumentation.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb b/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb index 7467ef3aef..4866e1ae1e 100644 --- a/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +++ b/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb @@ -48,6 +48,11 @@ def publish_with_tracing(payload, opts = {}) correlation_id: opts[:correlation_id], exchange_type: type ) + if segment + segment.add_agent_attribute('server.address', channel&.connection&.hostname) + segment.add_agent_attribute('messaging.destination.name', destination) + segment.add_agent_attribute('messaging.rabbitmq.destination.routing_key', opts[:routing_key]) + end rescue => e NewRelic::Agent.logger.error('Error starting message broker segment in Bunny::Exchange#publish', e) yield @@ -94,6 +99,14 @@ def pop_with_tracing queue_name: name, start_time: t0 ) + if segment + segment.add_agent_attribute('server.address', channel&.connection&.hostname) + segment.add_agent_attribute('server.port', channel&.connection&.port) + segment.add_agent_attribute('messaging.destination.name', name) + segment.add_agent_attribute('messaging.destination_publish.name', exch_name) + segment.add_agent_attribute('message.queueName', name) + segment.add_agent_attribute('messaging.rabbitmq.destination.routing_key', delivery_info&.routing_key) + end rescue => e NewRelic::Agent.logger.error('Error starting message broker segment in Bunny::Queue#pop', e) else From b317fa43315e45894ba07c1a38fab0771244528a Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Mon, 1 Jul 2024 16:52:31 -0700 Subject: [PATCH 046/109] Skip tests that fail on redis-clustering --- lib/new_relic/agent/instrumentation/redis.rb | 3 +-- .../instrumentation/redis/cluster_middleware.rb | 1 - .../suites/redis/redis_instrumentation_test.rb | 16 ++++++++++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/new_relic/agent/instrumentation/redis.rb b/lib/new_relic/agent/instrumentation/redis.rb index 246e7a410a..6c397ab59b 100644 --- a/lib/new_relic/agent/instrumentation/redis.rb +++ b/lib/new_relic/agent/instrumentation/redis.rb @@ -35,8 +35,7 @@ if NewRelic::Agent::Instrumentation::Redis::Constants::HAS_REDIS_CLIENT RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::Middleware) - if defined?(Redis::Cluster) - puts "REDIS CLUSTER DEFINED!" + if defined?(Redis::Cluster::Client) RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::ClusterMiddleware) end elsif use_prepend? diff --git a/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb b/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb index 9fe36ec9d5..849bb0e12a 100644 --- a/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb +++ b/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb @@ -7,7 +7,6 @@ module RedisClient module ClusterMiddleware include NewRelic::Agent::Instrumentation::Redis - # Can't access these in redis-clustering by prepending onto the same methods def call(*args, &block) call_with_tracing(args[0]) { super } end diff --git a/test/multiverse/suites/redis/redis_instrumentation_test.rb b/test/multiverse/suites/redis/redis_instrumentation_test.rb index bc88722d41..0d5a6a7420 100644 --- a/test/multiverse/suites/redis/redis_instrumentation_test.rb +++ b/test/multiverse/suites/redis/redis_instrumentation_test.rb @@ -59,6 +59,8 @@ def test_records_metrics_for_connect end def test_records_connect_tt_node_within_call_that_triggered_it + skip_for_redis_clustering_gem + in_transaction do redis = Redis.new redis.get('foo') @@ -277,6 +279,8 @@ def test_records_instance_parameters_on_tt_node_for_get end def test_records_hostname_on_tt_node_for_get_with_unix_domain_socket + skip_for_redis_clustering_gem + redis = Redis.new redis.send(client).stubs(:path).returns('/tmp/redis.sock') @@ -309,6 +313,8 @@ def test_records_instance_parameters_on_tt_node_for_multi end def test_records_hostname_on_tt_node_for_multi_with_unix_domain_socket + skip_for_redis_clustering_gem + redis = Redis.new redis.send(client).stubs(:path).returns('/tmp/redis.sock') @@ -327,6 +333,8 @@ def test_records_hostname_on_tt_node_for_multi_with_unix_domain_socket end def test_records_unknown_unknown_metric_when_error_gathering_instance_data + skip_for_redis_clustering_gem + redis = Redis.new redis.send(client).stubs(:path).raises(StandardError.new) in_transaction do @@ -347,6 +355,8 @@ def simulate_read_error end def test_noticed_error_at_segment_and_txn_on_error + skip_for_redis_clustering_gem + txn = nil begin in_transaction do |redis_txn| @@ -362,6 +372,8 @@ def test_noticed_error_at_segment_and_txn_on_error end def test_noticed_error_only_at_segment_on_error + skip_for_redis_clustering_gem + txn = nil in_transaction do |redis_txn| begin @@ -472,4 +484,8 @@ def either_hostname [NewRelic::Agent::Hostname.get, 'redis'] end end + + def skip_for_redis_clustering_gem + skip 'Incompatible with redis-clustering' if defined?(Redis::Cluster::Client) + end end From aea52de929cbdd3648b9d73e9aa73775cb51f566 Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Mon, 1 Jul 2024 16:58:59 -0700 Subject: [PATCH 047/109] Update --- lib/new_relic/agent/instrumentation/redis.rb | 6 ++++-- test/multiverse/suites/redis/Envfile | 14 +++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/new_relic/agent/instrumentation/redis.rb b/lib/new_relic/agent/instrumentation/redis.rb index 6c397ab59b..691c8e87c3 100644 --- a/lib/new_relic/agent/instrumentation/redis.rb +++ b/lib/new_relic/agent/instrumentation/redis.rb @@ -36,9 +36,11 @@ RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::Middleware) if defined?(Redis::Cluster::Client) - RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::ClusterMiddleware) + return RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::ClusterMiddleware) end - elsif use_prepend? + end + + if use_prepend? prepend_instrument Redis::Client, NewRelic::Agent::Instrumentation::Redis::Prepend else chain_instrument NewRelic::Agent::Instrumentation::Redis::Chain diff --git a/test/multiverse/suites/redis/Envfile b/test/multiverse/suites/redis/Envfile index 748e1c690d..9f9a56829c 100644 --- a/test/multiverse/suites/redis/Envfile +++ b/test/multiverse/suites/redis/Envfile @@ -4,11 +4,6 @@ instrumentation_methods :chain, :prepend -gemfile <<~RB - gem 'rack' - gem 'redis-clustering' -RB - REDIS_VERSIONS = [ [nil, 2.5], ['4.8.0', 2.4], @@ -24,3 +19,12 @@ def gem_list(redis_version = nil) end create_gemfiles(REDIS_VERSIONS) + +# We do not spin up a full Redis cluster in the testing environment, which +# limits our ability to run unit tests on the redis-clustering behavior. +# Since the testing capability is limited, only test the latest version of the +# redis-clustering gem. +gemfile <<~RB + gem 'rack' + gem 'redis-clustering' +RB From ee711e00c48c6a7f0a7df63d2769d8ac3d5ccf6c Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Tue, 2 Jul 2024 08:48:37 -0700 Subject: [PATCH 048/109] Add comment to ClusterMiddleware --- .../agent/instrumentation/redis/cluster_middleware.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb b/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb index 849bb0e12a..5be2334b8b 100644 --- a/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb +++ b/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb @@ -7,6 +7,13 @@ module RedisClient module ClusterMiddleware include NewRelic::Agent::Instrumentation::Redis + # Until we decide to move our Redis instrumentation entirely off patches + # keep the middleware instrumentation for the call and connect methods + # limited to the redis-clustering instrumentation. + # + # Redis's middleware option does not capture errors as high in the stack + # as our patches. Leaving the patches for call and connect on the main + # Redis gem limits the feature disparity our customers experience. def call(*args, &block) call_with_tracing(args[0]) { super } end From 902eef0fa25f3a5256ae19f791a9b44cc08d666e Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Tue, 2 Jul 2024 08:58:54 -0700 Subject: [PATCH 049/109] Add Ruby version constraint for redis-clustering --- test/multiverse/suites/redis/Envfile | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/multiverse/suites/redis/Envfile b/test/multiverse/suites/redis/Envfile index 9f9a56829c..1f631f56f9 100644 --- a/test/multiverse/suites/redis/Envfile +++ b/test/multiverse/suites/redis/Envfile @@ -24,7 +24,9 @@ create_gemfiles(REDIS_VERSIONS) # limits our ability to run unit tests on the redis-clustering behavior. # Since the testing capability is limited, only test the latest version of the # redis-clustering gem. -gemfile <<~RB - gem 'rack' - gem 'redis-clustering' -RB +if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7.0') + gemfile <<~RB + gem 'rack' + gem 'redis-clustering' + RB +end From e4a95b490b4d574d6bc5fa07d6f3aa67d2165379 Mon Sep 17 00:00:00 2001 From: "Kayla Reopelle (she/her)" <87386821+kaylareopelle@users.noreply.github.com> Date: Tue, 2 Jul 2024 13:41:58 -0700 Subject: [PATCH 050/109] Apply suggestions from code review Co-authored-by: James Bunch --- test/multiverse/suites/redis/Envfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/multiverse/suites/redis/Envfile b/test/multiverse/suites/redis/Envfile index 1f631f56f9..04d39db434 100644 --- a/test/multiverse/suites/redis/Envfile +++ b/test/multiverse/suites/redis/Envfile @@ -23,7 +23,7 @@ create_gemfiles(REDIS_VERSIONS) # We do not spin up a full Redis cluster in the testing environment, which # limits our ability to run unit tests on the redis-clustering behavior. # Since the testing capability is limited, only test the latest version of the -# redis-clustering gem. +# redis-clustering gem, which itself requires Ruby v2.7+. if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7.0') gemfile <<~RB gem 'rack' From dc565ebc056127fcb238569335da09c447213d00 Mon Sep 17 00:00:00 2001 From: Tanna McClure Date: Tue, 2 Jul 2024 15:47:59 -0500 Subject: [PATCH 051/109] add tests for attributes --- .../instrumentation/bunny/instrumentation.rb | 5 ++- test/multiverse/suites/bunny/bunny_test.rb | 41 +++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb b/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb index 4866e1ae1e..84a826f7d3 100644 --- a/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +++ b/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb @@ -50,7 +50,8 @@ def publish_with_tracing(payload, opts = {}) ) if segment segment.add_agent_attribute('server.address', channel&.connection&.hostname) - segment.add_agent_attribute('messaging.destination.name', destination) + segment.add_agent_attribute('server.port', channel&.connection&.port) + segment.add_agent_attribute('messaging.destination.name', destination) # for produce, this is exchange name segment.add_agent_attribute('messaging.rabbitmq.destination.routing_key', opts[:routing_key]) end rescue => e @@ -102,7 +103,7 @@ def pop_with_tracing if segment segment.add_agent_attribute('server.address', channel&.connection&.hostname) segment.add_agent_attribute('server.port', channel&.connection&.port) - segment.add_agent_attribute('messaging.destination.name', name) + segment.add_agent_attribute('messaging.destination.name', name) # for consume, this is queue name segment.add_agent_attribute('messaging.destination_publish.name', exch_name) segment.add_agent_attribute('message.queueName', name) segment.add_agent_attribute('messaging.rabbitmq.destination.routing_key', delivery_info&.routing_key) diff --git a/test/multiverse/suites/bunny/bunny_test.rb b/test/multiverse/suites/bunny/bunny_test.rb index 86f5bb77d4..89532f680b 100644 --- a/test/multiverse/suites/bunny/bunny_test.rb +++ b/test/multiverse/suites/bunny/bunny_test.rb @@ -15,6 +15,9 @@ class BunnyTest < Minitest::Test end def teardown + harvest_span_events! + mocha_teardown + NewRelic::Agent.instance.stats_engine.clear_stats @conn.close end @@ -333,6 +336,44 @@ def test_pop_returning_no_message_doesnt_error end end + def test_pop_adds_attributes_to_span + with_queue do |queue| + queue.publish('test_msg', routing_key: queue.name) + in_transaction('test_txn') do |txn| + txn.stubs(:sampled?).returns(true) + + queue.pop + end + sleep 0.5 + spans = harvest_span_events! + + assert_equal 'rabbitmq', spans[1][0][2]['server.address'] + assert_equal 5672, spans[1][0][2]['server.port'] + assert_equal 'Default', spans[1][0][2]['messaging.destination_publish.name'] + assert_equal queue.name, spans[1][0][2]['messaging.destination.name'] + assert_equal queue.name, spans[1][0][2]['messaging.rabbitmq.destination.routing_key'] + assert_equal queue.name, spans[1][0][2]['message.queueName'] + end + end + + def test_waluigi_publish_adds_attributes_to_span + NewRelic::Agent.stubs(:logger).returns(NewRelic::Agent::MemoryLogger.new) + + with_queue do |queue| + in_transaction('test_txn') do |txn| + txn.stubs(:sampled?).returns(true) + queue.publish('test_msg', routing_key: queue.name) + end + sleep 0.5 + spans = harvest_span_events! + + assert_equal 'rabbitmq', spans[1][0][2]['server.address'] + assert_equal 5672, spans[1][0][2]['server.port'] + assert_equal 'Default', spans[1][0][2]['messaging.destination.name'] + assert_equal queue.name, spans[1][0][2]['messaging.rabbitmq.destination.routing_key'] + end + end + def test_pop_returning_a_good_message_send_to_an_exchange_we_havent_accessed_doesnt_error NewRelic::Agent.stubs(:logger).returns(NewRelic::Agent::MemoryLogger.new) From 77f1af7a02d66216281be4b7d7b274371527e43b Mon Sep 17 00:00:00 2001 From: Tanna McClure Date: Tue, 2 Jul 2024 15:49:44 -0500 Subject: [PATCH 052/109] rename test --- test/multiverse/suites/bunny/bunny_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/multiverse/suites/bunny/bunny_test.rb b/test/multiverse/suites/bunny/bunny_test.rb index 89532f680b..20783394f5 100644 --- a/test/multiverse/suites/bunny/bunny_test.rb +++ b/test/multiverse/suites/bunny/bunny_test.rb @@ -356,7 +356,7 @@ def test_pop_adds_attributes_to_span end end - def test_waluigi_publish_adds_attributes_to_span + def test_publish_adds_attributes_to_span NewRelic::Agent.stubs(:logger).returns(NewRelic::Agent::MemoryLogger.new) with_queue do |queue| From 373aeaaa7e07f754989d0461469359300f34fd33 Mon Sep 17 00:00:00 2001 From: Tanna McClure Date: Tue, 2 Jul 2024 15:50:41 -0500 Subject: [PATCH 053/109] remove unneeded logger stubbing --- test/multiverse/suites/bunny/bunny_test.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/multiverse/suites/bunny/bunny_test.rb b/test/multiverse/suites/bunny/bunny_test.rb index 20783394f5..a02157095c 100644 --- a/test/multiverse/suites/bunny/bunny_test.rb +++ b/test/multiverse/suites/bunny/bunny_test.rb @@ -357,8 +357,6 @@ def test_pop_adds_attributes_to_span end def test_publish_adds_attributes_to_span - NewRelic::Agent.stubs(:logger).returns(NewRelic::Agent::MemoryLogger.new) - with_queue do |queue| in_transaction('test_txn') do |txn| txn.stubs(:sampled?).returns(true) From 982c3d2cc4490b9fbc976805bfc3527f884022cb Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Tue, 2 Jul 2024 16:32:18 -0700 Subject: [PATCH 054/109] Add changelog entry --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7f6e1094d..e03e3effcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # New Relic Ruby Agent Release Notes +## + +Version improves instrumentation for the `redis-clustering` gem. + +- **Feature: Add instrumentation for redis-clustering** + + Version 5.x of the `redis` gem moved cluster behavior into a different gem, `redis-clustering`. This gem can access instrumentation registered through `RedisClient::Middleware`. Previously, the agent only instrumented the `call_pipelined` method through this approach, but now users of the `redis-clustering` gem will also have instrumentation registered for `connect` and `call` methods. In addition, the way the `database_name` attribute is set for Redis datastore spans is now compatible with all versions of Redis supported by the New Relic Ruby agent. Thank you, [@praveen-ks](https://github.com/praveen-ks) for bringing this to our attention. [Issue#2444](https://github.com/newrelic/newrelic-ruby-agent/issues/2444) [PR#2720](https://github.com/newrelic/newrelic-ruby-agent/pull/2720) + ## v9.11.0 Version 9.11.0 introduces instrumentation for the aws-sdk-sqs gem, fixes a bug related to expected errors not bearing a "true" value for the "expected" attribute if expected as a result of an HTTP status code match and changes the way Stripe instrumentation metrics are named to prevent high-cardinality issues. From 337f888423d489dcd5f1fa9151584ef096e2beec Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Wed, 3 Jul 2024 09:12:30 -0700 Subject: [PATCH 055/109] Refactor _nr_db * Log the failure message at the debug level * Check for the presence of the #db method on the client config object using respond_to? --- .../agent/instrumentation/redis/instrumentation.rb | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/new_relic/agent/instrumentation/redis/instrumentation.rb b/lib/new_relic/agent/instrumentation/redis/instrumentation.rb index efa31df989..ca1ba59057 100644 --- a/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +++ b/lib/new_relic/agent/instrumentation/redis/instrumentation.rb @@ -91,13 +91,11 @@ def _nr_redis_client_config def _nr_db # db is a method on the Redis client in versions < 5.x return db if respond_to?(:db) - - begin - _nr_redis_client_config.db - rescue StandardError => e - NewRelic::Agent.logger.error("Failed to determine configured Redis db value: #{e.class} - #{e.message}") - nil - end + # db is accessible through the RedisClient::Config object in versions > 5.x + return _nr_redis_client_config.db if _nr_redis_client_config.respond_to?(:db) + rescue StandardError => e + NewRelic::Agent.logger.debug("Failed to determine configured Redis db value: #{e.class} - #{e.message}") + nil end end end From 7d779876af509c4c59436a5e49057d175964aac7 Mon Sep 17 00:00:00 2001 From: Tanna McClure Date: Wed, 3 Jul 2024 12:41:55 -0500 Subject: [PATCH 056/109] fix for bunny tests in CI --- test/multiverse/suites/bunny/bunny_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/multiverse/suites/bunny/bunny_test.rb b/test/multiverse/suites/bunny/bunny_test.rb index a02157095c..70b419da47 100644 --- a/test/multiverse/suites/bunny/bunny_test.rb +++ b/test/multiverse/suites/bunny/bunny_test.rb @@ -347,7 +347,7 @@ def test_pop_adds_attributes_to_span sleep 0.5 spans = harvest_span_events! - assert_equal 'rabbitmq', spans[1][0][2]['server.address'] + assert_equal @conn.hostname, spans[1][0][2]['server.address'] assert_equal 5672, spans[1][0][2]['server.port'] assert_equal 'Default', spans[1][0][2]['messaging.destination_publish.name'] assert_equal queue.name, spans[1][0][2]['messaging.destination.name'] @@ -365,7 +365,7 @@ def test_publish_adds_attributes_to_span sleep 0.5 spans = harvest_span_events! - assert_equal 'rabbitmq', spans[1][0][2]['server.address'] + assert_equal @conn.hostname, spans[1][0][2]['server.address'] assert_equal 5672, spans[1][0][2]['server.port'] assert_equal 'Default', spans[1][0][2]['messaging.destination.name'] assert_equal queue.name, spans[1][0][2]['messaging.rabbitmq.destination.routing_key'] From 1827a7aea31a5e53455459dd6b66141f8d254b7e Mon Sep 17 00:00:00 2001 From: Tanna McClure Date: Wed, 3 Jul 2024 14:19:43 -0500 Subject: [PATCH 057/109] remove sleeps --- test/multiverse/suites/bunny/bunny_test.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/multiverse/suites/bunny/bunny_test.rb b/test/multiverse/suites/bunny/bunny_test.rb index 70b419da47..52cb4fbbc9 100644 --- a/test/multiverse/suites/bunny/bunny_test.rb +++ b/test/multiverse/suites/bunny/bunny_test.rb @@ -344,7 +344,6 @@ def test_pop_adds_attributes_to_span queue.pop end - sleep 0.5 spans = harvest_span_events! assert_equal @conn.hostname, spans[1][0][2]['server.address'] @@ -362,7 +361,6 @@ def test_publish_adds_attributes_to_span txn.stubs(:sampled?).returns(true) queue.publish('test_msg', routing_key: queue.name) end - sleep 0.5 spans = harvest_span_events! assert_equal @conn.hostname, spans[1][0][2]['server.address'] From e412c6b505bdc324b48c3a4e59c95623ca3a12b4 Mon Sep 17 00:00:00 2001 From: fallwith Date: Wed, 3 Jul 2024 12:27:39 -0700 Subject: [PATCH 058/109] CI: JRuby 9.4.7.0 -> 9.4.8.0 Update setup-ruby and target the latest stable JRuby --- .github/versions.yml | 4 ++-- .github/workflows/ci.yml | 10 +++++----- .github/workflows/ci_cron.yml | 8 ++++---- .github/workflows/ci_jruby.yml | 8 ++++---- .github/workflows/config_docs.yml | 2 +- .github/workflows/performance_tests.yml | 2 +- .github/workflows/prerelease.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/release_notes.yml | 2 +- .github/workflows/release_pr.yml | 2 +- .github/workflows/slack_notifications.yml | 4 ++-- 11 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/versions.yml b/.github/versions.yml index e2ae82ae91..2f3e96cac2 100644 --- a/.github/versions.yml +++ b/.github/versions.yml @@ -1,8 +1,8 @@ --- # This file is consumed by lib/tasks/gha.rake ruby/setup-ruby: - :tag: v1.180.0 - :sha: ff740bc00a01b3a50fffc55a1071b1060eeae9dc + :tag: v1.184.0 + :sha: 97e35c5302afcf3f5ac1df3fca9343d32536b286 actions/checkout: :tag: v4.1.2 :sha: 9bb56186c3b09b4f86b1c65136769dd318469633 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ec55746139..c6e1d21ff7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: - name: Configure git run: 'git config --global init.defaultBranch main' - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 - - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: ruby-version: '3.3' - run: bundle @@ -49,7 +49,7 @@ jobs: run: sudo apt-get update; sudo apt-get install -y --no-install-recommends libcurl4-nss-dev libsasl2-dev libxslt1-dev - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -204,7 +204,7 @@ jobs: run: sudo apt-get update; sudo apt-get install -y --no-install-recommends libcurl4-nss-dev libsasl2-dev libxslt1-dev - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -297,7 +297,7 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -337,7 +337,7 @@ jobs: - name: Configure git run: 'git config --global init.defaultBranch main' - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 - - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: ruby-version: '3.3' - run: bundle diff --git a/.github/workflows/ci_cron.yml b/.github/workflows/ci_cron.yml index 5ea52835dc..b8fde8fbdb 100644 --- a/.github/workflows/ci_cron.yml +++ b/.github/workflows/ci_cron.yml @@ -16,7 +16,7 @@ jobs: - name: Configure git run: 'git config --global init.defaultBranch main' - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 - - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: ruby-version: '3.3' - run: bundle @@ -50,7 +50,7 @@ jobs: run: sudo apt-get update; sudo apt-get install -y --no-install-recommends libcurl4-nss-dev libsasl2-dev libxslt1-dev - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -216,7 +216,7 @@ jobs: run: sudo apt-get update; sudo apt-get install -y --no-install-recommends libcurl4-nss-dev libsasl2-dev libxslt1-dev - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -288,7 +288,7 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: ruby-version: ${{ matrix.ruby-version }} diff --git a/.github/workflows/ci_jruby.yml b/.github/workflows/ci_jruby.yml index 421977d1c9..0dc1ac362a 100644 --- a/.github/workflows/ci_jruby.yml +++ b/.github/workflows/ci_jruby.yml @@ -16,9 +16,9 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 - name: Install JRuby - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: - ruby-version: jruby-9.4.7.0 + ruby-version: jruby-9.4.8.0 - name: Bundle run: bundle install @@ -49,9 +49,9 @@ jobs: uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 - name: Install JRuby - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: - ruby-version: jruby-9.4.7.0 + ruby-version: jruby-9.4.8.0 - name: Bundle run: bundle install diff --git a/.github/workflows/config_docs.yml b/.github/workflows/config_docs.yml index 3ac1fd65c7..bdd63a8639 100644 --- a/.github/workflows/config_docs.yml +++ b/.github/workflows/config_docs.yml @@ -15,7 +15,7 @@ jobs: pull-requests: write steps: - name: Install Ruby 3.3 - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: ruby-version: 3.3 diff --git a/.github/workflows/performance_tests.yml b/.github/workflows/performance_tests.yml index b3c25088bb..6835edcfdc 100644 --- a/.github/workflows/performance_tests.yml +++ b/.github/workflows/performance_tests.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 with: ref: 'main' - - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: ruby-version: '3.3' - run: bundle diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index fef0a5a6f0..99a3c62b0d 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -11,7 +11,7 @@ jobs: pull-requests: write steps: - name: Install Ruby 3.3 - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: ruby-version: 3.3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7887d8a83e..1f2cb82645 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,7 @@ jobs: with: fetch-depth: 0 - - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: ruby-version: 3.3 diff --git a/.github/workflows/release_notes.yml b/.github/workflows/release_notes.yml index b0bf79887d..054d8fd03e 100644 --- a/.github/workflows/release_notes.yml +++ b/.github/workflows/release_notes.yml @@ -13,7 +13,7 @@ jobs: contents: write pull-requests: write steps: - - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: ruby-version: 3.3 - name: Checkout code diff --git a/.github/workflows/release_pr.yml b/.github/workflows/release_pr.yml index 9e68e4c333..22019cfa3e 100644 --- a/.github/workflows/release_pr.yml +++ b/.github/workflows/release_pr.yml @@ -14,7 +14,7 @@ jobs: pull-requests: write steps: - name: Install Ruby 3.3 - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: ruby-version: 3.3 diff --git a/.github/workflows/slack_notifications.yml b/.github/workflows/slack_notifications.yml index efdd74db92..db9ab0617d 100644 --- a/.github/workflows/slack_notifications.yml +++ b/.github/workflows/slack_notifications.yml @@ -8,7 +8,7 @@ jobs: gem_notifications: runs-on: ubuntu-22.04 steps: - - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: ruby-version: 3.3 - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 @@ -46,7 +46,7 @@ jobs: cve_notifications: runs-on: ubuntu-22.04 steps: - - uses: ruby/setup-ruby@ff740bc00a01b3a50fffc55a1071b1060eeae9dc # tag v1.180.0 + - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 with: ruby-version: 3.3 - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 From 5b13a17309247dc1d2fe92b888646ee8ae321f8c Mon Sep 17 00:00:00 2001 From: fallwith Date: Mon, 8 Jul 2024 15:07:33 -0700 Subject: [PATCH 059/109] add Rails v7.1 test environment add Rails v7.1 to the list of test environments --- .github/workflows/ci.yml | 2 +- .github/workflows/ci_cron.yml | 12 +++---- test/environments/rails71/Gemfile | 34 +++++++++++++++++++ test/environments/rails71/Rakefile | 17 ++++++++++ .../rails71/app/assets/config/manifest.js | 0 .../app/controllers/application_controller.rb | 6 ++++ .../app/controllers/no_method_controller.rb | 7 ++++ .../rails71/config/application.rb | 20 +++++++++++ test/environments/rails71/config/boot.rb | 8 +++++ test/environments/rails71/config/database.yml | 30 ++++++++++++++++ .../rails71/config/environment.rb | 9 +++++ .../rails71/config/initializers/test.rb | 20 +++++++++++ test/environments/rails71/db/schema.rb | 5 +++ 13 files changed, 163 insertions(+), 7 deletions(-) create mode 100644 test/environments/rails71/Gemfile create mode 100644 test/environments/rails71/Rakefile create mode 100644 test/environments/rails71/app/assets/config/manifest.js create mode 100644 test/environments/rails71/app/controllers/application_controller.rb create mode 100644 test/environments/rails71/app/controllers/no_method_controller.rb create mode 100644 test/environments/rails71/config/application.rb create mode 100644 test/environments/rails71/config/boot.rb create mode 100644 test/environments/rails71/config/database.yml create mode 100644 test/environments/rails71/config/environment.rb create mode 100644 test/environments/rails71/config/initializers/test.rb create mode 100644 test/environments/rails71/db/schema.rb diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c6e1d21ff7..098298b973 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,7 +63,7 @@ jobs: "rails": "norails,rails42,rails52" }, "3.3.3": { - "rails": "norails,rails61,rails70" + "rails": "norails,rails61,rails71" } } diff --git a/.github/workflows/ci_cron.yml b/.github/workflows/ci_cron.yml index b8fde8fbdb..a24a9a3b5b 100644 --- a/.github/workflows/ci_cron.yml +++ b/.github/workflows/ci_cron.yml @@ -70,22 +70,22 @@ jobs: "rails": "norails,rails61,rails60,rails52,rails51,rails50,rails42" }, "2.7.8": { - "rails": "norails,rails61,rails60,rails70" + "rails": "norails,rails61,rails60,rails70,rails71" }, "3.0.7": { - "rails": "norails,rails61,rails60,rails70" + "rails": "norails,rails61,rails60,rails70,rails71" }, "3.1.6": { - "rails": "norails,rails61,rails70" + "rails": "norails,rails61,rails70,rails71" }, "3.2.4": { - "rails": "norails,rails61,rails70" + "rails": "norails,rails61,rails70,rails71" }, "3.3.3": { - "rails": "norails,rails61,rails70" + "rails": "norails,rails61,rails70,rails71" }, "3.4.0-preview1": { - "rails": "norails,rails61,rails70" + "rails": "norails,rails61,rails70,rails71" } } diff --git a/test/environments/rails71/Gemfile b/test/environments/rails71/Gemfile new file mode 100644 index 0000000000..d6090d7871 --- /dev/null +++ b/test/environments/rails71/Gemfile @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gem 'rails', '~> 7.1.3' +gem 'bootsnap', '>= 1.4.4', require: false + +gem 'minitest', '5.2.3' +gem 'minitest-stub-const', '~> 0.6' +gem 'mocha', '~> 1.16', require: false + +platforms :ruby, :rbx do + gem 'mysql2', '>= 0.5.4' + gem 'sqlite3', '~> 1.4' +end + +gem 'newrelic_rpm', path: '../../..' + +group :development do + if ENV['ENABLE_PRY'] + gem 'pry', '~> 0.9.12' + gem 'pry-nav' + end +end + +gem 'simplecov' if ENV['VERBOSE_TEST_OUTPUT'] +gem 'warning' + +if RUBY_VERSION.split('.')[0..1].join('.').to_f >= 3.4 + gem 'base64' + gem 'bigdecimal' + gem 'mutex_m' + gem 'ostruct' +end diff --git a/test/environments/rails71/Rakefile b/test/environments/rails71/Rakefile new file mode 100644 index 0000000000..8c74a5a9a9 --- /dev/null +++ b/test/environments/rails71/Rakefile @@ -0,0 +1,17 @@ +# This file is distributed under new relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/license for complete details. +# frozen_string_literal: true + +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require_relative '../../warning_test_helper' + +require_relative 'config/application' + +Rails.application.load_tasks + +require 'tasks/all' + +Rake::Task['default'].clear +task :default => [:'test:newrelic'] diff --git a/test/environments/rails71/app/assets/config/manifest.js b/test/environments/rails71/app/assets/config/manifest.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/environments/rails71/app/controllers/application_controller.rb b/test/environments/rails71/app/controllers/application_controller.rb new file mode 100644 index 0000000000..612314dd94 --- /dev/null +++ b/test/environments/rails71/app/controllers/application_controller.rb @@ -0,0 +1,6 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +class ApplicationController < ActionController::Base +end diff --git a/test/environments/rails71/app/controllers/no_method_controller.rb b/test/environments/rails71/app/controllers/no_method_controller.rb new file mode 100644 index 0000000000..70a729db3f --- /dev/null +++ b/test/environments/rails71/app/controllers/no_method_controller.rb @@ -0,0 +1,7 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +require_relative 'application_controller' + +class NoMethodController < ApplicationController; end diff --git a/test/environments/rails71/config/application.rb b/test/environments/rails71/config/application.rb new file mode 100644 index 0000000000..32278ee1b4 --- /dev/null +++ b/test/environments/rails71/config/application.rb @@ -0,0 +1,20 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +require_relative 'boot' + +require 'rails/all' + +# Require the gems listed in Gemfile, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(*Rails.groups) + +module RpmTestApp + class Application < Rails::Application + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults(7.0) + config.eager_load = false + config.filter_parameters += [:password] + end +end diff --git a/test/environments/rails71/config/boot.rb b/test/environments/rails71/config/boot.rb new file mode 100644 index 0000000000..a8d25cb53d --- /dev/null +++ b/test/environments/rails71/config/boot.rb @@ -0,0 +1,8 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) + +require 'bundler/setup' # Set up gems listed in the Gemfile. +require 'bootsnap/setup' # Speed up boot time by caching expensive operations. diff --git a/test/environments/rails71/config/database.yml b/test/environments/rails71/config/database.yml new file mode 100644 index 0000000000..5e490dbd99 --- /dev/null +++ b/test/environments/rails71/config/database.yml @@ -0,0 +1,30 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +mysql: &mysql + adapter: mysql2 + username: root + password: <%= ENV['MYSQL_PASSWORD'] %> + host: localhost + database: <%= db = "#{ENV['RUBY_VERSION']}#{ENV['BRANCH']}"; db.empty? ? "rails_blog" : db %> + +sqlite3: &sqlite3 +<% if defined?(JRuby) %> + adapter: jdbcsqlite3 +<% else %> + adapter: sqlite3 +<% end %> + database: db/all.sqlite3 + pool: 5 + timeout: 5000 + host: localhost + +development: + <<: *sqlite3 + +test: + <<: *sqlite3 + +production: + <<: *sqlite3 diff --git a/test/environments/rails71/config/environment.rb b/test/environments/rails71/config/environment.rb new file mode 100644 index 0000000000..d0c0782949 --- /dev/null +++ b/test/environments/rails71/config/environment.rb @@ -0,0 +1,9 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +# Load the Rails application. +require_relative 'application' + +# Initialize the Rails application. +Rails.application.initialize! diff --git a/test/environments/rails71/config/initializers/test.rb b/test/environments/rails71/config/initializers/test.rb new file mode 100644 index 0000000000..9981aac1a3 --- /dev/null +++ b/test/environments/rails71/config/initializers/test.rb @@ -0,0 +1,20 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +require 'new_relic/agent/method_tracer' + +class Bloodhound < ActiveRecord::Base + include ::NewRelic::Agent::MethodTracer + + def sniff + puts 'When a bloodhound sniffs a scent article (a piece of clothing or item touched only by the subject), ' \ + "air rushes through its nasal cavity and chemical vapors — or odors — lodge in the mucus and bombard the dog's " \ + 'scent receptors. ' \ + 'Source: https://www.pbs.org/wnet/nature/underdogs-the-bloodhounds-amazing-sense-of-smell/350/' + end + + add_method_tracer :sniff +end + +Rails.application.config.active_record.timestamped_migrations = false diff --git a/test/environments/rails71/db/schema.rb b/test/environments/rails71/db/schema.rb new file mode 100644 index 0000000000..2d964da716 --- /dev/null +++ b/test/environments/rails71/db/schema.rb @@ -0,0 +1,5 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +# File is required to exist by Rails From 8ea9cef0132f714ee5ef7e146ed6090800edd2b0 Mon Sep 17 00:00:00 2001 From: fallwith Date: Mon, 8 Jul 2024 16:29:36 -0700 Subject: [PATCH 060/109] have the Rails v7.1 test app use v7.1 defaults v7.0 copy/paste fix: use v7.1 defaults with Rails v7.1 --- test/environments/rails71/config/application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/environments/rails71/config/application.rb b/test/environments/rails71/config/application.rb index 32278ee1b4..df9629d77f 100644 --- a/test/environments/rails71/config/application.rb +++ b/test/environments/rails71/config/application.rb @@ -13,7 +13,7 @@ module RpmTestApp class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. - config.load_defaults(7.0) + config.load_defaults(7.1) config.eager_load = false config.filter_parameters += [:password] end From 389f1fbb9c3fbd9835eb67298b76e65bc83b09c5 Mon Sep 17 00:00:00 2001 From: fallwith Date: Tue, 9 Jul 2024 10:13:07 -0700 Subject: [PATCH 061/109] CI: test with Ruby v3.3.4 v3.3.3 -> v3.3.4 --- .github/versions.yml | 4 ++-- .github/workflows/ci.yml | 18 +++++++++--------- .github/workflows/ci_cron.yml | 16 ++++++++-------- .github/workflows/ci_jruby.yml | 4 ++-- .github/workflows/config_docs.yml | 2 +- .github/workflows/performance_tests.yml | 2 +- .github/workflows/prerelease.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/release_notes.yml | 2 +- .github/workflows/release_pr.yml | 2 +- .github/workflows/slack_notifications.yml | 4 ++-- 11 files changed, 29 insertions(+), 29 deletions(-) diff --git a/.github/versions.yml b/.github/versions.yml index 2f3e96cac2..57decf9bc4 100644 --- a/.github/versions.yml +++ b/.github/versions.yml @@ -1,8 +1,8 @@ --- # This file is consumed by lib/tasks/gha.rake ruby/setup-ruby: - :tag: v1.184.0 - :sha: 97e35c5302afcf3f5ac1df3fca9343d32536b286 + :tag: v1.186.0 + :sha: 2a9a743e19810b9f3c38060637daf594dbd7b37f actions/checkout: :tag: v4.1.2 :sha: 9bb56186c3b09b4f86b1c65136769dd318469633 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 098298b973..f752a2dfae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: - name: Configure git run: 'git config --global init.defaultBranch main' - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 - - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: '3.3' - run: bundle @@ -36,7 +36,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: [2.4.10, 3.3.3] + ruby-version: [2.4.10, 3.3.4] steps: - name: Configure git run: 'git config --global init.defaultBranch main' @@ -49,7 +49,7 @@ jobs: run: sudo apt-get update; sudo apt-get install -y --no-install-recommends libcurl4-nss-dev libsasl2-dev libxslt1-dev - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -62,7 +62,7 @@ jobs: "2.4.10": { "rails": "norails,rails42,rails52" }, - "3.3.3": { + "3.3.4": { "rails": "norails,rails61,rails71" } } @@ -190,7 +190,7 @@ jobs: fail-fast: false matrix: multiverse: [agent, ai, background, background_2, database, frameworks, httpclients, httpclients_2, rails, rest] - ruby-version: [2.4.10, 3.3.3] + ruby-version: [2.4.10, 3.3.4] steps: - name: Configure git @@ -204,7 +204,7 @@ jobs: run: sudo apt-get update; sudo apt-get install -y --no-install-recommends libcurl4-nss-dev libsasl2-dev libxslt1-dev - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -290,14 +290,14 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: [2.7.8, 3.3.3] + ruby-version: [2.7.8, 3.3.4] steps: - name: Configure git run: 'git config --global init.defaultBranch main' - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -337,7 +337,7 @@ jobs: - name: Configure git run: 'git config --global init.defaultBranch main' - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 - - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: '3.3' - run: bundle diff --git a/.github/workflows/ci_cron.yml b/.github/workflows/ci_cron.yml index a24a9a3b5b..2e1636cc56 100644 --- a/.github/workflows/ci_cron.yml +++ b/.github/workflows/ci_cron.yml @@ -16,7 +16,7 @@ jobs: - name: Configure git run: 'git config --global init.defaultBranch main' - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 - - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: '3.3' - run: bundle @@ -36,7 +36,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: [2.4.10, 2.5.9, 2.6.10, 2.7.8, 3.0.7, 3.1.6, 3.2.4, 3.3.3, 3.4.0-preview1] + ruby-version: [2.4.10, 2.5.9, 2.6.10, 2.7.8, 3.0.7, 3.1.6, 3.2.4, 3.3.4, 3.4.0-preview1] steps: - name: Configure git @@ -50,7 +50,7 @@ jobs: run: sudo apt-get update; sudo apt-get install -y --no-install-recommends libcurl4-nss-dev libsasl2-dev libxslt1-dev - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -81,7 +81,7 @@ jobs: "3.2.4": { "rails": "norails,rails61,rails70,rails71" }, - "3.3.3": { + "3.3.4": { "rails": "norails,rails61,rails70,rails71" }, "3.4.0-preview1": { @@ -203,7 +203,7 @@ jobs: fail-fast: false matrix: multiverse: [agent, ai, background, background_2, database, frameworks, httpclients, httpclients_2, rails, rest] - ruby-version: [2.4.10, 2.5.9, 2.6.10, 2.7.8, 3.0.7, 3.1.6, 3.2.4, 3.3.3, 3.4.0-preview1] + ruby-version: [2.4.10, 2.5.9, 2.6.10, 2.7.8, 3.0.7, 3.1.6, 3.2.4, 3.3.4, 3.4.0-preview1] steps: - name: Configure git run: 'git config --global init.defaultBranch main' @@ -216,7 +216,7 @@ jobs: run: sudo apt-get update; sudo apt-get install -y --no-install-recommends libcurl4-nss-dev libsasl2-dev libxslt1-dev - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -281,14 +281,14 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: [2.7.8, 3.0.7, 3.1.6, 3.2.4, 3.3.3, 3.4.0-preview1] + ruby-version: [2.7.8, 3.0.7, 3.1.6, 3.2.4, 3.3.4, 3.4.0-preview1] steps: - name: Configure git run: 'git config --global init.defaultBranch main' - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: ${{ matrix.ruby-version }} diff --git a/.github/workflows/ci_jruby.yml b/.github/workflows/ci_jruby.yml index 0dc1ac362a..1d592b4607 100644 --- a/.github/workflows/ci_jruby.yml +++ b/.github/workflows/ci_jruby.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 - name: Install JRuby - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: jruby-9.4.8.0 @@ -49,7 +49,7 @@ jobs: uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 - name: Install JRuby - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: jruby-9.4.8.0 diff --git a/.github/workflows/config_docs.yml b/.github/workflows/config_docs.yml index bdd63a8639..37d9ecce52 100644 --- a/.github/workflows/config_docs.yml +++ b/.github/workflows/config_docs.yml @@ -15,7 +15,7 @@ jobs: pull-requests: write steps: - name: Install Ruby 3.3 - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: 3.3 diff --git a/.github/workflows/performance_tests.yml b/.github/workflows/performance_tests.yml index 6835edcfdc..d46f7c6067 100644 --- a/.github/workflows/performance_tests.yml +++ b/.github/workflows/performance_tests.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 with: ref: 'main' - - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: '3.3' - run: bundle diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 99a3c62b0d..eed97976e5 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -11,7 +11,7 @@ jobs: pull-requests: write steps: - name: Install Ruby 3.3 - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: 3.3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1f2cb82645..d545e12231 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,7 @@ jobs: with: fetch-depth: 0 - - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: 3.3 diff --git a/.github/workflows/release_notes.yml b/.github/workflows/release_notes.yml index 054d8fd03e..f2ab5c1b75 100644 --- a/.github/workflows/release_notes.yml +++ b/.github/workflows/release_notes.yml @@ -13,7 +13,7 @@ jobs: contents: write pull-requests: write steps: - - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: 3.3 - name: Checkout code diff --git a/.github/workflows/release_pr.yml b/.github/workflows/release_pr.yml index 22019cfa3e..75046b3856 100644 --- a/.github/workflows/release_pr.yml +++ b/.github/workflows/release_pr.yml @@ -14,7 +14,7 @@ jobs: pull-requests: write steps: - name: Install Ruby 3.3 - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: 3.3 diff --git a/.github/workflows/slack_notifications.yml b/.github/workflows/slack_notifications.yml index db9ab0617d..ba1a28f672 100644 --- a/.github/workflows/slack_notifications.yml +++ b/.github/workflows/slack_notifications.yml @@ -8,7 +8,7 @@ jobs: gem_notifications: runs-on: ubuntu-22.04 steps: - - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: 3.3 - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 @@ -46,7 +46,7 @@ jobs: cve_notifications: runs-on: ubuntu-22.04 steps: - - uses: ruby/setup-ruby@97e35c5302afcf3f5ac1df3fca9343d32536b286 # tag v1.184.0 + - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 with: ruby-version: 3.3 - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 From 92f869e6bd1e1aafa98700aefec33d1ce4f35706 Mon Sep 17 00:00:00 2001 From: fallwith Date: Tue, 9 Jul 2024 15:59:42 -0700 Subject: [PATCH 062/109] Introduce Rails v7.2 test environment Start CI testing against Rails v7.2 (in beta currently), which requires Ruby v3.1+ --- .github/workflows/ci.yml | 2 +- .github/workflows/ci_cron.yml | 8 ++--- test/environments/rails72/Gemfile | 34 +++++++++++++++++++ test/environments/rails72/Rakefile | 17 ++++++++++ .../rails72/app/assets/config/manifest.js | 0 .../app/controllers/application_controller.rb | 6 ++++ .../app/controllers/no_method_controller.rb | 7 ++++ .../rails72/config/application.rb | 20 +++++++++++ test/environments/rails72/config/boot.rb | 8 +++++ test/environments/rails72/config/database.yml | 30 ++++++++++++++++ .../rails72/config/environment.rb | 9 +++++ .../rails72/config/initializers/test.rb | 20 +++++++++++ test/environments/rails72/db/schema.rb | 5 +++ 13 files changed, 161 insertions(+), 5 deletions(-) create mode 100644 test/environments/rails72/Gemfile create mode 100644 test/environments/rails72/Rakefile create mode 100644 test/environments/rails72/app/assets/config/manifest.js create mode 100644 test/environments/rails72/app/controllers/application_controller.rb create mode 100644 test/environments/rails72/app/controllers/no_method_controller.rb create mode 100644 test/environments/rails72/config/application.rb create mode 100644 test/environments/rails72/config/boot.rb create mode 100644 test/environments/rails72/config/database.yml create mode 100644 test/environments/rails72/config/environment.rb create mode 100644 test/environments/rails72/config/initializers/test.rb create mode 100644 test/environments/rails72/db/schema.rb diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f752a2dfae..2260625d45 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,7 +63,7 @@ jobs: "rails": "norails,rails42,rails52" }, "3.3.4": { - "rails": "norails,rails61,rails71" + "rails": "norails,rails61,rails72" } } diff --git a/.github/workflows/ci_cron.yml b/.github/workflows/ci_cron.yml index 2e1636cc56..33834fb560 100644 --- a/.github/workflows/ci_cron.yml +++ b/.github/workflows/ci_cron.yml @@ -76,16 +76,16 @@ jobs: "rails": "norails,rails61,rails60,rails70,rails71" }, "3.1.6": { - "rails": "norails,rails61,rails70,rails71" + "rails": "norails,rails61,rails70,rails71,rails72" }, "3.2.4": { - "rails": "norails,rails61,rails70,rails71" + "rails": "norails,rails61,rails70,rails71,rails72" }, "3.3.4": { - "rails": "norails,rails61,rails70,rails71" + "rails": "norails,rails61,rails70,rails71,rails72" }, "3.4.0-preview1": { - "rails": "norails,rails61,rails70,rails71" + "rails": "norails,rails61,rails70,rails71,rails72" } } diff --git a/test/environments/rails72/Gemfile b/test/environments/rails72/Gemfile new file mode 100644 index 0000000000..24c6e38afe --- /dev/null +++ b/test/environments/rails72/Gemfile @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gem 'rails', '~> 7.2.0.beta2' +gem 'bootsnap', '>= 1.4.4', require: false + +gem 'minitest', '5.2.3' +gem 'minitest-stub-const', '~> 0.6' +gem 'mocha', '~> 1.16', require: false + +platforms :ruby, :rbx do + gem 'mysql2', '>= 0.5.4' + gem 'sqlite3', '~> 1.4' +end + +gem 'newrelic_rpm', path: '../../..' + +group :development do + if ENV['ENABLE_PRY'] + gem 'pry', '~> 0.9.12' + gem 'pry-nav' + end +end + +gem 'simplecov' if ENV['VERBOSE_TEST_OUTPUT'] +gem 'warning' + +if RUBY_VERSION.split('.')[0..1].join('.').to_f >= 3.4 + gem 'base64' + gem 'bigdecimal' + gem 'mutex_m' + gem 'ostruct' +end diff --git a/test/environments/rails72/Rakefile b/test/environments/rails72/Rakefile new file mode 100644 index 0000000000..8c74a5a9a9 --- /dev/null +++ b/test/environments/rails72/Rakefile @@ -0,0 +1,17 @@ +# This file is distributed under new relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/license for complete details. +# frozen_string_literal: true + +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require_relative '../../warning_test_helper' + +require_relative 'config/application' + +Rails.application.load_tasks + +require 'tasks/all' + +Rake::Task['default'].clear +task :default => [:'test:newrelic'] diff --git a/test/environments/rails72/app/assets/config/manifest.js b/test/environments/rails72/app/assets/config/manifest.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/environments/rails72/app/controllers/application_controller.rb b/test/environments/rails72/app/controllers/application_controller.rb new file mode 100644 index 0000000000..612314dd94 --- /dev/null +++ b/test/environments/rails72/app/controllers/application_controller.rb @@ -0,0 +1,6 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +class ApplicationController < ActionController::Base +end diff --git a/test/environments/rails72/app/controllers/no_method_controller.rb b/test/environments/rails72/app/controllers/no_method_controller.rb new file mode 100644 index 0000000000..70a729db3f --- /dev/null +++ b/test/environments/rails72/app/controllers/no_method_controller.rb @@ -0,0 +1,7 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +require_relative 'application_controller' + +class NoMethodController < ApplicationController; end diff --git a/test/environments/rails72/config/application.rb b/test/environments/rails72/config/application.rb new file mode 100644 index 0000000000..a5d6c01a28 --- /dev/null +++ b/test/environments/rails72/config/application.rb @@ -0,0 +1,20 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +require_relative 'boot' + +require 'rails/all' + +# Require the gems listed in Gemfile, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(*Rails.groups) + +module RpmTestApp + class Application < Rails::Application + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults(7.2) + config.eager_load = false + config.filter_parameters += [:password] + end +end diff --git a/test/environments/rails72/config/boot.rb b/test/environments/rails72/config/boot.rb new file mode 100644 index 0000000000..a8d25cb53d --- /dev/null +++ b/test/environments/rails72/config/boot.rb @@ -0,0 +1,8 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) + +require 'bundler/setup' # Set up gems listed in the Gemfile. +require 'bootsnap/setup' # Speed up boot time by caching expensive operations. diff --git a/test/environments/rails72/config/database.yml b/test/environments/rails72/config/database.yml new file mode 100644 index 0000000000..5e490dbd99 --- /dev/null +++ b/test/environments/rails72/config/database.yml @@ -0,0 +1,30 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +mysql: &mysql + adapter: mysql2 + username: root + password: <%= ENV['MYSQL_PASSWORD'] %> + host: localhost + database: <%= db = "#{ENV['RUBY_VERSION']}#{ENV['BRANCH']}"; db.empty? ? "rails_blog" : db %> + +sqlite3: &sqlite3 +<% if defined?(JRuby) %> + adapter: jdbcsqlite3 +<% else %> + adapter: sqlite3 +<% end %> + database: db/all.sqlite3 + pool: 5 + timeout: 5000 + host: localhost + +development: + <<: *sqlite3 + +test: + <<: *sqlite3 + +production: + <<: *sqlite3 diff --git a/test/environments/rails72/config/environment.rb b/test/environments/rails72/config/environment.rb new file mode 100644 index 0000000000..d0c0782949 --- /dev/null +++ b/test/environments/rails72/config/environment.rb @@ -0,0 +1,9 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +# Load the Rails application. +require_relative 'application' + +# Initialize the Rails application. +Rails.application.initialize! diff --git a/test/environments/rails72/config/initializers/test.rb b/test/environments/rails72/config/initializers/test.rb new file mode 100644 index 0000000000..9981aac1a3 --- /dev/null +++ b/test/environments/rails72/config/initializers/test.rb @@ -0,0 +1,20 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +require 'new_relic/agent/method_tracer' + +class Bloodhound < ActiveRecord::Base + include ::NewRelic::Agent::MethodTracer + + def sniff + puts 'When a bloodhound sniffs a scent article (a piece of clothing or item touched only by the subject), ' \ + "air rushes through its nasal cavity and chemical vapors — or odors — lodge in the mucus and bombard the dog's " \ + 'scent receptors. ' \ + 'Source: https://www.pbs.org/wnet/nature/underdogs-the-bloodhounds-amazing-sense-of-smell/350/' + end + + add_method_tracer :sniff +end + +Rails.application.config.active_record.timestamped_migrations = false diff --git a/test/environments/rails72/db/schema.rb b/test/environments/rails72/db/schema.rb new file mode 100644 index 0000000000..2d964da716 --- /dev/null +++ b/test/environments/rails72/db/schema.rb @@ -0,0 +1,5 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +# File is required to exist by Rails From fe3a29b61ff4687d38c7e80b728955d5aa68a750 Mon Sep 17 00:00:00 2001 From: Tanna McClure Date: Wed, 10 Jul 2024 10:36:09 -0500 Subject: [PATCH 063/109] update to only try to get cluster name once per client instance --- .../agent/instrumentation/elasticsearch/instrumentation.rb | 2 +- .../elasticsearch/elasticsearch_instrumentation_test.rb | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb b/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb index ba91aea6b4..74b42642de 100644 --- a/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb +++ b/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb @@ -102,7 +102,7 @@ def nr_reported_query(query) end def nr_cluster_name - return @nr_cluster_name if @nr_cluster_name + return @nr_cluster_name if defined?(@nr_cluster_name) return if nr_hosts.empty? NewRelic::Agent.disable_all_tracing do diff --git a/test/multiverse/suites/elasticsearch/elasticsearch_instrumentation_test.rb b/test/multiverse/suites/elasticsearch/elasticsearch_instrumentation_test.rb index 1427f0dd6c..a57061089f 100644 --- a/test/multiverse/suites/elasticsearch/elasticsearch_instrumentation_test.rb +++ b/test/multiverse/suites/elasticsearch/elasticsearch_instrumentation_test.rb @@ -102,6 +102,13 @@ def test_segment_database_name assert_equal 'docker-cluster', @segment.database_name end + def test_cluster_name_not_captured_if_defined_but_nil + @client.instance_variable_set(:@nr_cluster_name, nil) + search + + assert_nil @segment.database_name + end + def test_nosql_statement_recorded_params_obfuscated with_config(:'elasticsearch.obfuscate_queries' => true) do txn = in_transaction do From ab384a7129d76d8f742c9e10de12beea6efc5704 Mon Sep 17 00:00:00 2001 From: fallwith Date: Wed, 10 Jul 2024 12:04:39 -0700 Subject: [PATCH 064/109] ActiveJob tests: disable test adapter For agent testing, we want Rails to behave in a production-like context so disable all test adapter functionality for Active Job --- .../agent/instrumentation/rails/active_job_subscriber.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb b/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb index 8cdfbe51ae..57cd2f5f13 100644 --- a/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb +++ b/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb @@ -30,6 +30,11 @@ class ActiveJobSubscriberTest < Minitest::Test ID = 71741 SUBSCRIBER = NewRelic::Agent::Instrumentation::ActiveJobSubscriber.new + def setup + # https://github.com/rails/rails/issues/37270 + (ActiveJob::Base.descendants << ActiveJob::Base).each(&:disable_test_adapter) + end + def test_segment_naming_with_unknown_method assert_equal 'Ruby/ActiveJob/default/Unknown', SUBSCRIBER.send(:metric_name, 'indecipherable', {job: TestJob.new}) From a8b153f2637b9179a4a0514a4b7719151a7ec91b Mon Sep 17 00:00:00 2001 From: Tanna McClure Date: Wed, 10 Jul 2024 14:10:14 -0500 Subject: [PATCH 065/109] change the way we create error object because options changed --- .../suites/httpx/httpx_instrumentation_test.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/multiverse/suites/httpx/httpx_instrumentation_test.rb b/test/multiverse/suites/httpx/httpx_instrumentation_test.rb index 1190e924ee..ddefbd430f 100644 --- a/test/multiverse/suites/httpx/httpx_instrumentation_test.rb +++ b/test/multiverse/suites/httpx/httpx_instrumentation_test.rb @@ -33,7 +33,15 @@ def test_finish_with_error request = Minitest::Mock.new request.expect :response, :the_response 2.times { request.expect :hash, 1138 } - responses = {request => ::HTTPX::ErrorResponse.new(request, StandardError.new, {})} + + error = if Gem::Version.new(::HTTPX::VERSION) >= Gem::Version.new('1.3.0') + request.expect :options, ::HTTPX::Options.new({}) + ::HTTPX::ErrorResponse.new(request, StandardError.new) + else + ::HTTPX::ErrorResponse.new(request, StandardError.new, {}) + end + responses = {request => error} + segment = Minitest::Mock.new def segment.notice_error(_error); end def segment.process_response_headers(_wrappep); end From b7d9b15a925e07fd7c9570f3361869c3646674a3 Mon Sep 17 00:00:00 2001 From: Tanna McClure Date: Wed, 10 Jul 2024 14:31:43 -0500 Subject: [PATCH 066/109] update test --- .../elasticsearch/elasticsearch_instrumentation_test.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/multiverse/suites/elasticsearch/elasticsearch_instrumentation_test.rb b/test/multiverse/suites/elasticsearch/elasticsearch_instrumentation_test.rb index a57061089f..33ea640617 100644 --- a/test/multiverse/suites/elasticsearch/elasticsearch_instrumentation_test.rb +++ b/test/multiverse/suites/elasticsearch/elasticsearch_instrumentation_test.rb @@ -102,9 +102,11 @@ def test_segment_database_name assert_equal 'docker-cluster', @segment.database_name end - def test_cluster_name_not_captured_if_defined_but_nil - @client.instance_variable_set(:@nr_cluster_name, nil) + def test_cluster_name_doesnt_try_again_if_defined_but_nil + original = @client.instance_variable_get(:@transport).instance_variable_get(:@nr_cluster_name) + @client.instance_variable_get(:@transport).instance_variable_set(:@nr_cluster_name, nil) search + @client.instance_variable_get(:@transport).instance_variable_set(:@nr_cluster_name, original) assert_nil @segment.database_name end From 94638d21b81a8017fe89c26725e90c2f5eab7e2f Mon Sep 17 00:00:00 2001 From: fallwith Date: Wed, 10 Jul 2024 12:34:37 -0700 Subject: [PATCH 067/109] ActiveJob tests: conditionally disable test adptr only call `disable_test_adapter` on objects that respond to it --- .../agent/instrumentation/rails/active_job_subscriber.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb b/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb index 57cd2f5f13..cc4dde5134 100644 --- a/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb +++ b/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb @@ -32,7 +32,9 @@ class ActiveJobSubscriberTest < Minitest::Test def setup # https://github.com/rails/rails/issues/37270 - (ActiveJob::Base.descendants << ActiveJob::Base).each(&:disable_test_adapter) + (ActiveJob::Base.descendants << ActiveJob::Base).each do |b| + b.disable_test_adapter if b.respond_to?(:disable_test_adapter) + end end def test_segment_naming_with_unknown_method From 84e727cce8904844e3ae00469030c8315f881e2b Mon Sep 17 00:00:00 2001 From: fallwith Date: Wed, 10 Jul 2024 12:51:50 -0700 Subject: [PATCH 068/109] ActiveJob tests: use `rescue nil` always attempt, don't worry about failures --- .../agent/instrumentation/rails/active_job_subscriber.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb b/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb index cc4dde5134..84d0fb1faf 100644 --- a/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb +++ b/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb @@ -32,9 +32,7 @@ class ActiveJobSubscriberTest < Minitest::Test def setup # https://github.com/rails/rails/issues/37270 - (ActiveJob::Base.descendants << ActiveJob::Base).each do |b| - b.disable_test_adapter if b.respond_to?(:disable_test_adapter) - end + (ActiveJob::Base.descendants << ActiveJob::Base).each { |b| b.disable_test_adapter rescue nil } end def test_segment_naming_with_unknown_method From 6f701a21f4e028dc90349d75969c35df1a223d5a Mon Sep 17 00:00:00 2001 From: fallwith Date: Wed, 10 Jul 2024 15:39:23 -0700 Subject: [PATCH 069/109] ActiveJob: permit TestAdapter don't fight Rails' test environment behavior. We care that the metric is there, not that Rails swapped out the adapter when under test --- .../instrumentation/rails/active_job_subscriber.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb b/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb index 84d0fb1faf..1b1f3ef529 100644 --- a/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb +++ b/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb @@ -30,11 +30,6 @@ class ActiveJobSubscriberTest < Minitest::Test ID = 71741 SUBSCRIBER = NewRelic::Agent::Instrumentation::ActiveJobSubscriber.new - def setup - # https://github.com/rails/rails/issues/37270 - (ActiveJob::Base.descendants << ActiveJob::Base).each { |b| b.disable_test_adapter rescue nil } - end - def test_segment_naming_with_unknown_method assert_equal 'Ruby/ActiveJob/default/Unknown', SUBSCRIBER.send(:metric_name, 'indecipherable', {job: TestJob.new}) @@ -112,7 +107,12 @@ def validate_transaction(txn, methods = []) segment = segments.detect { |s| s.name == "Ruby/ActiveJob/default/#{method}" } assert segment - assert_equal 'ActiveJob::QueueAdapters::AsyncAdapter', segment.params[:adapter].class.name + + if defined?(Rails) && Rails.respond_to?(:version) && Gem::Version.new(Rails.version) >= Gem::Version.new('7.1') + assert_matches(/ActiveJob::QueueAdapters::(?:Test|Async)Adapter/, segment.params[:adapter].class.name) + else + assert_equal 'ActiveJob::QueueAdapters::AsyncAdapter', segment.params[:adapter].class.name + end end end end From e3911624f3e474104137b25618398e7f684bea3a Mon Sep 17 00:00:00 2001 From: fallwith Date: Wed, 10 Jul 2024 16:07:34 -0700 Subject: [PATCH 070/109] assert_match typo fix --- .../agent/instrumentation/rails/active_job_subscriber.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb b/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb index 1b1f3ef529..dbb637f7fd 100644 --- a/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb +++ b/test/new_relic/agent/instrumentation/rails/active_job_subscriber.rb @@ -109,7 +109,7 @@ def validate_transaction(txn, methods = []) assert segment if defined?(Rails) && Rails.respond_to?(:version) && Gem::Version.new(Rails.version) >= Gem::Version.new('7.1') - assert_matches(/ActiveJob::QueueAdapters::(?:Test|Async)Adapter/, segment.params[:adapter].class.name) + assert_match(/ActiveJob::QueueAdapters::(?:Test|Async)Adapter/, segment.params[:adapter].class.name) else assert_equal 'ActiveJob::QueueAdapters::AsyncAdapter', segment.params[:adapter].class.name end From 0008a949d058efc4307c5151125ba117b4efb6a2 Mon Sep 17 00:00:00 2001 From: prateek-ap Date: Thu, 11 Jul 2024 11:12:16 +0530 Subject: [PATCH 071/109] Update UTs for SecurityInterface --- test/new_relic/control/security_interface_test.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/new_relic/control/security_interface_test.rb b/test/new_relic/control/security_interface_test.rb index f1a77f3001..3997b39e42 100644 --- a/test/new_relic/control/security_interface_test.rb +++ b/test/new_relic/control/security_interface_test.rb @@ -30,6 +30,9 @@ def test_initialization_short_circuits_when_the_security_agent_is_disabled with_config('security.agent.enabled' => false, 'security.enabled' => true, 'high_security' => false) do NewRelic::Agent.stub :logger, logger do logger.expect :info, nil, [/Security is completely disabled/] + logger.expect :info, nil, [/high_security = false/] + logger.expect :info, nil, [/security.enabled = true/] + logger.expect :info, nil, [/security.agent.enabled = false/] NewRelic::Control::SecurityInterface.instance.init_agent end @@ -48,6 +51,9 @@ def test_initialization_short_circuits_when_the_security_is_disabled with_config('security.agent.enabled' => true, 'security.enabled' => false, 'high_security' => false) do NewRelic::Agent.stub :logger, logger do logger.expect :info, nil, [/Security is completely disabled/] + logger.expect :info, nil, [/high_security = false/] + logger.expect :info, nil, [/security.enabled = false/] + logger.expect :info, nil, [/security.agent.enabled = true/] NewRelic::Control::SecurityInterface.instance.init_agent end @@ -64,6 +70,9 @@ def test_initialization_short_circuits_when_high_security_mode_is_enabled with_config('security.agent.enabled' => true, 'security.enabled' => true, 'high_security' => true) do NewRelic::Agent.stub :logger, logger do logger.expect :info, nil, [/Security is completely disabled/] + logger.expect :info, nil, [/high_security = true/] + logger.expect :info, nil, [/security.enabled = true/] + logger.expect :info, nil, [/security.agent.enabled = true/] NewRelic::Control::SecurityInterface.instance.init_agent end From 49c220a7d2c61ef843ef7053f9058f505f499490 Mon Sep 17 00:00:00 2001 From: Hannah Ramadan <76922290+hannahramadan@users.noreply.github.com> Date: Thu, 11 Jul 2024 09:40:08 -0700 Subject: [PATCH 072/109] Logstasher instrumentation (#2559) * Add LogStasher instrumentation --------- Co-authored-by: fallwith Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- CHANGELOG.md | 5 +- .../agent/configuration/default_source.rb | 9 + .../agent/instrumentation/logstasher.rb | 27 +++ .../agent/instrumentation/logstasher/chain.rb | 21 +++ .../logstasher/instrumentation.rb | 24 +++ .../instrumentation/logstasher/prepend.rb | 13 ++ lib/new_relic/agent/local_log_decorator.rb | 9 +- lib/new_relic/agent/log_event_aggregator.rb | 117 +++++++++--- test/multiverse/suites/logstasher/Envfile | 19 ++ .../suites/logstasher/config/newrelic.yml | 22 +++ .../logstasher_instrumentation_test.rb | 131 +++++++++++++ .../agent/local_log_decorator_test.rb | 31 +++- .../agent/log_event_aggregator_test.rb | 172 ++++++++++++++++++ 13 files changed, 571 insertions(+), 29 deletions(-) create mode 100644 lib/new_relic/agent/instrumentation/logstasher.rb create mode 100644 lib/new_relic/agent/instrumentation/logstasher/chain.rb create mode 100644 lib/new_relic/agent/instrumentation/logstasher/instrumentation.rb create mode 100644 lib/new_relic/agent/instrumentation/logstasher/prepend.rb create mode 100644 test/multiverse/suites/logstasher/Envfile create mode 100644 test/multiverse/suites/logstasher/config/newrelic.yml create mode 100644 test/multiverse/suites/logstasher/logstasher_instrumentation_test.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index e03e3effcb..5d6ba7217b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,11 @@ # New Relic Ruby Agent Release Notes ## +Version introduces instrumentation for the LogStasher gem and improves instrumentation for the `redis-clustering` gem. -Version improves instrumentation for the `redis-clustering` gem. +- **Feature: Add instrumentation for LogStasher** + + The agent will now record logs generated by [LogStasher](https://github.com/shadabahmed/logstasher). Versions 1.0.0 and above of the LogStasher gem are supported. [PR#2559](https://github.com/newrelic/newrelic-ruby-agent/pull/2559) - **Feature: Add instrumentation for redis-clustering** diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index 2721d8cd8b..3de2b00e4e 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -1636,6 +1636,15 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :allowed_from_server => false, :description => 'Controls auto-instrumentation of Ruby standard library Logger at start-up. May be one of: `auto`, `prepend`, `chain`, `disabled`.' }, + :'instrumentation.logstasher' => { + :default => instrumentation_value_from_boolean(:'application_logging.enabled'), + :documentation_default => 'auto', + :public => true, + :type => String, + :dynamic_name => true, + :allowed_from_server => false, + :description => 'Controls auto-instrumentation of the LogStasher library at start-up. May be one of [auto|prepend|chain|disabled].' + }, :'instrumentation.memcache' => { :default => 'auto', :documentation_default => 'auto', diff --git a/lib/new_relic/agent/instrumentation/logstasher.rb b/lib/new_relic/agent/instrumentation/logstasher.rb new file mode 100644 index 0000000000..2799996e5e --- /dev/null +++ b/lib/new_relic/agent/instrumentation/logstasher.rb @@ -0,0 +1,27 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +require_relative 'logstasher/instrumentation' +require_relative 'logstasher/chain' +require_relative 'logstasher/prepend' + +DependencyDetection.defer do + named :logstasher + + depends_on do + defined?(LogStasher) && + Gem::Version.new(LogStasher::VERSION) >= Gem::Version.new('1.0.0') && + NewRelic::Agent.config[:'application_logging.enabled'] + end + + executes do + NewRelic::Agent.logger.info('Installing LogStasher instrumentation') + + if use_prepend? + prepend_instrument LogStasher.singleton_class, NewRelic::Agent::Instrumentation::LogStasher::Prepend + else + chain_instrument NewRelic::Agent::Instrumentation::LogStasher::Chain + end + end +end diff --git a/lib/new_relic/agent/instrumentation/logstasher/chain.rb b/lib/new_relic/agent/instrumentation/logstasher/chain.rb new file mode 100644 index 0000000000..9dc6e59017 --- /dev/null +++ b/lib/new_relic/agent/instrumentation/logstasher/chain.rb @@ -0,0 +1,21 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +module NewRelic::Agent::Instrumentation + module LogStasher::Chain + def self.instrument! + ::LogStasher.singleton_class.class_eval do + include NewRelic::Agent::Instrumentation::LogStasher + + alias_method(:build_logstash_event_without_new_relic, :build_logstash_event) + + def build_logstash_event(*args) + build_logstash_event_with_new_relic(*args) do + build_logstash_event_without_new_relic(*args) + end + end + end + end + end +end diff --git a/lib/new_relic/agent/instrumentation/logstasher/instrumentation.rb b/lib/new_relic/agent/instrumentation/logstasher/instrumentation.rb new file mode 100644 index 0000000000..ca0fce5215 --- /dev/null +++ b/lib/new_relic/agent/instrumentation/logstasher/instrumentation.rb @@ -0,0 +1,24 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +module NewRelic::Agent::Instrumentation + module LogStasher + INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name) + + def self.enabled? + NewRelic::Agent.config[:'instrumentation.logstasher'] != 'disabled' + end + + def build_logstash_event_with_new_relic(*args) + logstasher_event = yield + log = logstasher_event.instance_variable_get(:@data) + + ::NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME) + ::NewRelic::Agent.agent.log_event_aggregator.record_logstasher_event(log) + ::NewRelic::Agent::LocalLogDecorator.decorate(log) + + logstasher_event + end + end +end diff --git a/lib/new_relic/agent/instrumentation/logstasher/prepend.rb b/lib/new_relic/agent/instrumentation/logstasher/prepend.rb new file mode 100644 index 0000000000..504022afd4 --- /dev/null +++ b/lib/new_relic/agent/instrumentation/logstasher/prepend.rb @@ -0,0 +1,13 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +module NewRelic::Agent::Instrumentation + module LogStasher::Prepend + include NewRelic::Agent::Instrumentation::LogStasher + + def build_logstash_event(*args) + build_logstash_event_with_new_relic(*args) { super } + end + end +end diff --git a/lib/new_relic/agent/local_log_decorator.rb b/lib/new_relic/agent/local_log_decorator.rb index 257868346c..e5a5abe60e 100644 --- a/lib/new_relic/agent/local_log_decorator.rb +++ b/lib/new_relic/agent/local_log_decorator.rb @@ -12,6 +12,12 @@ def decorate(message) return message unless decorating_enabled? metadata = NewRelic::Agent.linking_metadata + + if message.is_a?(Hash) + message.merge!(metadata) unless message.frozen? + return + end + formatted_metadata = " NR-LINKING|#{metadata[ENTITY_GUID_KEY]}|#{metadata[HOSTNAME_KEY]}|" \ "#{metadata[TRACE_ID_KEY]}|#{metadata[SPAN_ID_KEY]}|" \ "#{escape_entity_name(metadata[ENTITY_NAME_KEY])}|" @@ -23,7 +29,8 @@ def decorate(message) def decorating_enabled? NewRelic::Agent.config[:'application_logging.enabled'] && - NewRelic::Agent::Instrumentation::Logger.enabled? && + (NewRelic::Agent::Instrumentation::Logger.enabled? || + NewRelic::Agent::Instrumentation::LogStasher.enabled?) && NewRelic::Agent.config[:'application_logging.local_decorating.enabled'] end diff --git a/lib/new_relic/agent/log_event_aggregator.rb b/lib/new_relic/agent/log_event_aggregator.rb index ff31b07d4a..05c754308d 100644 --- a/lib/new_relic/agent/log_event_aggregator.rb +++ b/lib/new_relic/agent/log_event_aggregator.rb @@ -20,7 +20,8 @@ class LogEventAggregator < EventAggregator DROPPED_METRIC = 'Logging/Forwarding/Dropped'.freeze SEEN_METRIC = 'Supportability/Logging/Forwarding/Seen'.freeze SENT_METRIC = 'Supportability/Logging/Forwarding/Sent'.freeze - OVERALL_SUPPORTABILITY_FORMAT = 'Supportability/Logging/Ruby/Logger/%s'.freeze + LOGGER_SUPPORTABILITY_FORMAT = 'Supportability/Logging/Ruby/Logger/%s'.freeze + LOGSTASHER_SUPPORTABILITY_FORMAT = 'Supportability/Logging/Ruby/LogStasher/%s'.freeze METRICS_SUPPORTABILITY_FORMAT = 'Supportability/Logging/Metrics/Ruby/%s'.freeze FORWARDING_SUPPORTABILITY_FORMAT = 'Supportability/Logging/Forwarding/Ruby/%s'.freeze DECORATING_SUPPORTABILITY_FORMAT = 'Supportability/Logging/LocalDecorating/Ruby/%s'.freeze @@ -58,38 +59,71 @@ def capacity end def record(formatted_message, severity) - return unless enabled? + return unless logger_enabled? severity = 'UNKNOWN' if severity.nil? || severity.empty? + increment_event_counters(severity) + + return if formatted_message.nil? || formatted_message.empty? + return unless monitoring_conditions_met?(severity) + + txn = NewRelic::Agent::Transaction.tl_current + priority = LogPriority.priority_for(txn) - if NewRelic::Agent.config[METRICS_ENABLED_KEY] - @counter_lock.synchronize do - @seen += 1 - @seen_by_severity[severity] += 1 + return txn.add_log_event(create_event(priority, formatted_message, severity)) if txn + + @lock.synchronize do + @buffer.append(priority: priority) do + create_event(priority, formatted_message, severity) end end + rescue + nil + end - return if severity_too_low?(severity) - return if formatted_message.nil? || formatted_message.empty? - return unless NewRelic::Agent.config[FORWARDING_ENABLED_KEY] - return if @high_security + def record_logstasher_event(log) + return unless logstasher_enabled? + + # LogStasher logs do not inherently include a message key, so most logs are recorded. + # But when the key exists, we should not record the log if the message value is nil or empty. + return if log.key?('message') && (log['message'].nil? || log['message'].empty?) + + severity = determine_severity(log) + increment_event_counters(severity) + + return unless monitoring_conditions_met?(severity) txn = NewRelic::Agent::Transaction.tl_current priority = LogPriority.priority_for(txn) - if txn - return txn.add_log_event(create_event(priority, formatted_message, severity)) - else - return @lock.synchronize do - @buffer.append(priority: priority) do - create_event(priority, formatted_message, severity) - end + return txn.add_log_event(create_logstasher_event(priority, severity, log)) if txn + + @lock.synchronize do + @buffer.append(priority: priority) do + create_logstasher_event(priority, severity, log) end end rescue nil end + def monitoring_conditions_met?(severity) + !severity_too_low?(severity) && NewRelic::Agent.config[FORWARDING_ENABLED_KEY] && !@high_security + end + + def determine_severity(log) + log['level'] ? log['level'].to_s.upcase : 'UNKNOWN' + end + + def increment_event_counters(severity) + return unless NewRelic::Agent.config[METRICS_ENABLED_KEY] + + @counter_lock.synchronize do + @seen += 1 + @seen_by_severity[severity] += 1 + end + end + def record_batch(txn, logs) # Ensure we have the same shared priority priority = LogPriority.priority_for(txn) @@ -104,15 +138,17 @@ def record_batch(txn, logs) end end - def create_event(priority, formatted_message, severity) - formatted_message = truncate_message(formatted_message) - - event = LinkingMetadata.append_trace_linking_metadata({ + def add_event_metadata(formatted_message, severity) + metadata = { LEVEL_KEY => severity, - MESSAGE_KEY => formatted_message, TIMESTAMP_KEY => Process.clock_gettime(Process::CLOCK_REALTIME) * 1000 - }) + } + metadata[MESSAGE_KEY] = formatted_message unless formatted_message.nil? + + LinkingMetadata.append_trace_linking_metadata(metadata) + end + def create_prioritized_event(priority, event) [ { PrioritySampledBuffer::PRIORITY_KEY => priority @@ -121,6 +157,31 @@ def create_event(priority, formatted_message, severity) ] end + def create_event(priority, formatted_message, severity) + formatted_message = truncate_message(formatted_message) + event = add_event_metadata(formatted_message, severity) + + create_prioritized_event(priority, event) + end + + def create_logstasher_event(priority, severity, log) + formatted_message = log['message'] ? truncate_message(log['message']) : nil + event = add_event_metadata(formatted_message, severity) + add_logstasher_event_attributes(event, log) + + create_prioritized_event(priority, event) + end + + def add_logstasher_event_attributes(event, log) + log_copy = log.dup + # Delete previously reported attributes + log_copy.delete('message') + log_copy.delete('level') + log_copy.delete('@timestamp') + + event['attributes'] = log_copy + end + def add_custom_attributes(custom_attributes) attributes.add_custom_attributes(custom_attributes) end @@ -166,10 +227,14 @@ def reset! super end - def enabled? + def logger_enabled? @enabled && @instrumentation_logger_enabled end + def logstasher_enabled? + @enabled && NewRelic::Agent::Instrumentation::LogStasher.enabled? + end + private # We record once-per-connect metrics for enabled/disabled state at the @@ -177,8 +242,8 @@ def enabled? def register_for_done_configuring(events) events.subscribe(:server_source_configuration_added) do @high_security = NewRelic::Agent.config[:high_security] - - record_configuration_metric(OVERALL_SUPPORTABILITY_FORMAT, OVERALL_ENABLED_KEY) + record_configuration_metric(LOGGER_SUPPORTABILITY_FORMAT, OVERALL_ENABLED_KEY) + record_configuration_metric(LOGSTASHER_SUPPORTABILITY_FORMAT, OVERALL_ENABLED_KEY) record_configuration_metric(METRICS_SUPPORTABILITY_FORMAT, METRICS_ENABLED_KEY) record_configuration_metric(FORWARDING_SUPPORTABILITY_FORMAT, FORWARDING_ENABLED_KEY) record_configuration_metric(DECORATING_SUPPORTABILITY_FORMAT, DECORATING_ENABLED_KEY) diff --git a/test/multiverse/suites/logstasher/Envfile b/test/multiverse/suites/logstasher/Envfile new file mode 100644 index 0000000000..ae515679de --- /dev/null +++ b/test/multiverse/suites/logstasher/Envfile @@ -0,0 +1,19 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +instrumentation_methods :chain, :prepend + +logstasher_versions = [ + [nil, 2.7] +] + +# Lock down activesupport version due to a logstasher test incompatiability with 7.1. +def gem_list(logstasher_versions = nil) + <<~RB + gem 'logstasher'#{logstasher_versions} + gem 'activesupport', '< 7.1' + RB +end + +create_gemfiles(logstasher_versions) diff --git a/test/multiverse/suites/logstasher/config/newrelic.yml b/test/multiverse/suites/logstasher/config/newrelic.yml new file mode 100644 index 0000000000..3c27a58cce --- /dev/null +++ b/test/multiverse/suites/logstasher/config/newrelic.yml @@ -0,0 +1,22 @@ +--- +development: + error_collector: + enabled: true + apdex_t: 0.5 + monitor_mode: true + license_key: bootstrap_newrelic_admin_license_key_000 + instrumentation: + logstasher: <%= $instrumentation_method %> + app_name: test + log_level: debug + host: 127.0.0.1 + api_host: 127.0.0.1 + transaction_trace: + record_sql: obfuscated + enabled: true + stack_trace_threshold: 0.5 + transaction_threshold: 1.0 + capture_params: false + application_logging: + forwarding: + enabled: true diff --git a/test/multiverse/suites/logstasher/logstasher_instrumentation_test.rb b/test/multiverse/suites/logstasher/logstasher_instrumentation_test.rb new file mode 100644 index 0000000000..9c1df1f06f --- /dev/null +++ b/test/multiverse/suites/logstasher/logstasher_instrumentation_test.rb @@ -0,0 +1,131 @@ +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. +# frozen_string_literal: true + +require 'ostruct' + +class LogStasherInstrumentationTest < Minitest::Test + include MultiverseHelpers + + def setup + @written = StringIO.new + + # Give LogStasher's setup method a new place to write logs to, as well as + # skip a config check, controller_monkey_patch, that otherwise causes an error + LogStasher.setup(OpenStruct.new(logger_path: @written, controller_monkey_patch: false)) + + # required for build_logstasher_event method + LogStasher.field_renaming = {} + @aggregator = NewRelic::Agent.agent.log_event_aggregator + + NewRelic::Agent.instance.stats_engine.reset! + NewRelic::Agent.instance.log_event_aggregator.reset! + end + + def teardown + NewRelic::Agent.instance.stats_engine.reset! + NewRelic::Agent.instance.log_event_aggregator.reset! + end + + def json_log_hash + { + :identifier => 'dinosaurs/_dinosaur.html.erb', + :name => 'render_partial.action_view', + :request_id => '01234-abcde-56789-fghij', + 'source' => '127.0.0.1', + 'tags' => [], + '@timestamp' => '2024-06-24T23:55:59.497Z' + } + end + + def test_level_is_recorded + in_transaction do + LogStasher.build_logstash_event({'level' => :info, 'message' => 'hi there'}, ['log']) + end + _, events = @aggregator.harvest! + + assert_equal 'INFO', events[0][1]['level'] + assert_metrics_recorded(%w[Logging/lines/INFO]) + end + + def test_logs_without_levels_are_unknown + in_transaction do + LogStasher.build_logstash_event(json_log_hash, ['log']) + end + _, events = @aggregator.harvest! + + assert_equal 'UNKNOWN', events[0][1]['level'] + assert_metrics_recorded(%w[Logging/lines/UNKNOWN]) + end + + def test_logs_without_messages_are_not_added + in_transaction do + LogStasher.build_logstash_event(json_log_hash, ['log']) + end + _, events = @aggregator.harvest! + + refute events[0][1]['message'] + end + + def test_attributes_added_to_payload + in_transaction do + LogStasher.build_logstash_event(json_log_hash, ['log']) + end + _, events = @aggregator.harvest! + + assert events[0][1]['attributes'].key?(:identifier) + assert events[0][1]['attributes'].key?(:name) + assert events[0][1]['attributes'].key?('source') + end + + def test_log_decorating_enabled_records_linking_metadata + with_config(:'application_logging.local_decorating.enabled' => true) do + in_transaction do + LogStasher.warn('yikes') + end + end + logfile = JSON.parse(@written.string) + + assert logfile.key?('entity.name') + assert logfile.key?('entity.type') + assert logfile.key?('hostname') + assert logfile.key?('trace.id') + assert logfile.key?('span.id') + end + + def test_log_decorating_disabled_doesnt_records_linking_metadata + with_config(:'application_logging.local_decorating.enabled' => false) do + in_transaction do + LogStasher.warn('yikes') + end + end + logfile = JSON.parse(@written.string) + + refute logfile.key?('entity.name') + refute logfile.key?('entity.type') + refute logfile.key?('hostname') + refute logfile.key?('trace.id') + refute logfile.key?('span.id') + end + + def test_no_instrumentation_when_disabled + with_config(:'instrumentation.logstasher' => 'disabled') do + LogStasher.warn('yikes') + end + _, events = @aggregator.harvest! + + assert_empty(events) + end + + def test_enabled_returns_false_when_disabled + with_config(:'instrumentation.logstasher' => 'disabled') do + refute_predicate NewRelic::Agent::Instrumentation::LogStasher, :enabled? + end + end + + def test_enabled_returns_true_when_enabled + with_config(:'instrumentation.logstasher' => 'auto') do + assert_predicate NewRelic::Agent::Instrumentation::LogStasher, :enabled? + end + end +end diff --git a/test/new_relic/agent/local_log_decorator_test.rb b/test/new_relic/agent/local_log_decorator_test.rb index 6846f85c20..a3208fedd2 100644 --- a/test/new_relic/agent/local_log_decorator_test.rb +++ b/test/new_relic/agent/local_log_decorator_test.rb @@ -45,9 +45,10 @@ def test_does_not_decorate_if_local_decoration_disabled end end - def test_does_not_decorate_if_instrumentation_logger_disabled + def test_does_not_decorate_if_instrumentation_logger_and_logastasher_disabled with_config( :'instrumentation.logger' => 'disabled', + :'instrumentation.logstasher' => 'disabled', :'application_logging.enabled' => true, :'application_logging.local_decorating.enabled' => true ) do @@ -99,6 +100,34 @@ def test_safe_without_entity_name assert_includes decorated_message, '||' end end + + def test_decorates_json_log_hashes + canned_hostname = 'blazkowicz' + hash = {'dennis' => 'gnasher'} + + in_transaction do |txn| + expected = hash.merge({'entity.name' => @enabled_config[:app_name], + 'entity.type' => 'SERVICE', + 'hostname' => canned_hostname, + 'entity.guid' => @enabled_config[:entity_guid], + 'trace.id' => txn.trace_id, + 'span.id' => txn.segments.first.guid}) + + NewRelic::Agent::Hostname.stub(:get, canned_hostname) do + LocalLogDecorator.decorate(hash) + end + + assert_equal expected, hash, "Expected hash to be decorated. Wanted >>#{expected}<<, got >>#{hash}<<" + end + end + + def test_returns_early_with_frozen_hashes + hash = {'dennis' => 'gnasher'}.freeze + expected = hash.dup + LocalLogDecorator.decorate(hash) + + assert_equal expected, hash, 'Expected no errors and no hash modifications for a frozen hash' + end end end end diff --git a/test/new_relic/agent/log_event_aggregator_test.rb b/test/new_relic/agent/log_event_aggregator_test.rb index 78b4ff1ee2..d707a84f99 100644 --- a/test/new_relic/agent/log_event_aggregator_test.rb +++ b/test/new_relic/agent/log_event_aggregator_test.rb @@ -15,6 +15,7 @@ def setup @enabled_config = { :'instrumentation.logger' => 'auto', + :'instrumentation.logstasher' => 'auto', LogEventAggregator::OVERALL_ENABLED_KEY => true, LogEventAggregator::FORWARDING_ENABLED_KEY => true } @@ -57,6 +58,7 @@ def test_records_enabled_metrics_on_startup assert_metrics_recorded_exclusive({ 'Supportability/Logging/Ruby/Logger/enabled' => {:call_count => 1}, + 'Supportability/Logging/Ruby/LogStasher/enabled' => {:call_count => 1}, 'Supportability/Logging/Metrics/Ruby/enabled' => {:call_count => 1}, 'Supportability/Logging/Forwarding/Ruby/enabled' => {:call_count => 1}, 'Supportability/Logging/LocalDecorating/Ruby/enabled' => {:call_count => 1} @@ -76,6 +78,7 @@ def test_records_disabled_metrics_on_startup assert_metrics_recorded_exclusive({ 'Supportability/Logging/Ruby/Logger/disabled' => {:call_count => 1}, + 'Supportability/Logging/Ruby/LogStasher/disabled' => {:call_count => 1}, 'Supportability/Logging/Metrics/Ruby/disabled' => {:call_count => 1}, 'Supportability/Logging/Forwarding/Ruby/disabled' => {:call_count => 1}, 'Supportability/Logging/LocalDecorating/Ruby/disabled' => {:call_count => 1} @@ -337,6 +340,7 @@ def test_high_security_mode 'Logging/lines' => {:call_count => 9}, 'Logging/lines/DEBUG' => {:call_count => 9}, 'Supportability/Logging/Ruby/Logger/enabled' => {:call_count => 1}, + 'Supportability/Logging/Ruby/LogStasher/enabled' => {:call_count => 1}, 'Supportability/Logging/Metrics/Ruby/enabled' => {:call_count => 1}, 'Supportability/Logging/Forwarding/Ruby/enabled' => {:call_count => 1}, 'Supportability/Logging/LocalDecorating/Ruby/disabled' => {:call_count => 1} @@ -359,6 +363,7 @@ def test_overall_disabled # All settings should report as disabled regardless of config option assert_metrics_recorded_exclusive({ 'Supportability/Logging/Ruby/Logger/disabled' => {:call_count => 1}, + 'Supportability/Logging/Ruby/LogStasher/disabled' => {:call_count => 1}, 'Supportability/Logging/Metrics/Ruby/disabled' => {:call_count => 1}, 'Supportability/Logging/Forwarding/Ruby/disabled' => {:call_count => 1}, 'Supportability/Logging/LocalDecorating/Ruby/disabled' => {:call_count => 1} @@ -384,6 +389,7 @@ def test_overall_disabled_in_high_security_mode assert_metrics_recorded_exclusive({ 'Supportability/Logging/Ruby/Logger/disabled' => {:call_count => 1}, + 'Supportability/Logging/Ruby/LogStasher/disabled' => {:call_count => 1}, 'Supportability/Logging/Metrics/Ruby/disabled' => {:call_count => 1}, 'Supportability/Logging/Forwarding/Ruby/disabled' => {:call_count => 1}, 'Supportability/Logging/LocalDecorating/Ruby/disabled' => {:call_count => 1} @@ -521,5 +527,171 @@ def test_records_log_events_not_within_default_severities assert_equal(log_message, events.first.last['message']) end end + + def test_record_json_sets_severity_when_given_level + @aggregator.record_logstasher_event({'level' => :warn, 'message' => 'yikes!'}) + _, events = @aggregator.harvest! + + assert_equal 'WARN', events[0][1]['level'] + assert_metrics_recorded([ + 'Logging/lines/WARN' + ]) + end + + def test_record_json_sets_severity_unknown_when_no_level + @aggregator.record_logstasher_event({'message' => 'hello there'}) + _, events = @aggregator.harvest! + + assert_equal 'UNKNOWN', events[0][1]['level'] + assert_metrics_recorded([ + 'Logging/lines/UNKNOWN' + ]) + end + + def test_record_json_does_not_record_if_message_is_nil + @aggregator.record_logstasher_event({'level' => :info, 'message' => nil}) + _, events = @aggregator.harvest! + + assert_empty events + end + + def test_record_json_does_not_record_if_message_empty_string + @aggregator.record_logstasher_event({'level' => :info, 'message' => ''}) + _, events = @aggregator.harvest! + + assert_empty events + end + + def test_record_json_returns_message_when_avaliable + @aggregator.record_logstasher_event({'level' => :warn, 'message' => 'A trex is near'}) + _, events = @aggregator.harvest! + + assert_equal 'A trex is near', events[0][1]['message'] + end + + def test_create_logstasher_event_do_not_message_when_not_given + @aggregator.record_logstasher_event({'level' => :info}) + _, events = @aggregator.harvest! + + refute events[0][1]['message'] + end + + def test_add_logstasher_event_attributes_records_attributes + @aggregator.record_logstasher_event({'source' => '127.0.0.1', 'tags' => ['log']}) + _, events = @aggregator.harvest! + + assert_includes(events[0][1]['attributes'], 'source') + assert_includes(events[0][1]['attributes'], 'tags') + end + + def test_add_add_logstasher_event_attributes_deletes_already_recorded_attributes + @aggregator.record_logstasher_event({'message' => 'bye', 'level' => :info, '@timestamp' => 'now', 'include_me' => 'random attribute'}) + _, events = @aggregator.harvest! + + # The event's 'attributes' hash doesn't include already recorded attributes + refute_includes(events[0][1]['attributes'], 'message') + refute_includes(events[0][1]['attributes'], 'level') + refute_includes(events[0][1]['attributes'], '@timestamp') + assert events[0][1]['attributes']['include_me'] + + # The event still includes necessary attributes + assert events[0][1]['message'] + assert events[0][1]['level'] + assert events[0][1]['timestamp'] + end + + def test_logstasher_forwarding_disabled_and_high_security_enabled + with_config(:'application_logging.forwarding.enabled' => false) do + # Refresh the high security setting on this notification + NewRelic::Agent.config.notify_server_source_added + + @aggregator.record_logstasher_event({'message' => 'high security enabled', 'level' => :info}) + _, events = @aggregator.harvest! + + assert_empty events + end + end + + def test_records_customer_metrics_when_enabled_logstasher + with_config(LogEventAggregator::METRICS_ENABLED_KEY => true) do + 2.times { @aggregator.record_logstasher_event({'message' => 'metrics enabled', 'level' => :debug}) } + @aggregator.harvest! + end + + assert_metrics_recorded({ + 'Logging/lines' => {:call_count => 2}, + 'Logging/lines/DEBUG' => {:call_count => 2} + }) + end + + def test_doesnt_record_customer_metrics_when_overall_disabled_and_metrics_enabled_logstasher + with_config( + LogEventAggregator::OVERALL_ENABLED_KEY => false, + LogEventAggregator::METRICS_ENABLED_KEY => true + ) do + NewRelic::Agent.config.notify_server_source_added + + @aggregator.record_logstasher_event({'message' => 'overall disabled, metrics enabled', 'level' => :debug}) + @aggregator.harvest! + end + + assert_metrics_not_recorded([ + 'Logging/lines', + 'Logging/lines/DEBUG' + ]) + end + + def test_doesnt_record_customer_metrics_when_disabled_logstasher + with_config(LogEventAggregator::METRICS_ENABLED_KEY => false) do + @aggregator.record_logstasher_event({'message' => 'metrics disabled', 'level' => :warn}) + @aggregator.harvest! + end + + assert_metrics_not_recorded([ + 'Logging/lines', + 'Logging/lines/WARN' + ]) + end + + def test_high_security_mode_logstasher + with_config(CAPACITY_KEY => 5, :high_security => true) do + # Refresh the high security setting on this notification + NewRelic::Agent.config.notify_server_source_added + + @aggregator.record_logstasher_event({'message' => 'high security enabled', 'level' => :info}) + _, events = @aggregator.harvest! + + assert_empty events + end + end + + def test_does_not_record_logstasher_events_with_a_severity_below_config + with_config(LogEventAggregator::LOG_LEVEL_KEY => 'info') do + assert_equal :INFO, @aggregator.send(:configured_log_level_constant) + + @aggregator.record_logstasher_event({'message' => 'severity below config', 'level' => :debug}) + _, events = @aggregator.harvest! + + assert_empty events + end + end + + def test_record_logstasher_exits_if_forwarding_disabled + with_config(LogEventAggregator::FORWARDING_ENABLED_KEY => false) do + @aggregator.record_logstasher_event({'message' => 'forwarding disabled', 'level' => :info}) + _, results = @aggregator.harvest! + + assert_empty results + end + end + + def test_nil_when_record_logstasher_errors + @aggregator.stub(:severity_too_low?, -> { raise 'kaboom' }) do + @aggregator.record_logstasher_event({'level' => :warn, 'message' => 'A trex is near'}) + _, results = @aggregator.harvest! + + assert_empty results + end + end end end From 1e93a5f64116c0656ecc3200dd479f50ee6da425 Mon Sep 17 00:00:00 2001 From: Tanna McClure Date: Thu, 11 Jul 2024 12:41:58 -0500 Subject: [PATCH 073/109] update changelog --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e03e3effcb..9ae17372d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,17 @@ ## -Version improves instrumentation for the `redis-clustering` gem. +Version improves instrumentation for the `redis-clustering` gem, and updates the elasticsearch instrumentation to only attempt to get the cluster name once per client, even if it fails. - **Feature: Add instrumentation for redis-clustering** Version 5.x of the `redis` gem moved cluster behavior into a different gem, `redis-clustering`. This gem can access instrumentation registered through `RedisClient::Middleware`. Previously, the agent only instrumented the `call_pipelined` method through this approach, but now users of the `redis-clustering` gem will also have instrumentation registered for `connect` and `call` methods. In addition, the way the `database_name` attribute is set for Redis datastore spans is now compatible with all versions of Redis supported by the New Relic Ruby agent. Thank you, [@praveen-ks](https://github.com/praveen-ks) for bringing this to our attention. [Issue#2444](https://github.com/newrelic/newrelic-ruby-agent/issues/2444) [PR#2720](https://github.com/newrelic/newrelic-ruby-agent/pull/2720) +- **Bugfix: Update Elasticsearch instrumentation to only attempt to get the cluster name once per client** + + Previously, the agent would attempt to get the cluster name every time a call was made if it was not already captured. This could lead to a large number of failures if the cluster name could not be retrieved. Now, the agent will only attempt to get the cluster name once per client, even if it fails. Thank you, [@ascoppa](https://github.com/ascoppa) for bringing this to our attention. + + ## v9.11.0 Version 9.11.0 introduces instrumentation for the aws-sdk-sqs gem, fixes a bug related to expected errors not bearing a "true" value for the "expected" attribute if expected as a result of an HTTP status code match and changes the way Stripe instrumentation metrics are named to prevent high-cardinality issues. From 055f4438e9daf086c37d658ea9b7c76b10a55ed3 Mon Sep 17 00:00:00 2001 From: Tanna McClure Date: Thu, 11 Jul 2024 14:02:52 -0500 Subject: [PATCH 074/109] changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a300572d0..16c8cf4489 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ Version introduces instrumentation for the LogStasher gem, improves instru - **Bugfix: Update Elasticsearch instrumentation to only attempt to get the cluster name once per client** - Previously, the agent would attempt to get the cluster name every time a call was made if it was not already captured. This could lead to a large number of failures if the cluster name could not be retrieved. Now, the agent will only attempt to get the cluster name once per client, even if it fails. Thank you, [@ascoppa](https://github.com/ascoppa) for bringing this to our attention. + Previously, the agent would attempt to get the cluster name every time a call was made if it was not already captured. This could lead to a large number of failures if the cluster name could not be retrieved. Now, the agent will only attempt to get the cluster name once per client, even if it fails. Thank you, [@ascoppa](https://github.com/ascoppa) for bringing this to our attention. [Issue#2730](https://github.com/newrelic/newrelic-ruby-agent/issues/2730) [PR#2743](https://github.com/newrelic/newrelic-ruby-agent/pull/2743) ## v9.11.0 From e764ac742d1ea22e9db73a5616eed4bd6e446e18 Mon Sep 17 00:00:00 2001 From: Tanna McClure Date: Thu, 11 Jul 2024 14:03:06 -0500 Subject: [PATCH 075/109] Update CHANGELOG.md Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16c8cf4489..9746451a0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # New Relic Ruby Agent Release Notes ## -Version introduces instrumentation for the LogStasher gem, improves instrumentation for the `redis-clustering` gem, and updates the elasticsearch instrumentation to only attempt to get the cluster name once per client, even if it fails. +Version introduces instrumentation for the LogStasher gem, improves instrumentation for the `redis-clustering` gem, and updates the Elasticsearch instrumentation to only attempt to get the cluster name once per client, even if it fails. - **Feature: Add instrumentation for LogStasher** From 3b5e1d96b4ec26c499155e7c62fe95a92aca14cf Mon Sep 17 00:00:00 2001 From: fallwith Date: Fri, 12 Jul 2024 12:06:13 -0700 Subject: [PATCH 076/109] include additional AC topics in Rails subscription When subscribing to Action Controller topics for Rails notifications, include 4 new topics in the subscription regex: - `exist_fragment?` - `expire_fragment` - `read_fragment` - `write_fragment` --- .../rails_notifications/action_controller.rb | 14 ++-- .../rails/action_controller_other_test.rb | 83 ++++++++++++++++++- 2 files changed, 91 insertions(+), 6 deletions(-) diff --git a/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb b/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb index dd0285e248..2750b0f923 100644 --- a/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb +++ b/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb @@ -32,15 +32,19 @@ NewRelic::Agent::Instrumentation::ActionControllerSubscriber \ .subscribe(/^process_action.action_controller$/) - subs = %w[send_file + subs = %w[exist_fragment? + expire_fragment + halted_callback + read_fragment + redirect_to send_data + send_file send_stream - redirect_to - halted_callback - unpermitted_parameters] + write_fragment + unpermitted_parameters].map { |s| Regexp.escape(s) } # have to double escape period because its going from string -> regex NewRelic::Agent::Instrumentation::ActionControllerOtherSubscriber \ - .subscribe(Regexp.new("^(#{subs.join('|')})\\.action_controller$")) + .subscribe(Regexp.new("^(?:#{subs.join('|')})\\.action_controller$")) end end diff --git a/test/multiverse/suites/rails/action_controller_other_test.rb b/test/multiverse/suites/rails/action_controller_other_test.rb index 672469d6b8..76a5566ed2 100644 --- a/test/multiverse/suites/rails/action_controller_other_test.rb +++ b/test/multiverse/suites/rails/action_controller_other_test.rb @@ -3,10 +3,11 @@ # frozen_string_literal: true require './app' - if defined?(ActionController::Live) class DataController < ApplicationController + CACHE_KEY = :the_key + # send_file def send_test_file send_file(Rails.root + '../../../../README.md') @@ -35,6 +36,26 @@ def do_a_redirect def not_allowed params.permit(:only_this) end + + # exist_fragment? + def exist_fragment + fragment_exist?(CACHE_KEY) + end + + # expire_fragment + def expire_test_fragment + expire_fragment(CACHE_KEY) + end + + # read_fragment + def read_test_fragment + read_fragment(CACHE_KEY) + end + + # write_fragment + def write_test_fragment + write_fragment(CACHE_KEY, 'fragment') + end end class ActionControllerDataTest < ActionDispatch::IntegrationTest @@ -121,6 +142,66 @@ def test_unpermitted_parameters assert_metrics_recorded(['Controller/data/not_allowed', segment_name]) end + def test_exist_fragment? + skip if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('6.0.0') + + get('/data/exist_fragment') + + node = find_node_with_name_matching(last_transaction_trace, /ActionController/) + + assert node, 'Could not find an >>ActionController<< metric while testing >>exist_fragment?<<' + child = node.children.detect { |n| n.metric_name.include?('FileStore/exist') } + + assert child, 'Could not find a >>Filestore/exist<< child of the ActionController node!' + assert_includes child.params[:key], DataController::CACHE_KEY, + "Expected to find the cache key >>#{DataController::CACHE_KEY}<< in the node params!" + end + + def test_expire_fragment + skip if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('6.0.0') + + get('/data/expire_test_fragment') + + node = find_node_with_name_matching(last_transaction_trace, /ActionController/) + + assert node, 'Could not find an >>ActionController<< metric while testing >>expire_fragment<<' + child = node.children.detect { |n| n.metric_name.include?('FileStore/delete') } + + assert child, 'Could not find a >>Filestore/delete<< child of the ActionController node!' + assert_includes child.params[:key], DataController::CACHE_KEY, + "Expected to find the cache key >>#{DataController::CACHE_KEY}<< in the node params!" + end + + def test_read_fragment + skip if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('6.0.0') + + get('/data/read_test_fragment') + + node = find_node_with_name_matching(last_transaction_trace, /ActionController/) + + assert node, 'Could not find an >>ActionController<< metric while testing >>read_fragment<<' + child = node.children.detect { |n| n.metric_name.include?('FileStore/read') } + + assert child, 'Could not find a >>Filestore/read<< child of the ActionController node!' + assert_includes child.params[:key], DataController::CACHE_KEY, + "Expected to find the cache key >>#{DataController::CACHE_KEY}<< in the node params!" + end + + def test_write_fragment + skip if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('6.0.0') + + get('/data/write_test_fragment') + + node = find_node_with_name_matching(last_transaction_trace, /ActionController/) + + assert node, 'Could not find an >>ActionController<< metric while testing >>write_fragment<<' + child = node.children.detect { |n| n.metric_name.include?('FileStore/write') } + + assert child, 'Could not find a >>Filestore/write<< child of the ActionController node!' + assert_includes child.params[:key], DataController::CACHE_KEY, + "Expected to find the cache key >>#{DataController::CACHE_KEY}<< in the node params!" + end + class TestClassActionController; end def test_no_metric_naming_error From 43326de6cd0619414e3285a88d2526411abd9822 Mon Sep 17 00:00:00 2001 From: Tanna McClure Date: Fri, 12 Jul 2024 14:12:54 -0500 Subject: [PATCH 077/109] pin protobuf version for infinite tracing --- infinite_tracing/CHANGELOG.md | 4 ++++ infinite_tracing/newrelic-infinite_tracing.gemspec | 1 + 2 files changed, 5 insertions(+) diff --git a/infinite_tracing/CHANGELOG.md b/infinite_tracing/CHANGELOG.md index a725414cb1..bd484a51f3 100644 --- a/infinite_tracing/CHANGELOG.md +++ b/infinite_tracing/CHANGELOG.md @@ -1,5 +1,9 @@ # New Relic Infinite Tracing for Ruby Agent Release Notes # + ## v9.12.0 + + * Pin google-protobuf dependency to < 4.0 due to compatibility issues with version 4+. + ## v8.9.0 * **Bugfix: Infinite Tracing hung on connection restart** diff --git a/infinite_tracing/newrelic-infinite_tracing.gemspec b/infinite_tracing/newrelic-infinite_tracing.gemspec index 729cbef34a..3c94f78297 100644 --- a/infinite_tracing/newrelic-infinite_tracing.gemspec +++ b/infinite_tracing/newrelic-infinite_tracing.gemspec @@ -73,6 +73,7 @@ Gem::Specification.new do |s| s.add_dependency 'newrelic_rpm', NewRelic::VERSION::STRING s.add_dependency 'grpc', '~> 1.34' + s.add_dependency 'google-protobuf', '< 4.0' s.add_development_dependency 'rake', '12.3.3' s.add_development_dependency 'rb-inotify' From a96d082ad49858f8ad17d1070b925a76d5b2f420 Mon Sep 17 00:00:00 2001 From: fallwith Date: Fri, 12 Jul 2024 14:59:37 -0700 Subject: [PATCH 078/109] update Lambda docs link the Lambda docs have been reorganized to accommodate what are being referred to as "layerless", "containerized", and "non-containerized" approaches, with that last one being the closest analogue to what was linked to previously. --- lib/new_relic/agent/configuration/default_source.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index 3de2b00e4e..bc2fa142cc 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -1956,7 +1956,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) If `true`, the agent will operate in a streamlined mode suitable for use with short-lived serverless functions. NOTE: Only AWS Lambda functions are supported currently and this option is not intended for use without - [New Relic's Ruby Lambda layer](https://docs.newrelic.com/docs/serverless-function-monitoring/aws-lambda-monitoring/get-started/monitoring-aws-lambda-serverless-monitoring/) + [New Relic's Ruby Lambda layer based instrumentation](https://docs.newrelic.com/docs/serverless-function-monitoring/aws-lambda-monitoring/instrument-lambda-function/instrument-your-own/) offering. DESC }, From 14e86a60b845622e7df09d5bacc23661e6beeec9 Mon Sep 17 00:00:00 2001 From: fallwith Date: Mon, 15 Jul 2024 12:04:28 -0700 Subject: [PATCH 079/109] re-enable Rails EDGE testing resume CI testing of Rails EDGE (which currently references Rails v8.0 alpha) --- .github/workflows/ci_cron.yml | 8 ++++---- test/multiverse/suites/active_record_pg/Envfile | 2 +- .../suites/active_support_broadcast_logger/Envfile | 2 +- test/multiverse/suites/rails/Envfile | 2 +- test/multiverse/suites/rails_prepend/Envfile | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci_cron.yml b/.github/workflows/ci_cron.yml index 33834fb560..f098e47082 100644 --- a/.github/workflows/ci_cron.yml +++ b/.github/workflows/ci_cron.yml @@ -76,16 +76,16 @@ jobs: "rails": "norails,rails61,rails60,rails70,rails71" }, "3.1.6": { - "rails": "norails,rails61,rails70,rails71,rails72" + "rails": "norails,rails61,rails70,rails71,rails72,railsedge" }, "3.2.4": { - "rails": "norails,rails61,rails70,rails71,rails72" + "rails": "norails,rails61,rails70,rails71,rails72,railsedge" }, "3.3.4": { - "rails": "norails,rails61,rails70,rails71,rails72" + "rails": "norails,rails61,rails70,rails71,rails72,railsedge" }, "3.4.0-preview1": { - "rails": "norails,rails61,rails70,rails71,rails72" + "rails": "norails,rails61,rails70,rails71,rails72,railsedge" } } diff --git a/test/multiverse/suites/active_record_pg/Envfile b/test/multiverse/suites/active_record_pg/Envfile index 3947564ad8..68d718c94d 100644 --- a/test/multiverse/suites/active_record_pg/Envfile +++ b/test/multiverse/suites/active_record_pg/Envfile @@ -22,7 +22,7 @@ ACTIVERECORD_VERSIONS = [ ['5.0.0', 2.4, 2.7] ] -# unshift_rails_edge(ACTIVERECORD_VERSIONS) +unshift_rails_edge(ACTIVERECORD_VERSIONS) def gem_list(activerecord_version = nil) <<~RB diff --git a/test/multiverse/suites/active_support_broadcast_logger/Envfile b/test/multiverse/suites/active_support_broadcast_logger/Envfile index 9a6b79c4fc..9a274d0c4f 100644 --- a/test/multiverse/suites/active_support_broadcast_logger/Envfile +++ b/test/multiverse/suites/active_support_broadcast_logger/Envfile @@ -11,7 +11,7 @@ ACTIVE_SUPPORT_VERSIONS = [ ['7.1.0', 2.7] ] -# unshift_rails_edge(ACTIVE_SUPPORT_VERSIONS) +unshift_rails_edge(ACTIVE_SUPPORT_VERSIONS) def gem_list(activesupport_version = nil) <<-RB diff --git a/test/multiverse/suites/rails/Envfile b/test/multiverse/suites/rails/Envfile index adcf97a305..f98327f984 100644 --- a/test/multiverse/suites/rails/Envfile +++ b/test/multiverse/suites/rails/Envfile @@ -14,7 +14,7 @@ RAILS_VERSIONS = [ ['4.2.11', 2.4, 2.4] ] -# unshift_rails_edge(RAILS_VERSIONS) +unshift_rails_edge(RAILS_VERSIONS) def haml_rails(rails_version = nil) if rails_version && ( diff --git a/test/multiverse/suites/rails_prepend/Envfile b/test/multiverse/suites/rails_prepend/Envfile index c474d0b6e5..18884f4cb1 100644 --- a/test/multiverse/suites/rails_prepend/Envfile +++ b/test/multiverse/suites/rails_prepend/Envfile @@ -14,7 +14,7 @@ RAILS_VERSIONS = [ ['4.2.0', 2.4, 2.4] ] -# unshift_rails_edge(RAILS_VERSIONS) +unshift_rails_edge(RAILS_VERSIONS) def gem_list(rails_version = nil) # earlier thor errors, uncertain if they persist From 5902957e71c5007c400087d9dba24cfad837ca7f Mon Sep 17 00:00:00 2001 From: fallwith Date: Mon, 15 Jul 2024 12:50:07 -0700 Subject: [PATCH 080/109] README: serverless link fix the NR serverless docs have moved, so update the readme accordingly --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 20d1d22195..bbdaf18c33 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ You can also monitor non-web applications. Refer to the "Other Environments" section below. We offer an AWS Lambda layer for instrumenting your serverless Ruby functions. -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/). +Details can be found on our [getting started guide](https://docs.newrelic.com/docs/serverless-function-monitoring/aws-lambda-monitoring/instrument-lambda-function/instrument-your-own/). ## Installing and Using From 2d8f43e0e5b081f080368e62357e21a1a4c642ee Mon Sep 17 00:00:00 2001 From: fallwith Date: Mon, 15 Jul 2024 14:50:19 -0700 Subject: [PATCH 081/109] CI: Rails EDGE fixes - Use v8.0 defaults - Conditiionally include gems not included with Ruby v3.4 / v3.5 --- test/environments/railsedge/Gemfile | 7 +++++++ test/environments/railsedge/config/application.rb | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/test/environments/railsedge/Gemfile b/test/environments/railsedge/Gemfile index 5bc73b6cde..70e0119b67 100644 --- a/test/environments/railsedge/Gemfile +++ b/test/environments/railsedge/Gemfile @@ -25,3 +25,10 @@ end gem 'simplecov' if ENV['VERBOSE_TEST_OUTPUT'] gem 'warning' + +if RUBY_VERSION.split('.')[0..1].join('.').to_f >= 3.4 + gem 'base64' + gem 'bigdecimal' + gem 'mutex_m' + gem 'ostruct' +end diff --git a/test/environments/railsedge/config/application.rb b/test/environments/railsedge/config/application.rb index 2565b8762e..930b300484 100644 --- a/test/environments/railsedge/config/application.rb +++ b/test/environments/railsedge/config/application.rb @@ -13,7 +13,7 @@ module RpmTestApp class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. - config.load_defaults(7.0) # TODO: keep this number up to date (and keep this TODO) + config.load_defaults(8.0) # TODO: keep this number up to date (and keep this TODO) config.eager_load = false config.filter_parameters += [:password] end From 4723381e52001fbb9f1b57b94554e283d782b914 Mon Sep 17 00:00:00 2001 From: fallwith Date: Mon, 15 Jul 2024 15:29:28 -0700 Subject: [PATCH 082/109] CHANGELOG: entry for PR 2745 PR 2745 (4 additional Action Controller notifications) changelog entry --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9746451a0a..cf29c33d98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ Version introduces instrumentation for the LogStasher gem, improves instru Previously, the agent would attempt to get the cluster name every time a call was made if it was not already captured. This could lead to a large number of failures if the cluster name could not be retrieved. Now, the agent will only attempt to get the cluster name once per client, even if it fails. Thank you, [@ascoppa](https://github.com/ascoppa) for bringing this to our attention. [Issue#2730](https://github.com/newrelic/newrelic-ruby-agent/issues/2730) [PR#2743](https://github.com/newrelic/newrelic-ruby-agent/pull/2743) +- **Feature: Produce metrics for 4 additional Action Controller Rails notifications** + + Four additional Action Controller related Rails notifications are now subscribed to by the agent to produce metrics. These 4 are `exist_fragment?`, `expire_fragment`, `read_fragment`, and `write_fragment`. As with instrumentation for Action Controller itself, these notifications are enabled by default and can be disabled by setting `:disable_action_controller` to `true` in the agent's `newrelic.yml` configuration file. [PR#2745](https://github.com/newrelic/newrelic-ruby-agent/pull/2745) + ## v9.11.0 From 5e05495c4b2ec314c973d789040b4310e177bfdb Mon Sep 17 00:00:00 2001 From: James Bunch Date: Mon, 15 Jul 2024 15:41:38 -0700 Subject: [PATCH 083/109] Update CHANGELOG.md metrics -> telemetry Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf29c33d98..ee5489d1ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ Version introduces instrumentation for the LogStasher gem, improves instru - **Feature: Produce metrics for 4 additional Action Controller Rails notifications** - Four additional Action Controller related Rails notifications are now subscribed to by the agent to produce metrics. These 4 are `exist_fragment?`, `expire_fragment`, `read_fragment`, and `write_fragment`. As with instrumentation for Action Controller itself, these notifications are enabled by default and can be disabled by setting `:disable_action_controller` to `true` in the agent's `newrelic.yml` configuration file. [PR#2745](https://github.com/newrelic/newrelic-ruby-agent/pull/2745) + Four additional Action Controller related Rails notifications are now subscribed to by the agent to produce telemetry. These 4 are `exist_fragment?`, `expire_fragment`, `read_fragment`, and `write_fragment`. As with instrumentation for Action Controller itself, these notifications are enabled by default and can be disabled by setting `:disable_action_controller` to `true` in the agent's `newrelic.yml` configuration file. [PR#2745](https://github.com/newrelic/newrelic-ruby-agent/pull/2745) ## v9.11.0 From 5840f64d3ec3e7eb32f63b9e70f7eab2ef3b4d33 Mon Sep 17 00:00:00 2001 From: prateek-ap Date: Tue, 16 Jul 2024 12:32:15 +0530 Subject: [PATCH 084/109] security.enabled should be checked in Security agent only and not in APM agent --- lib/new_relic/control/security_interface.rb | 6 +-- .../control/security_interface_test.rb | 39 ++++--------------- 2 files changed, 9 insertions(+), 36 deletions(-) diff --git a/lib/new_relic/control/security_interface.rb b/lib/new_relic/control/security_interface.rb index 85cadf0276..05065b30f3 100644 --- a/lib/new_relic/control/security_interface.rb +++ b/lib/new_relic/control/security_interface.rb @@ -29,15 +29,14 @@ def init_agent record_supportability_metrics - if Agent.config[:'security.agent.enabled'] && Agent.config[:'security.enabled'] && !Agent.config[:high_security] + if Agent.config[:'security.agent.enabled'] && !Agent.config[:high_security] Agent.logger.info('Invoking New Relic security module') require 'newrelic_security' @agent_started = true else - Agent.logger.info('New Relic Security is completely disabled by one of the user provided config `security.agent.enabled`, `security.enabled`, or `high_security`. Not loading security capabilities.') + Agent.logger.info('New Relic Security is completely disabled by one of the user provided config `security.agent.enabled`, or `high_security`. Not loading security capabilities.') Agent.logger.info("high_security = #{Agent.config[:high_security]}") - Agent.logger.info("security.enabled = #{Agent.config[:'security.enabled']}") Agent.logger.info("security.agent.enabled = #{Agent.config[:'security.agent.enabled']}") end rescue LoadError @@ -47,7 +46,6 @@ def init_agent end def record_supportability_metrics - Agent.config[:'security.enabled'] ? security_metric(ENABLED) : security_metric(DISABLED) Agent.config[:'security.agent.enabled'] ? security_agent_metric(ENABLED) : security_agent_metric(DISABLED) end diff --git a/test/new_relic/control/security_interface_test.rb b/test/new_relic/control/security_interface_test.rb index 3997b39e42..9f3994c32e 100644 --- a/test/new_relic/control/security_interface_test.rb +++ b/test/new_relic/control/security_interface_test.rb @@ -20,18 +20,16 @@ def reset_supportability_metrics def assert_supportability_metrics_enabled assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Agent/Enabled/enabled' - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' end def test_initialization_short_circuits_when_the_security_agent_is_disabled reset_supportability_metrics logger = MiniTest::Mock.new - with_config('security.agent.enabled' => false, 'security.enabled' => true, 'high_security' => false) do + with_config('security.agent.enabled' => false, 'high_security' => false) do NewRelic::Agent.stub :logger, logger do logger.expect :info, nil, [/Security is completely disabled/] logger.expect :info, nil, [/high_security = false/] - logger.expect :info, nil, [/security.enabled = true/] logger.expect :info, nil, [/security.agent.enabled = false/] NewRelic::Control::SecurityInterface.instance.init_agent @@ -39,39 +37,16 @@ def test_initialization_short_circuits_when_the_security_agent_is_disabled refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Agent/Enabled/disabled' - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/enabled' - end - logger.verify - end - - def test_initialization_short_circuits_when_the_security_is_disabled - reset_supportability_metrics - - logger = MiniTest::Mock.new - with_config('security.agent.enabled' => true, 'security.enabled' => false, 'high_security' => false) do - NewRelic::Agent.stub :logger, logger do - logger.expect :info, nil, [/Security is completely disabled/] - logger.expect :info, nil, [/high_security = false/] - logger.expect :info, nil, [/security.enabled = false/] - logger.expect :info, nil, [/security.agent.enabled = true/] - - NewRelic::Control::SecurityInterface.instance.init_agent - end - - refute_predicate NewRelic::Control::SecurityInterface.instance, :agent_started? - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Agent/Enabled/enabled' - assert_metrics_recorded 'Supportability/Ruby/SecurityAgent/Enabled/disabled' end logger.verify end def test_initialization_short_circuits_when_high_security_mode_is_enabled logger = MiniTest::Mock.new - with_config('security.agent.enabled' => true, 'security.enabled' => true, 'high_security' => true) do + with_config('security.agent.enabled' => true, 'high_security' => true) do NewRelic::Agent.stub :logger, logger do logger.expect :info, nil, [/Security is completely disabled/] logger.expect :info, nil, [/high_security = true/] - logger.expect :info, nil, [/security.enabled = true/] logger.expect :info, nil, [/security.agent.enabled = true/] NewRelic::Control::SecurityInterface.instance.init_agent @@ -85,7 +60,7 @@ def test_initialization_short_circuits_when_high_security_mode_is_enabled def test_initialization_short_circuits_if_the_agent_has_already_been_started reached = false - with_config('security.agent.enabled' => true, 'security.enabled' => true) do + with_config('security.agent.enabled' => true) do NewRelic::Agent.stub :config, -> { reached = true } do NewRelic::Control::SecurityInterface.instance.instance_variable_set(:@agent_started, true) NewRelic::Control::SecurityInterface.instance.init_agent @@ -97,7 +72,7 @@ def test_initialization_short_circuits_if_the_agent_has_already_been_started def test_initialization_short_circuits_if_the_agent_has_been_told_to_wait reached = false - with_config('security.agent.enabled' => true, 'security.enabled' => true) do + with_config('security.agent.enabled' => true) do NewRelic::Agent.stub :config, -> { reached = true } do NewRelic::Control::SecurityInterface.instance.instance_variable_set(:@wait, true) NewRelic::Control::SecurityInterface.instance.init_agent @@ -112,7 +87,7 @@ def test_initialization_requires_the_security_agent required = false logger = MiniTest::Mock.new - with_config('security.agent.enabled' => true, 'security.enabled' => true) do + with_config('security.agent.enabled' => true) do NewRelic::Agent.stub :logger, logger do logger.expect :info, nil, [/Invoking New Relic security/] @@ -132,7 +107,7 @@ def test_initialization_anticipates_a_load_error skip_unless_minitest5_or_above logger = MiniTest::Mock.new - with_config('security.agent.enabled' => true, 'security.enabled' => true) do + with_config('security.agent.enabled' => true) do NewRelic::Agent.stub :logger, logger do logger.expect :info, nil, [/Invoking New Relic security/] logger.expect :info, nil, [/security agent not found/] @@ -153,7 +128,7 @@ def test_initialization_handles_errors skip_unless_minitest5_or_above logger = MiniTest::Mock.new - with_config('security.agent.enabled' => true, 'security.enabled' => true) do + with_config('security.agent.enabled' => true) do NewRelic::Agent.stub :logger, logger do logger.expect :info, nil, [/Invoking New Relic security/] logger.expect :error, nil, [/Exception in New Relic security module loading/] From 1b769237776fd7b3e6598b3611b266369cae884d Mon Sep 17 00:00:00 2001 From: fallwith Date: Tue, 16 Jul 2024 11:24:15 -0700 Subject: [PATCH 085/109] CI: Rails multiverse updates - start explicitly testing v7.2 (in beta) now that EDGE points to v8.0 alpha - add helper methods for Rails version related checks - for the 4 new notifications added with PR 2745, expect Rails v6.0 to behave differently than Rails v6.1+ --- test/multiverse/suites/rails/Envfile | 1 + .../rails/action_controller_other_test.rb | 40 ++++++++++++++----- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/test/multiverse/suites/rails/Envfile b/test/multiverse/suites/rails/Envfile index adcf97a305..eac82deffa 100644 --- a/test/multiverse/suites/rails/Envfile +++ b/test/multiverse/suites/rails/Envfile @@ -4,6 +4,7 @@ RAILS_VERSIONS = [ [nil, 3.1], + ['7.2.0.beta3', 3.1], ['7.1.0', 2.7], ['7.0.4', 2.7], ['6.1.7', 2.5], diff --git a/test/multiverse/suites/rails/action_controller_other_test.rb b/test/multiverse/suites/rails/action_controller_other_test.rb index 76a5566ed2..a424199877 100644 --- a/test/multiverse/suites/rails/action_controller_other_test.rb +++ b/test/multiverse/suites/rails/action_controller_other_test.rb @@ -78,7 +78,7 @@ def test_send_data end def test_send_stream - skip if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('7.2.0') + skip unless rails_version_at_least?('7.2') get('/data/send_test_stream') assert_metrics_recorded(['Controller/data/send_test_stream', 'Ruby/ActionController/send_stream']) @@ -100,7 +100,7 @@ def test_redirect_to get('/data/do_a_redirect') # payload does not include the request in rails < 6.1 - rails61 = Gem::Version.new(Rails::VERSION::STRING) >= Gem::Version.new('6.1.0') + rails61 = rails_version_at_least?('6.1') segment_name = if rails61 'Ruby/ActionController/data/redirect_to' @@ -117,8 +117,8 @@ def test_redirect_to end def test_unpermitted_parameters - skip if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('6.0.0') # unpermitted parameters is only available in rails 6.0+ + skip unless rails_version_at_least?('6') get('/data/not_allowed', params: {this_is_a_param: 1}) @@ -143,14 +143,16 @@ def test_unpermitted_parameters end def test_exist_fragment? - skip if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('6.0.0') + skip unless rails_version_at_least?('6') get('/data/exist_fragment') node = find_node_with_name_matching(last_transaction_trace, /ActionController/) assert node, 'Could not find an >>ActionController<< metric while testing >>exist_fragment?<<' - child = node.children.detect { |n| n.metric_name.include?('FileStore/exist') } + child_metric_partial_name = rails_version_at_least?('6.1') ? 'FileStore/exist' : 'ActiveSupport/exist?' + child = node.children.detect { |n| n.metric_name.include?(child_metric_partial_name) } + binding.irb unless child assert child, 'Could not find a >>Filestore/exist<< child of the ActionController node!' assert_includes child.params[:key], DataController::CACHE_KEY, @@ -158,14 +160,16 @@ def test_exist_fragment? end def test_expire_fragment - skip if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('6.0.0') + skip unless rails_version_at_least?('6') get('/data/expire_test_fragment') node = find_node_with_name_matching(last_transaction_trace, /ActionController/) assert node, 'Could not find an >>ActionController<< metric while testing >>expire_fragment<<' - child = node.children.detect { |n| n.metric_name.include?('FileStore/delete') } + child_metric_partial_name = rails_version_at_least?('6.1') ? 'FileStore/delete' : 'ActiveSupport/delete' + child = node.children.detect { |n| n.metric_name.include?(child_metric_partial_name) } + binding.irb unless child assert child, 'Could not find a >>Filestore/delete<< child of the ActionController node!' assert_includes child.params[:key], DataController::CACHE_KEY, @@ -173,14 +177,16 @@ def test_expire_fragment end def test_read_fragment - skip if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('6.0.0') + skip unless rails_version_at_least?('6') get('/data/read_test_fragment') node = find_node_with_name_matching(last_transaction_trace, /ActionController/) assert node, 'Could not find an >>ActionController<< metric while testing >>read_fragment<<' - child = node.children.detect { |n| n.metric_name.include?('FileStore/read') } + child_metric_partial_name = rails_version_at_least?('6.1') ? 'FileStore/read' : 'ActiveSupport/read' + child = node.children.detect { |n| n.metric_name.include?(child_metric_partial_name) } + binding.irb unless child assert child, 'Could not find a >>Filestore/read<< child of the ActionController node!' assert_includes child.params[:key], DataController::CACHE_KEY, @@ -188,14 +194,16 @@ def test_read_fragment end def test_write_fragment - skip if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('6.0.0') + skip unless rails_version_at_least?('6') get('/data/write_test_fragment') node = find_node_with_name_matching(last_transaction_trace, /ActionController/) assert node, 'Could not find an >>ActionController<< metric while testing >>write_fragment<<' - child = node.children.detect { |n| n.metric_name.include?('FileStore/write') } + child_metric_partial_name = rails_version_at_least?('6.1') ? 'FileStore/write' : 'ActiveSupport/write' + child = node.children.detect { |n| n.metric_name.include?(child_metric_partial_name) } + binding.irb unless child assert child, 'Could not find a >>Filestore/write<< child of the ActionController node!' assert_includes child.params[:key], DataController::CACHE_KEY, @@ -223,5 +231,15 @@ def controller_class NewRelic::Agent::Instrumentation::ActionControllerOtherSubscriber.new.controller_name_for_metric(payload) end end + + private + + def rails_version + @rails_version ||= Gem::Version.new(Rails::VERSION::STRING) + end + + def rails_version_at_least?(version_string) + rails_version >= Gem::Version.new(version_string) + end end end From 1b824ab2009eac8b842b5719b0bf3043aaadbdba Mon Sep 17 00:00:00 2001 From: fallwith Date: Tue, 16 Jul 2024 11:26:57 -0700 Subject: [PATCH 086/109] remove debug statements remove `binding.irb` lines --- test/multiverse/suites/rails/action_controller_other_test.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/multiverse/suites/rails/action_controller_other_test.rb b/test/multiverse/suites/rails/action_controller_other_test.rb index a424199877..f5ee8ece34 100644 --- a/test/multiverse/suites/rails/action_controller_other_test.rb +++ b/test/multiverse/suites/rails/action_controller_other_test.rb @@ -152,7 +152,6 @@ def test_exist_fragment? assert node, 'Could not find an >>ActionController<< metric while testing >>exist_fragment?<<' child_metric_partial_name = rails_version_at_least?('6.1') ? 'FileStore/exist' : 'ActiveSupport/exist?' child = node.children.detect { |n| n.metric_name.include?(child_metric_partial_name) } - binding.irb unless child assert child, 'Could not find a >>Filestore/exist<< child of the ActionController node!' assert_includes child.params[:key], DataController::CACHE_KEY, @@ -169,7 +168,6 @@ def test_expire_fragment assert node, 'Could not find an >>ActionController<< metric while testing >>expire_fragment<<' child_metric_partial_name = rails_version_at_least?('6.1') ? 'FileStore/delete' : 'ActiveSupport/delete' child = node.children.detect { |n| n.metric_name.include?(child_metric_partial_name) } - binding.irb unless child assert child, 'Could not find a >>Filestore/delete<< child of the ActionController node!' assert_includes child.params[:key], DataController::CACHE_KEY, @@ -186,7 +184,6 @@ def test_read_fragment assert node, 'Could not find an >>ActionController<< metric while testing >>read_fragment<<' child_metric_partial_name = rails_version_at_least?('6.1') ? 'FileStore/read' : 'ActiveSupport/read' child = node.children.detect { |n| n.metric_name.include?(child_metric_partial_name) } - binding.irb unless child assert child, 'Could not find a >>Filestore/read<< child of the ActionController node!' assert_includes child.params[:key], DataController::CACHE_KEY, @@ -203,7 +200,6 @@ def test_write_fragment assert node, 'Could not find an >>ActionController<< metric while testing >>write_fragment<<' child_metric_partial_name = rails_version_at_least?('6.1') ? 'FileStore/write' : 'ActiveSupport/write' child = node.children.detect { |n| n.metric_name.include?(child_metric_partial_name) } - binding.irb unless child assert child, 'Could not find a >>Filestore/write<< child of the ActionController node!' assert_includes child.params[:key], DataController::CACHE_KEY, From 56231270259a865ad04f98d912f9660342952ea9 Mon Sep 17 00:00:00 2001 From: fallwith Date: Tue, 16 Jul 2024 12:51:57 -0700 Subject: [PATCH 087/109] CI: Rails v7.2 handles params a bit different handle params related assertions differently for Rails v7.2+ --- .../rails/action_controller_other_test.rb | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/test/multiverse/suites/rails/action_controller_other_test.rb b/test/multiverse/suites/rails/action_controller_other_test.rb index f5ee8ece34..410d15aa3c 100644 --- a/test/multiverse/suites/rails/action_controller_other_test.rb +++ b/test/multiverse/suites/rails/action_controller_other_test.rb @@ -154,8 +154,7 @@ def test_exist_fragment? child = node.children.detect { |n| n.metric_name.include?(child_metric_partial_name) } assert child, 'Could not find a >>Filestore/exist<< child of the ActionController node!' - assert_includes child.params[:key], DataController::CACHE_KEY, - "Expected to find the cache key >>#{DataController::CACHE_KEY}<< in the node params!" + confirm_key_exists_in_params(child) end def test_expire_fragment @@ -170,8 +169,7 @@ def test_expire_fragment child = node.children.detect { |n| n.metric_name.include?(child_metric_partial_name) } assert child, 'Could not find a >>Filestore/delete<< child of the ActionController node!' - assert_includes child.params[:key], DataController::CACHE_KEY, - "Expected to find the cache key >>#{DataController::CACHE_KEY}<< in the node params!" + confirm_key_exists_in_params(child) end def test_read_fragment @@ -186,8 +184,7 @@ def test_read_fragment child = node.children.detect { |n| n.metric_name.include?(child_metric_partial_name) } assert child, 'Could not find a >>Filestore/read<< child of the ActionController node!' - assert_includes child.params[:key], DataController::CACHE_KEY, - "Expected to find the cache key >>#{DataController::CACHE_KEY}<< in the node params!" + confirm_key_exists_in_params(child) end def test_write_fragment @@ -202,8 +199,7 @@ def test_write_fragment child = node.children.detect { |n| n.metric_name.include?(child_metric_partial_name) } assert child, 'Could not find a >>Filestore/write<< child of the ActionController node!' - assert_includes child.params[:key], DataController::CACHE_KEY, - "Expected to find the cache key >>#{DataController::CACHE_KEY}<< in the node params!" + confirm_key_exists_in_params(child) end class TestClassActionController; end @@ -235,7 +231,19 @@ def rails_version end def rails_version_at_least?(version_string) + version_string += '.0' until version_string.count('.') >= 2 # '7' => '7.0.0' rails_version >= Gem::Version.new(version_string) end + + def confirm_key_exists_in_params(node) + assertion_failure = "Expected to find the cache key >>#{DataController::CACHE_KEY}<< in the node params!" + # Rails v7.2+ stores the URI string, so look for the key on the end of it + if rails_version_at_least?('7.2.0.beta1') + assert_match(/#{CGI.escape("/#{DataController::CACHE_KEY}")}/, node.params[:key], assertion_failure) + # Rails < v7.2 stores the params in an array, so confirm it includes the key + else + assert_includes node.params[:key], DataController::CACHE_KEY, assertion_failure + end + end end end From bc3795178c05f0518781a02e2b1499b953d5a15c Mon Sep 17 00:00:00 2001 From: fallwith Date: Tue, 16 Jul 2024 16:33:34 -0700 Subject: [PATCH 088/109] Rails v8.0 fixes related to streaming/chunking Don't expect the Rails notification to fire nor the 'chunked' header to be set by Rails v8.0. --- lib/new_relic/rack/browser_monitoring.rb | 24 ++++++++++++------- .../rails/action_controller_other_test.rb | 4 +++- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/lib/new_relic/rack/browser_monitoring.rb b/lib/new_relic/rack/browser_monitoring.rb index a87b2cefae..94e4a8ab8c 100644 --- a/lib/new_relic/rack/browser_monitoring.rb +++ b/lib/new_relic/rack/browser_monitoring.rb @@ -20,15 +20,15 @@ class BrowserMonitoring < AgentMiddleware # examine in order to look for a RUM insertion point. SCAN_LIMIT = 50_000 - CONTENT_TYPE = 'Content-Type'.freeze - CONTENT_DISPOSITION = 'Content-Disposition'.freeze - CONTENT_LENGTH = 'Content-Length'.freeze + CONTENT_TYPE = 'Content-Type' + CONTENT_DISPOSITION = 'Content-Disposition' + CONTENT_LENGTH = 'Content-Length' ATTACHMENT = /attachment/.freeze TEXT_HTML = %r{text/html}.freeze - BODY_START = ']+charset\s*=[^>]*>/im.freeze @@ -120,8 +120,16 @@ def attachment?(headers) end def streaming?(env, headers) - # Chunked transfer encoding is a streaming data transfer mechanism available only in HTTP/1.1 - return true if headers && headers['Transfer-Encoding'] == 'chunked' + # Up until version 8.0, Rails would set 'Transfer-Encoding' to 'chunked' + # to trigger the desired HTTP/1.1 based streaming functionality in Rack. + # With version v8.0+, Rails assumes that the web server will be using + # Rack v3+ or an equally modern alternative and simply leaves the + # streaming behavior up to them. + if Rails::VERSION::MAJOR >= 8 + return true if headers['cache-control'] == 'no-cache' && !headers.key?(CONTENT_LENGTH) + else + return true if headers && headers['Transfer-Encoding'] == 'chunked' + end defined?(ActionController::Live) && env['action_controller.instance'].class.included_modules.include?(ActionController::Live) diff --git a/test/multiverse/suites/rails/action_controller_other_test.rb b/test/multiverse/suites/rails/action_controller_other_test.rb index 410d15aa3c..c5be7a6d84 100644 --- a/test/multiverse/suites/rails/action_controller_other_test.rb +++ b/test/multiverse/suites/rails/action_controller_other_test.rb @@ -78,7 +78,9 @@ def test_send_data end def test_send_stream - skip unless rails_version_at_least?('7.2') + # rails/rails@ed68af0 now defers all streaming behavior over to Rack (v3+) itself, so test + # only versions >= 7.2 and < 8.0 + skip unless rails_version_at_least?('7.2') && !rails_version_at_least?('8.0.0.alpha') get('/data/send_test_stream') assert_metrics_recorded(['Controller/data/send_test_stream', 'Ruby/ActionController/send_stream']) From 37d26c9218e36c09ca29d8e04e1bda5cb9ad5ee2 Mon Sep 17 00:00:00 2001 From: Tanna McClure Date: Wed, 17 Jul 2024 12:29:38 -0500 Subject: [PATCH 089/109] add config reset to prevent leaky tests --- test/new_relic/control/security_interface_test.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/new_relic/control/security_interface_test.rb b/test/new_relic/control/security_interface_test.rb index 9f3994c32e..3746d79587 100644 --- a/test/new_relic/control/security_interface_test.rb +++ b/test/new_relic/control/security_interface_test.rb @@ -7,6 +7,7 @@ class NewRelic::Control::SecurityInterfaceTest < Minitest::Test def setup + NewRelic::Agent.config.reset_to_defaults %i[@agent_started @wait].each do |variable| instance = NewRelic::Control::SecurityInterface.instance instance.remove_instance_variable(variable) if instance.instance_variable_defined?(variable) From 9e552c987db29f3b51852ba667cba37d8f423faf Mon Sep 17 00:00:00 2001 From: Tanna McClure Date: Wed, 17 Jul 2024 15:21:43 -0500 Subject: [PATCH 090/109] reset metrics for tests --- test/new_relic/control/security_interface_test.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/new_relic/control/security_interface_test.rb b/test/new_relic/control/security_interface_test.rb index 3746d79587..8eee07c86e 100644 --- a/test/new_relic/control/security_interface_test.rb +++ b/test/new_relic/control/security_interface_test.rb @@ -7,6 +7,7 @@ class NewRelic::Control::SecurityInterfaceTest < Minitest::Test def setup + reset_supportability_metrics NewRelic::Agent.config.reset_to_defaults %i[@agent_started @wait].each do |variable| instance = NewRelic::Control::SecurityInterface.instance @@ -24,8 +25,6 @@ def assert_supportability_metrics_enabled end def test_initialization_short_circuits_when_the_security_agent_is_disabled - reset_supportability_metrics - logger = MiniTest::Mock.new with_config('security.agent.enabled' => false, 'high_security' => false) do NewRelic::Agent.stub :logger, logger do From 3c3e8c1d1cfb06ddb18f38497cc445485cf9ea1f Mon Sep 17 00:00:00 2001 From: fallwith Date: Wed, 17 Jul 2024 13:36:00 -0700 Subject: [PATCH 091/109] Browser monitoring: revert Rails v8 driven change Rails leaves things up to Rack, and so should we --- lib/new_relic/rack/browser_monitoring.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/new_relic/rack/browser_monitoring.rb b/lib/new_relic/rack/browser_monitoring.rb index 94e4a8ab8c..0401e0e337 100644 --- a/lib/new_relic/rack/browser_monitoring.rb +++ b/lib/new_relic/rack/browser_monitoring.rb @@ -125,11 +125,7 @@ def streaming?(env, headers) # With version v8.0+, Rails assumes that the web server will be using # Rack v3+ or an equally modern alternative and simply leaves the # streaming behavior up to them. - if Rails::VERSION::MAJOR >= 8 - return true if headers['cache-control'] == 'no-cache' && !headers.key?(CONTENT_LENGTH) - else - return true if headers && headers['Transfer-Encoding'] == 'chunked' - end + return true if headers && headers['Transfer-Encoding'] == 'chunked' defined?(ActionController::Live) && env['action_controller.instance'].class.included_modules.include?(ActionController::Live) From 73c5f2833b507d90f1ec50628848459fe4bdbd64 Mon Sep 17 00:00:00 2001 From: fallwith Date: Wed, 17 Jul 2024 14:08:30 -0700 Subject: [PATCH 092/109] Browser agent test: Rails v8 exemption Rails v8 won't set the "chunked" header value, so don't expect it for Rails v8+ --- test/agent_helper.rb | 9 +++++++++ .../suites/rails/action_controller_live_rum_test.rb | 3 +++ .../suites/rails/action_controller_other_test.rb | 9 --------- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/test/agent_helper.rb b/test/agent_helper.rb index dbcabd1955..f53f4b7af3 100644 --- a/test/agent_helper.rb +++ b/test/agent_helper.rb @@ -1043,3 +1043,12 @@ def first_call_for(subject) def ruby_version_float RUBY_VERSION.split('.')[0..1].join('.').to_f end + +def rails_version + @rails_version ||= Gem::Version.new(Rails::VERSION::STRING) +end + +def rails_version_at_least?(version_string) + version_string += '.0' until version_string.count('.') >= 2 # '7' => '7.0.0' + rails_version >= Gem::Version.new(version_string) +end diff --git a/test/multiverse/suites/rails/action_controller_live_rum_test.rb b/test/multiverse/suites/rails/action_controller_live_rum_test.rb index ed21ace9d8..053c3c20e0 100644 --- a/test/multiverse/suites/rails/action_controller_live_rum_test.rb +++ b/test/multiverse/suites/rails/action_controller_live_rum_test.rb @@ -42,6 +42,9 @@ def test_excludes_rum_instrumentation_when_streaming_with_action_controller_live end def test_excludes_rum_instrumentation_when_streaming_with_action_stream_true + # Rails 8 stopped using the 'chunked' header value and defers all streaming responsibilities to Rack + skip if rails_version_at_least?('8.0.0.alpha') + get('/undead/brain_stream', env: {'HTTP_VERSION' => 'HTTP/1.1'}) assert_predicate(response, :ok?, 'Expected ActionController streaming response to be OK') diff --git a/test/multiverse/suites/rails/action_controller_other_test.rb b/test/multiverse/suites/rails/action_controller_other_test.rb index c5be7a6d84..799ed069a8 100644 --- a/test/multiverse/suites/rails/action_controller_other_test.rb +++ b/test/multiverse/suites/rails/action_controller_other_test.rb @@ -228,15 +228,6 @@ def controller_class private - def rails_version - @rails_version ||= Gem::Version.new(Rails::VERSION::STRING) - end - - def rails_version_at_least?(version_string) - version_string += '.0' until version_string.count('.') >= 2 # '7' => '7.0.0' - rails_version >= Gem::Version.new(version_string) - end - def confirm_key_exists_in_params(node) assertion_failure = "Expected to find the cache key >>#{DataController::CACHE_KEY}<< in the node params!" # Rails v7.2+ stores the URI string, so look for the key on the end of it From 5a94b9bb2d823d6a81988f301003d8071206e3d2 Mon Sep 17 00:00:00 2001 From: fallwith Date: Wed, 17 Jul 2024 15:29:54 -0700 Subject: [PATCH 093/109] ActiveRecord test updates - support Rails v8.0 - drop testing logic for Rails < v4.0 --- .../active_record/active_record_test.rb | 207 ++++++------------ .../active_record_pg/active_record_test.rb | 128 ++++------- 2 files changed, 102 insertions(+), 233 deletions(-) diff --git a/test/multiverse/suites/active_record/active_record_test.rb b/test/multiverse/suites/active_record/active_record_test.rb index 4fc0f0e1b9..6cc148c27d 100644 --- a/test/multiverse/suites/active_record/active_record_test.rb +++ b/test/multiverse/suites/active_record/active_record_test.rb @@ -8,35 +8,6 @@ class ActiveRecordInstrumentationTest < Minitest::Test include MultiverseHelpers setup_and_teardown_agent - module VersionHelpers - def active_record_major_version - if defined?(::ActiveRecord::VERSION::MAJOR) - ::ActiveRecord::VERSION::MAJOR.to_i - else - 2 - end - end - - def active_record_minor_version - if defined?(::ActiveRecord::VERSION::MINOR) - ::ActiveRecord::VERSION::MINOR.to_i - else - 1 - end - end - - def active_record_version - if defined?(::ActiveRecord::VERSION::MINOR) - Gem::Version.new(::ActiveRecord::VERSION::STRING) - else - Gem::Version.new('2.1.0') # Can't tell between 2.1 and 2.2. Meh. - end - end - end - - include VersionHelpers - extend VersionHelpers - def after_setup super NewRelic::Agent.drop_buffered_data @@ -51,31 +22,23 @@ def test_metrics_for_calculation_methods Order.sum(:id) end - if active_record_major_version >= 3 - assert_activerecord_metrics(Order, 'select', :call_count => 5) - else - assert_generic_rollup_metrics('select') - end + assert_activerecord_metrics(Order, 'select', :call_count => 5) end - if active_record_version >= Gem::Version.new('3.2.0') - def test_metrics_for_pluck - in_web_transaction do - Order.pluck(:id) - end - - assert_activerecord_metrics(Order, 'select') + def test_metrics_for_pluck + in_web_transaction do + Order.pluck(:id) end - end - if active_record_version >= Gem::Version.new('4.0.0') - def test_metrics_for_ids - in_web_transaction do - Order.ids - end + assert_activerecord_metrics(Order, 'select') + end - assert_activerecord_metrics(Order, 'select') + def test_metrics_for_ids + in_web_transaction do + Order.ids end + + assert_activerecord_metrics(Order, 'select') end def test_metrics_for_create @@ -98,11 +61,7 @@ def test_metrics_for_create_via_association def test_metrics_for_find in_web_transaction do - if active_record_major_version >= 4 - Order.where(:name => 'foo').load - else - Order.find_all_by_name('foo') - end + Order.where(:name => 'foo').load end assert_activerecord_metrics(Order, 'find') @@ -120,38 +79,19 @@ def test_metrics_for_find_via_association def test_metrics_for_find_all in_web_transaction do - case - when active_record_major_version >= 4 - Order.all.load - when active_record_major_version >= 3 - Order.all - else - Order.find(:all) - end + Order.all.load end assert_activerecord_metrics(Order, 'find') end def test_metrics_for_find_via_named_scope - major_version = active_record_major_version - minor_version = active_record_minor_version Order.class_eval do - if major_version >= 4 - scope(:jeffs, lambda { where(:name => 'Jeff') }) - elsif major_version == 3 && minor_version >= 1 - scope(:jeffs, :conditions => {:name => 'Jeff'}) - else - named_scope(:jeffs, :conditions => {:name => 'Jeff'}) - end + scope(:jeffs, lambda { where(:name => 'Jeff') }) end in_web_transaction do - if active_record_major_version >= 4 - Order.jeffs.load - else - Order.jeffs.find(:all) - end + Order.jeffs.load end assert_activerecord_metrics(Order, 'find') @@ -162,12 +102,7 @@ def test_metrics_for_exists Order.exists?(['name=?', 'jeff']) end - if active_record_major_version == 3 && [0, 1].include?(active_record_minor_version) - # Bugginess in Rails 3.0 and 3.1 doesn't let us get ActiveRecord/find - assert_generic_rollup_metrics('select') - else - assert_activerecord_metrics(Order, 'find') - end + assert_activerecord_metrics(Order, 'find') end def test_metrics_for_update_all @@ -192,11 +127,7 @@ def test_metrics_for_delete_all Order.delete_all end - if active_record_major_version >= 3 - assert_activerecord_metrics(Order, 'delete') - else - assert_generic_rollup_metrics('delete') - end + assert_activerecord_metrics(Order, 'delete') end def test_metrics_for_relation_delete @@ -205,32 +136,25 @@ def test_metrics_for_relation_delete Order.delete(order.id) end - if active_record_major_version >= 3 - assert_activerecord_metrics(Order, 'delete') - else - assert_generic_rollup_metrics('delete') - end + assert_activerecord_metrics(Order, 'delete') end - # delete and touch did not exist in AR 2.2 - if active_record_version >= Gem::Version.new('3.0.0') - def test_metrics_for_delete - in_web_transaction do - order = Order.create('name' => 'burt') - order.delete - end - - assert_activerecord_metrics(Order, 'delete') + def test_metrics_for_delete + in_web_transaction do + order = Order.create('name' => 'burt') + order.delete end - def test_metrics_for_touch - in_web_transaction do - order = Order.create('name' => 'wendy') - order.touch - end + assert_activerecord_metrics(Order, 'delete') + end - assert_activerecord_metrics(Order, 'update') + def test_metrics_for_touch + in_web_transaction do + order = Order.create('name' => 'wendy') + order.touch end + + assert_activerecord_metrics(Order, 'update') end def test_metrics_for_relation_update @@ -252,11 +176,7 @@ def test_create_via_association_equal u.groups = groups end - if active_record_major_version >= 3 - assert_activerecord_metrics(Group, 'create') - else - assert_generic_rollup_metrics('insert') - end + assert_activerecord_metrics(Group, 'create') end # Can be Mysql2::Error or ActiveRecord::RecordNotUnique @@ -305,11 +225,7 @@ def test_create_via_association_shovel u.groups << Group.new(:name => 'radiohead') end - if active_record_major_version >= 3 - assert_activerecord_metrics(Group, 'create') - else - assert_generic_rollup_metrics('insert') - end + assert_activerecord_metrics(Group, 'create') end def test_create_via_association_create @@ -318,11 +234,7 @@ def test_create_via_association_create u.groups.create(:name => 'radiohead') end - if active_record_major_version >= 3 - assert_activerecord_metrics(Group, 'create') - else - assert_generic_rollup_metrics('insert') - end + assert_activerecord_metrics(Group, 'create') end def test_create_via_association_create_bang @@ -331,11 +243,7 @@ def test_create_via_association_create_bang u.groups.create!(:name => 'radiohead') end - if active_record_major_version >= 3 - assert_activerecord_metrics(Group, 'create') - else - assert_generic_rollup_metrics('insert') - end + assert_activerecord_metrics(Group, 'create') end def test_destroy_via_dependent_destroy @@ -349,25 +257,22 @@ def test_destroy_via_dependent_destroy assert_activerecord_metrics(Alias, 'delete') end - # update & update! didn't become public until 4.0 - if active_record_version >= Gem::Version.new('4.0.0') - def test_metrics_for_update - in_web_transaction do - order = Order.create(:name => 'wendy') - order.update(:name => 'walter') - end - - assert_activerecord_metrics(Order, 'update') + def test_metrics_for_update + in_web_transaction do + order = Order.create(:name => 'wendy') + order.update(:name => 'walter') end - def test_metrics_for_update_bang - in_web_transaction do - order = Order.create(:name => 'wendy') - order.update!(:name => 'walter') - end + assert_activerecord_metrics(Order, 'update') + end - assert_activerecord_metrics(Order, 'update') + def test_metrics_for_update_bang + in_web_transaction do + order = Order.create(:name => 'wendy') + order.update!(:name => 'walter') end + + assert_activerecord_metrics(Order, 'update') end def test_metrics_for_update_attribute @@ -601,6 +506,8 @@ def test_with_database_metric_name ## helpers + private + def adapter adapter_string = Order.configurations[RAILS_ENV]['adapter'] adapter_string.downcase.to_sym @@ -619,12 +526,10 @@ def current_product end def operation_for(op) - is_5_2 = active_record_version >= Gem::Version.new('5.2.0.beta1') - if op == 'create' - active_record_major_version >= 3 && !is_5_2 ? 'insert' : 'create' - elsif op == 'delete' - active_record_major_version >= 3 && !is_5_2 ? 'delete' : 'destroy' + active_record_version_at_least?(5.2) ? 'create' : 'insert' + elsif op == 'delete' && !active_record_version_at_least?(7) + active_record_version_at_least?(5.2) ? 'destroy' : 'delete' else op end @@ -648,4 +553,14 @@ def assert_generic_rollup_metrics(operation) 'Datastore/all' ]) end + + def active_record_version + Gem::Version.new(::ActiveRecord::VERSION::STRING) + end + + def active_record_version_at_least?(version_string) + version_string = version_string.to_s + version_string += '.0' until version_string.count('.') >= 2 # '7' => '7.0.0' + active_record_version >= Gem::Version.new(version_string) + end end diff --git a/test/multiverse/suites/active_record_pg/active_record_test.rb b/test/multiverse/suites/active_record_pg/active_record_test.rb index c670380fd8..8f6eb2ff89 100644 --- a/test/multiverse/suites/active_record_pg/active_record_test.rb +++ b/test/multiverse/suites/active_record_pg/active_record_test.rb @@ -8,31 +8,6 @@ class ActiveRecordInstrumentationTest < Minitest::Test include MultiverseHelpers setup_and_teardown_agent - module VersionHelpers - def active_record_major_version - if defined?(::ActiveRecord::VERSION::MAJOR) - ::ActiveRecord::VERSION::MAJOR.to_i - else - 2 - end - end - - def active_record_minor_version - if defined?(::ActiveRecord::VERSION::MINOR) - ::ActiveRecord::VERSION::MINOR.to_i - else - 1 - end - end - - def active_record_version - Gem::Version.new(::ActiveRecord::VERSION::STRING) - end - end - - include VersionHelpers - extend VersionHelpers - def after_setup super NewRelic::Agent.drop_buffered_data @@ -47,7 +22,7 @@ def test_metrics_for_calculation_methods Order.sum(:id) end - if active_record_major_version >= 7 + if active_record_version_at_least?(7) assert_activerecord_metrics(Order, 'find') else assert_activerecord_metrics(Order, 'select', call_count: '>= 5') @@ -59,7 +34,7 @@ def test_metrics_for_pluck Order.pluck(:id) end - if active_record_major_version >= 7 + if active_record_version_at_least?(7) assert_activerecord_metrics(Order, 'pluck') else assert_activerecord_metrics(Order, 'select') @@ -71,12 +46,10 @@ def test_metrics_for_ids Order.ids end - if active_record_major_version >= 7 - if active_record_minor_version >= 1 - assert_activerecord_metrics(Order, 'ids') - else - assert_activerecord_metrics(Order, 'pluck') - end + if active_record_version_at_least?(7.1) + assert_activerecord_metrics(Order, 'ids') + elsif active_record_version_at_least?(7) + assert_activerecord_metrics(Order, 'pluck') else assert_activerecord_metrics(Order, 'select') end @@ -102,11 +75,7 @@ def test_metrics_for_create_via_association def test_metrics_for_find in_web_transaction do - if active_record_major_version >= 4 - Order.where(:name => 'foo').load - else - Order.find_all_by_name('foo') - end + Order.where(:name => 'foo').load end assert_activerecord_metrics(Order, 'find') @@ -124,35 +93,19 @@ def test_metrics_for_find_via_association def test_metrics_for_find_all in_web_transaction do - if active_record_major_version >= 4 - Order.all.load - else - Order.all - end + Order.all.load end assert_activerecord_metrics(Order, 'find') end def test_metrics_for_find_via_named_scope - major_version = active_record_major_version - minor_version = active_record_minor_version Order.class_eval do - if major_version >= 4 - scope(:jeffs, lambda { where(:name => 'Jeff') }) - elsif major_version == 3 && minor_version >= 1 - scope(:jeffs, :conditions => {:name => 'Jeff'}) - else - named_scope(:jeffs, :conditions => {:name => 'Jeff'}) - end + scope(:jeffs, lambda { where(:name => 'Jeff') }) end in_web_transaction do - if active_record_major_version >= 4 Order.jeffs.load - else - Order.jeffs.find(:all) - end end assert_activerecord_metrics(Order, 'find') @@ -163,7 +116,7 @@ def test_metrics_for_exists Order.exists?(['name=?', 'jeff']) end - if active_record_major_version >= 6 + if active_record_version_at_least?(6) assert_activerecord_metrics(Order, 'exists?') else assert_activerecord_metrics(Order, 'find') @@ -210,7 +163,7 @@ def test_metrics_for_delete order.delete end - if active_record_major_version >= 7 + if active_record_version_at_least?(7) assert_activerecord_metrics(Order, 'destroy') else assert_activerecord_metrics(Order, 'delete') @@ -322,7 +275,7 @@ def test_destroy_via_dependent_destroy u.destroy end - if active_record_major_version >= 7 + if active_record_version_at_least?(7) assert_activerecord_metrics(User, 'destroy') assert_activerecord_metrics(Alias, 'destroy') else @@ -331,25 +284,22 @@ def test_destroy_via_dependent_destroy end end - # update & update! didn't become public until 4.0 - if active_record_version >= Gem::Version.new('4.0.0') - def test_metrics_for_update - in_web_transaction do - order = Order.create(:name => 'wendy') - order.update(:name => 'walter') - end - - assert_activerecord_metrics(Order, 'update') + def test_metrics_for_update + in_web_transaction do + order = Order.create(:name => 'wendy') + order.update(:name => 'walter') end - def test_metrics_for_update_bang - in_web_transaction do - order = Order.create(:name => 'wendy') - order.update!(:name => 'walter') - end + assert_activerecord_metrics(Order, 'update') + end - assert_activerecord_metrics(Order, 'update') + def test_metrics_for_update_bang + in_web_transaction do + order = Order.create(:name => 'wendy') + order.update!(:name => 'walter') end + + assert_activerecord_metrics(Order, 'update') end def test_metrics_for_update_attribute @@ -398,7 +348,7 @@ def test_metrics_for_destroy order.destroy end - if active_record_major_version >= 7 + if active_record_version_at_least?(7) assert_activerecord_metrics(Order, 'destroy') else assert_activerecord_metrics(Order, 'delete') @@ -586,7 +536,7 @@ def test_with_database_metric_name end def test_metrics_for_async_find_by_sql - skip_unless_active_record_7_1_or_above + skip unless active_record_version_at_least?(7.1) in_web_transaction do Order.async_find_by_sql('SELECT * FROM orders') @@ -596,7 +546,7 @@ def test_metrics_for_async_find_by_sql end def test_metrics_for_async_count_by_sql - skip_unless_active_record_7_1_or_above + skip unless active_record_version_at_least?(7.1) in_web_transaction do Order.create(:name => 'wendy') @@ -607,7 +557,7 @@ def test_metrics_for_async_count_by_sql end def test_metrics_for_async_pluck - skip_unless_active_record_7_1_or_above + skip unless active_record_version_at_least?(7.1) in_web_transaction do Order.async_pluck(:id) @@ -617,7 +567,7 @@ def test_metrics_for_async_pluck end def test_metrics_for_async_calculation_methods - skip_unless_active_record_7_1_or_above + skip unless active_record_version_at_least?(7.1) in_web_transaction do Order.async_count @@ -631,6 +581,7 @@ def test_metrics_for_async_calculation_methods end ## helpers + private def adapter # ActiveRecord::Base.configurations[NewRelic::Control.instance.env]['adapter'] @@ -654,13 +605,10 @@ def current_product end def operation_for(op) - is_greater_than_5_2 = active_record_version >= Gem::Version.new('5.2.0.beta1') - is_less_than_7_0 = active_record_version < Gem::Version.new('7.0.0.alpha1') - if op == 'create' - !is_greater_than_5_2 ? 'insert' : 'create' - elsif op == 'delete' && is_less_than_7_0 - !is_greater_than_5_2 ? 'delete' : 'destroy' + active_record_version_at_least?(5.2) ? 'create' : 'insert' + elsif op == 'delete' && !active_record_version_at_least?(7) + active_record_version_at_least?(5.2) ? 'destroy' : 'delete' else op end @@ -685,7 +633,13 @@ def assert_generic_rollup_metrics(operation) ]) end - def skip_unless_active_record_7_1_or_above - skip unless active_record_major_version >= 7 && active_record_minor_version >= 1 + def active_record_version + Gem::Version.new(::ActiveRecord::VERSION::STRING) + end + + def active_record_version_at_least?(version_string) + version_string = version_string.to_s + version_string += '.0' until version_string.count('.') >= 2 # '7' => '7.0.0' + active_record_version >= Gem::Version.new(version_string) end end From 1bb14e9dba87c9e3735f134b562d46502f5c75da Mon Sep 17 00:00:00 2001 From: fallwith Date: Wed, 17 Jul 2024 15:35:00 -0700 Subject: [PATCH 094/109] indentation fix fix resulting from 5a94b9b --- test/multiverse/suites/active_record_pg/active_record_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/multiverse/suites/active_record_pg/active_record_test.rb b/test/multiverse/suites/active_record_pg/active_record_test.rb index 8f6eb2ff89..470a267c06 100644 --- a/test/multiverse/suites/active_record_pg/active_record_test.rb +++ b/test/multiverse/suites/active_record_pg/active_record_test.rb @@ -105,7 +105,7 @@ def test_metrics_for_find_via_named_scope end in_web_transaction do - Order.jeffs.load + Order.jeffs.load end assert_activerecord_metrics(Order, 'find') From 863c5f184c10687e651fffb3237c4bd986fa7897 Mon Sep 17 00:00:00 2001 From: Prateek Sen <33506953+prateeksen@users.noreply.github.com> Date: Thu, 18 Jul 2024 10:29:21 +0530 Subject: [PATCH 095/109] Update lib/new_relic/agent/configuration/default_source.rb Co-authored-by: James Bunch --- lib/new_relic/agent/configuration/default_source.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index ab2242c8ed..c94b7b50bb 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -2647,7 +2647,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Integer, :external => true, :allowed_from_server => false, - :description => 'Defines the request body limit to process in security events(In KB). The default value is 300KB.' + :description => 'Defines the request body limit to process in security events (in KB). The default value is 300, for 300KB.' } }.freeze # rubocop:enable Metrics/CollectionLiteralLength From d933a5d066ef8ba3a167a4ad436277a1bf351e27 Mon Sep 17 00:00:00 2001 From: Prateek Sen <33506953+prateeksen@users.noreply.github.com> Date: Thu, 18 Jul 2024 10:29:37 +0530 Subject: [PATCH 096/109] Update lib/new_relic/control/security_interface.rb Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- lib/new_relic/control/security_interface.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/new_relic/control/security_interface.rb b/lib/new_relic/control/security_interface.rb index 05065b30f3..27a11962ef 100644 --- a/lib/new_relic/control/security_interface.rb +++ b/lib/new_relic/control/security_interface.rb @@ -35,7 +35,7 @@ def init_agent @agent_started = true else - Agent.logger.info('New Relic Security is completely disabled by one of the user provided config `security.agent.enabled`, or `high_security`. Not loading security capabilities.') + Agent.logger.info('New Relic Security is completely disabled by one of the user-provided configurations: `security.agent.enabled` or `high_security`. Not loading security capabilities.') Agent.logger.info("high_security = #{Agent.config[:high_security]}") Agent.logger.info("security.agent.enabled = #{Agent.config[:'security.agent.enabled']}") end From db297b85b582ce3fc273476bed28016634de1d85 Mon Sep 17 00:00:00 2001 From: prateek-ap Date: Thu, 18 Jul 2024 10:38:23 +0530 Subject: [PATCH 097/109] PR review suggestions incorporated --- lib/new_relic/agent/configuration/default_source.rb | 6 +++--- lib/new_relic/control/security_interface.rb | 4 ---- newrelic.yml | 4 ++-- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index c94b7b50bb..83f1a96f7a 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -2594,7 +2594,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :public => true, :type => String, :allowed_from_server => true, - :allowlist => %w[IAST RASP], + :allowlist => %w[IAST], :description => 'Defines the mode for the security agent to operate in. Currently only `IAST` is supported', :dynamic_name => true }, @@ -2613,7 +2613,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :public => true, :type => Boolean, :allowed_from_server => false, - :description => 'If `true`, enables RCI detection' + :description => 'If `true`, enables RCI(Remote Code Injection) detection' }, :'security.detection.rxss.enabled' => { :default => true, @@ -2621,7 +2621,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :public => true, :type => Boolean, :allowed_from_server => false, - :description => 'If `true`, enables RXSS detection' + :description => 'If `true`, enables RXSS(Reflected Cross-site Scripting) detection' }, :'security.detection.deserialization.enabled' => { :default => true, diff --git a/lib/new_relic/control/security_interface.rb b/lib/new_relic/control/security_interface.rb index 27a11962ef..7edbea5c62 100644 --- a/lib/new_relic/control/security_interface.rb +++ b/lib/new_relic/control/security_interface.rb @@ -49,10 +49,6 @@ def record_supportability_metrics Agent.config[:'security.agent.enabled'] ? security_agent_metric(ENABLED) : security_agent_metric(DISABLED) end - def security_metric(setting) - NewRelic::Agent.record_metric_once(SUPPORTABILITY_PREFIX_SECURITY + setting) - end - def security_agent_metric(setting) NewRelic::Agent.record_metric_once(SUPPORTABILITY_PREFIX_SECURITY_AGENT + setting) end diff --git a/newrelic.yml b/newrelic.yml index c0390e10f4..f38f26e660 100644 --- a/newrelic.yml +++ b/newrelic.yml @@ -888,10 +888,10 @@ common: &default_settings # Defines the endpoint URL for posting security related data # security.validator_service_url: wss://csec.nr-data.net - # If `true`, enables RCI detection + # If `true`, enables RCI(Remote Code Injection) detection # security.detection.rci.enabled: true - # If `true`, enables RXSS detection + # If `true`, enables RXSS(Reflected Cross-site Scripting) detection # security.detection.rxss.enabled: true # If `true`, enables deserialization detection From bd0d524234ec77023bbefffe935b8e20e1a4f5be Mon Sep 17 00:00:00 2001 From: prateek-ap Date: Mon, 22 Jul 2024 12:37:33 +0530 Subject: [PATCH 098/109] add RASP in allowlist for dev and testing --- lib/new_relic/agent/configuration/default_source.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index 83f1a96f7a..ba72498a5f 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -2594,7 +2594,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :public => true, :type => String, :allowed_from_server => true, - :allowlist => %w[IAST], + :allowlist => %w[IAST RASP], :description => 'Defines the mode for the security agent to operate in. Currently only `IAST` is supported', :dynamic_name => true }, From f114363c94d5d0bf2ae4182b3c4b90d9f09dd69a Mon Sep 17 00:00:00 2001 From: Tanna McClure Date: Mon, 22 Jul 2024 09:03:45 -0500 Subject: [PATCH 099/109] run url test only on its own --- .github/workflows/ci_special.yml | 80 +++++++++++++++++++++++++++++ test/helpers/misc.rb | 6 +++ test/new_relic/healthy_urls_test.rb | 3 +- 3 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/ci_special.yml diff --git a/.github/workflows/ci_special.yml b/.github/workflows/ci_special.yml new file mode 100644 index 0000000000..7a5f61c49f --- /dev/null +++ b/.github/workflows/ci_special.yml @@ -0,0 +1,80 @@ +name: URL Test CI + +on: + schedule: + - cron: '0 9 * * *' + workflow_dispatch: + +jobs: + unit_tests: + runs-on: ubuntu-22.04 + + steps: + - name: Configure git + run: 'git config --global init.defaultBranch main' + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # tag v4.1.2 + + # - curl is needed for Curb + # - xslt is needed for older Nokogiris, RUBY_VERSION < 2.5 + # - sasl is needed for memcached + - name: Install OS packages + run: sudo apt-get update; sudo apt-get install -y --no-install-recommends libcurl4-nss-dev libsasl2-dev libxslt1-dev + + - name: Install Ruby 3.4.0-preview1 + uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f # tag v1.186.0 + with: + ruby-version: 3.4.0-preview1 + + - name: Setup bundler + run: ./.github/workflows/scripts/setup_bundler + env: + RUBY_VERSION: 3.4.0-preview1 + + - name: Run Unit Tests + uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # tag v3.0.0 + with: + timeout_minutes: 30 + max_attempts: 2 + command: TEST=test/new_relic/healthy_urls_test bundle exec rake test + env: + VERBOSE_TEST_OUTPUT: true + SPECIAL_CI: true + + + notify_slack_fail: + name: Notify slack fail + needs: [unit_tests] + runs-on: ubuntu-22.04 + if: always() + steps: + - uses: technote-space/workflow-conclusion-action@45ce8e0eb155657ab8ccf346ade734257fd196a5 # tag v3.0.3 + - uses: voxmedia/github-action-slack-notify-build@3665186a8c1a022b28a1dbe0954e73aa9081ea9e # tag v1.6.0 + if: ${{ env.WORKFLOW_CONCLUSION == 'failure' && github.event_name != 'workflow_dispatch' }} + env: + SLACK_BOT_TOKEN: ${{ secrets.RUBY_GITHUB_ACTIONS_BOT_WEBHOOK }} + with: + channel: ruby-agent-notifications + status: FAILED + color: danger + + + notify_slack_success: + name: Notify slack success + needs: [unit_tests] + runs-on: ubuntu-22.04 + if: always() + steps: + - uses: technote-space/workflow-conclusion-action@45ce8e0eb155657ab8ccf346ade734257fd196a5 # tag v3.0.3 + - run: echo ${{ github.event_name }} + - uses: Mercymeilya/last-workflow-status@3418710aefe8556d73b6f173a0564d38bcfd9a43 # tag v0.3.3 + id: last_status + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + - uses: voxmedia/github-action-slack-notify-build@3665186a8c1a022b28a1dbe0954e73aa9081ea9e # tag v1.6.0 + if: ${{ env.WORKFLOW_CONCLUSION == 'success' && steps.last_status.outputs.last_status == 'failure' && github.event_name != 'workflow_dispatch' }} + env: + SLACK_BOT_TOKEN: ${{ secrets.RUBY_GITHUB_ACTIONS_BOT_WEBHOOK }} + with: + channel: ruby-agent-notifications + status: SUCCESS + color: good diff --git a/test/helpers/misc.rb b/test/helpers/misc.rb index 47717db285..2f0c0b3094 100644 --- a/test/helpers/misc.rb +++ b/test/helpers/misc.rb @@ -131,6 +131,12 @@ def skip_unless_ci_cron skip 'This test only runs as part of the CI cron workflow' end +def skip_unless_special_ci + return if ENV['SPECIAL_CI'] + + skip 'This test only runs as part of the special CI workflow' +end + def agent_root @agent_root ||= File.expand_path('../../..', __FILE__).freeze end diff --git a/test/new_relic/healthy_urls_test.rb b/test/new_relic/healthy_urls_test.rb index a444e9c3e9..d42340fcd5 100644 --- a/test/new_relic/healthy_urls_test.rb +++ b/test/new_relic/healthy_urls_test.rb @@ -70,8 +70,7 @@ class HealthyUrlsTest < Minitest::Test DEBUG = false def test_all_urls - skip_unless_ci_cron - skip_unless_newest_ruby + skip_unless_special_ci urls = gather_urls errors = urls.each_with_object({}) do |(url, _files), hash| From 5d9c813a1a5ebe168cabd11655af49fc7b8ee10b Mon Sep 17 00:00:00 2001 From: Prateek Sen <33506953+prateeksen@users.noreply.github.com> Date: Mon, 22 Jul 2024 22:59:29 +0530 Subject: [PATCH 100/109] Update lib/new_relic/agent/configuration/default_source.rb Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- lib/new_relic/agent/configuration/default_source.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index ba72498a5f..32b281d04e 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -2613,7 +2613,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :public => true, :type => Boolean, :allowed_from_server => false, - :description => 'If `true`, enables RCI(Remote Code Injection) detection' + :description => 'If `true`, enables RCI (remote code injection) detection' }, :'security.detection.rxss.enabled' => { :default => true, From 7c0b4757d2894212f39157df24a3a5d492aaa355 Mon Sep 17 00:00:00 2001 From: Prateek Sen <33506953+prateeksen@users.noreply.github.com> Date: Mon, 22 Jul 2024 22:59:41 +0530 Subject: [PATCH 101/109] Update lib/new_relic/agent/configuration/default_source.rb Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- lib/new_relic/agent/configuration/default_source.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index 32b281d04e..b104da010c 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -2621,7 +2621,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :public => true, :type => Boolean, :allowed_from_server => false, - :description => 'If `true`, enables RXSS(Reflected Cross-site Scripting) detection' + :description => 'If `true`, enables RXSS (reflected cross-site scripting) detection' }, :'security.detection.deserialization.enabled' => { :default => true, From 376e3b1594119a7a6c884d06acef142b9409abb6 Mon Sep 17 00:00:00 2001 From: newrelic-ruby-agent-bot Date: Mon, 22 Jul 2024 21:15:44 +0000 Subject: [PATCH 102/109] bump version --- CHANGELOG.md | 2 +- lib/new_relic/version.rb | 2 +- newrelic.yml | 417 ++++++++++++++++++++------------------- 3 files changed, 220 insertions(+), 201 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee5489d1ce..1ee96bb14a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # New Relic Ruby Agent Release Notes ## -Version introduces instrumentation for the LogStasher gem, improves instrumentation for the `redis-clustering` gem, and updates the Elasticsearch instrumentation to only attempt to get the cluster name once per client, even if it fails. +Version 9.12.0 introduces instrumentation for the LogStasher gem, improves instrumentation for the `redis-clustering` gem, and updates the Elasticsearch instrumentation to only attempt to get the cluster name once per client, even if it fails. - **Feature: Add instrumentation for LogStasher** diff --git a/lib/new_relic/version.rb b/lib/new_relic/version.rb index 3baf6cb032..eb65139f10 100644 --- a/lib/new_relic/version.rb +++ b/lib/new_relic/version.rb @@ -6,7 +6,7 @@ module NewRelic module VERSION # :nodoc: MAJOR = 9 - MINOR = 11 + MINOR = 12 TINY = 0 STRING = "#{MAJOR}.#{MINOR}.#{TINY}" diff --git a/newrelic.yml b/newrelic.yml index f38f26e660..71d5f215fc 100644 --- a/newrelic.yml +++ b/newrelic.yml @@ -26,40 +26,41 @@ common: &default_settings # All of the following configuration options are optional. Review them, and # uncomment or edit them if they appear relevant to your application needs. - # An array of ActiveSupport custom event names to subscribe to and instrument. For - # example, + # An array of ActiveSupport custom event names to subscribe to and instrument. + # For example, # - one.custom.event # - another.event # - a.third.event # active_support_custom_events_names: [] - # If false, all LLM instrumentation (OpenAI only for now) will be disabled and no - # metrics, events, or spans will be sent. AI Monitoring is automatically disabled - # if high_security mode is enabled. + # If false, all LLM instrumentation (OpenAI only for now) will be disabled and + # no metrics, events, or spans will be sent. AI Monitoring is automatically + # disabled if high_security mode is enabled. # ai_monitoring.enabled: false # If false, LLM instrumentation (OpenAI only for now) will not capture input and - # output content on specific LLM events. + # output content on specific + # LLM events. # The excluded attributes include: # * content from LlmChatCompletionMessage events # * input from LlmEmbedding events - # This is an optional security setting to prevent recording sensitive data sent to - # and received from your LLMs. + # This is an optional security setting to prevent recording sensitive data sent + # to and received from your LLMs. # ai_monitoring.record_content.enabled: true # If true, enables capture of all HTTP request headers for all destinations. # allow_all_headers: false - # Your New Relic userKey. Required when using the New Relic REST API v2 to record - # deployments using the newrelic deployments command. + # Your New Relic userKey. Required when using the New Relic REST API v2 to + # record deployments using the newrelic deployments command. # api_key: "" # If true, enables log decoration and the collection of log events and metrics. # application_logging.enabled: true # A hash with key/value pairs to add as custom attributes to all log events - # forwarded to New Relic. If sending using an environment variable, the value must - # be formatted like: "key1=value1,key2=value2" + # forwarded to New Relic. If sending using an environment variable, the value + # must be formatted like: "key1=value1,key2=value2" # application_logging.forwarding.custom_attributes: {} # If true, the agent captures log records emitted by your application. @@ -69,10 +70,12 @@ common: &default_settings # This is based on the integer values of Ruby's Logger::Severity constants: # https://github.com/ruby/ruby/blob/master/lib/logger/severity.rb # The intention is to forward logs with the level given to the configuration, as - # well as any logs with a higher level of severity. + # well as any logs with a + # higher level of severity. # For example, setting this value to "debug" will forward all log events to New - # Relic. Setting this value to "error" will only forward log events with the - # levels "error", "fatal", and "unknown". + # Relic. Setting this value to + # "error" will only forward log events with the levels "error", "fatal", and + # "unknown". # Valid values (ordered lowest to highest): # * "debug" # * "info" @@ -126,16 +129,16 @@ common: &default_settings # instrument. For example, "assets:precompile,db:migrate". # autostart.denylisted_rake_tasks: about,assets:clean,assets:clobber,assets:environment,assets:precompile,assets:precompile:all,db:create,db:drop,db:fixtures:load,db:migrate,db:migrate:status,db:rollback,db:schema:cache:clear,db:schema:cache:dump,db:schema:dump,db:schema:load,db:seed,db:setup,db:structure:dump,db:version,doc:app,log:clear,middleware,notes,notes:custom,rails:template,rails:update,routes,secret,spec,spec:features,spec:requests,spec:controllers,spec:helpers,spec:models,spec:views,spec:routing,spec:rcov,stats,test,test:all,test:all:db,test:recent,test:single,test:uncommitted,time:zones:all,tmp:clear,tmp:create,webpacker:compile - # Backports the faster ActiveRecord connection lookup introduced in Rails 6, which - # improves agent performance when instrumenting ActiveRecord. Note that this - # setting may not be compatible with other gems that patch ActiveRecord. + # Backports the faster ActiveRecord connection lookup introduced in Rails 6, + # which improves agent performance when instrumenting ActiveRecord. Note that + # this setting may not be compatible with other gems that patch ActiveRecord. # backport_fast_active_record_connection_lookup: false # If true, the agent captures attributes from browser monitoring. # browser_monitoring.attributes.enabled: false - # Prefix of attributes to exclude from browser monitoring. Allows * as wildcard at - # end. + # Prefix of attributes to exclude from browser monitoring. Allows * as wildcard + # at end. # browser_monitoring.attributes.exclude: [] # Prefix of attributes to include in browser monitoring. Allows * as wildcard at @@ -159,18 +162,24 @@ common: &default_settings # capture_memcache_keys: false # When true, the agent captures HTTP request parameters and attaches them to - # transaction traces, traced errors, and TransactionError events. - # When using the capture_params setting, the Ruby agent will not attempt to filter - # secret information. Recommendation: To filter secret information from request - # parameters, use the attributes.include setting instead. For more information, - # see the Ruby attribute examples. + # transaction traces, traced + # errors, and TransactionError events. + # When using the capture_params setting, the Ruby agent will not attempt to + # filter secret information. + # Recommendation: To filter secret information from request parameters, use the + # attributes.include setting + # instead. For more information, see the + # Ruby + # attribute + # examples. # capture_params: false # If true, the agent will clear Tracer::State in Agent.drop_buffered_data. # clear_transaction_state_after_fork: false # If true, the agent will report source code level metrics for traced methods. - # see: + # See: # https://docs.newrelic.com/docs/apm/agents/ruby-agent/features/ruby-codestream-integration/ # code_level_metrics.enabled: true @@ -188,17 +197,17 @@ common: &default_settings # If true, the agent captures custom events. # custom_insights_events.enabled: true - # * Specify a maximum number of custom events to buffer in memory at a time.' + # * Specify a maximum number of custom events to buffer in memory at a time. # * When configuring the agent for AI monitoring, set to max value 100000. This # ensures the agent captures the maximum amount of LLM events. # custom_insights_events.max_samples_stored: 3000 - # If false, the agent will not add database_name parameter to transaction or slow - # sql traces. + # If false, the agent will not add database_name parameter to transaction or + # slow sql traces. # datastore_tracer.database_name_reporting.enabled: true - # If false, the agent will not report datastore instance metrics, nor add host or - # port_path_or_id parameters to transaction or slow SQL traces. + # If false, the agent will not report datastore instance metrics, nor add host + # or port_path_or_id parameters to transaction or slow SQL traces. # datastore_tracer.instance_reporting.enabled: true # If true, disables Action Cable instrumentation. @@ -242,18 +251,20 @@ common: &default_settings # disable_memory_sampler: false # If true, the agent won't wrap third-party middlewares in instrumentation - # (regardless of whether they are installed via Rack::Builder or Rails). + # (regardless of whether they are + # installed via Rack::Builder or Rails). # When middleware instrumentation is disabled, if an application is using - # middleware that could alter the response code, the HTTP status code reported on - # the transaction may not reflect the altered value. + # middleware that could alter the + # response code, the HTTP status code reported on the transaction may not + # reflect the altered value. # disable_middleware_instrumentation: false - # If true, disables agent middleware for Roda. This middleware is responsible for - # advanced feature support such as page load timing and error collection. + # If true, disables agent middleware for Roda. This middleware is responsible + # for advanced feature support such as page load timing and error collection. # disable_roda_auto_middleware: false - # If true, disables the collection of sampler metrics. Sampler metrics are metrics - # that are not event-based (such as CPU time or memory usage). + # If true, disables the collection of sampler metrics. Sampler metrics are + # metrics that are not event-based (such as CPU time or memory usage). # disable_samplers: false # If true, disables Sequel instrumentation. @@ -263,13 +274,19 @@ common: &default_settings # disable_sidekiq: false # If true, disables agent middleware for Sinatra. This middleware is responsible - # for advanced feature support such as cross application tracing, page load - # timing, and error collection. - # Cross application tracing is deprecated in favor of distributed tracing. + # for advanced feature + # support such as + # cross application tracing, + # page load timing, and + # error collection. + # Cross application tracing is deprecated in favor of + # distributed tracing. # Distributed tracing is on by default for Ruby agent versions 8.0.0 and above. - # Middlewares are not required to support distributed tracing. + # Middlewares are not + # required to support distributed tracing. # To continue using cross application tracing, update the following options in - # your newrelic.yml configuration file: + # your newrelic.yml + # configuration file: # ``yaml # # newrelic.yml # cross_application_tracer: @@ -287,8 +304,8 @@ common: &default_settings # Distributed tracing lets you see the path that a request takes through your # distributed system. Enabling distributed tracing changes the behavior of some - # New Relic features, so carefully consult the transition guide before you enable - # this feature. + # New Relic features, so carefully consult the transition guide before you + # enable this feature. # distributed_tracing.enabled: true # If true, the agent captures Elasticsearch queries in transaction traces. @@ -319,8 +336,10 @@ common: &default_settings # error_collector.expected_classes: [] # A map of error classes to a list of messages. When an error of one of the - # classes specified here occurs, if its error message contains one of the strings - # corresponding to it here, that error will be treated as expected. + # classes specified here occurs, if + # its error message contains one of the strings corresponding to it here, that + # error will be treated as + # expected. # This option can't be set via environment variable. # error_collector.expected_messages: {} @@ -334,8 +353,9 @@ common: &default_settings # error_collector.ignore_classes: ["ActionController::RoutingError", "Sinatra::NotFound"] # A map of error classes to a list of messages. When an error of one of the - # classes specified here occurs, if its error message contains one of the strings - # corresponding to it here, that error will be ignored. + # classes specified here occurs, if + # its error message contains one of the strings corresponding to it here, that + # error will be ignored. # This option can't be set via environment variable. # error_collector.ignore_messages: {} @@ -343,9 +363,9 @@ common: &default_settings # associated with these status codes, where applicable, will be ignored. # error_collector.ignore_status_codes: "" - # Defines the maximum number of frames in an error backtrace. Backtraces over this - # amount are truncated in the middle, preserving the beginning and the end of the - # stack trace. + # Defines the maximum number of frames in an error backtrace. Backtraces over + # this amount are truncated in the middle, preserving the beginning and the end + # of the stack trace. # error_collector.max_backtrace_frames: 50 # Defines the maximum number of TransactionError events reported per harvest @@ -357,18 +377,23 @@ common: &default_settings # exclude_newrelic_header: false # The exit handler that sends all cached data to the collector before shutting - # down is forcibly installed. This is true even when it detects scenarios where it - # generally should not be. The known use case for this option is when Sinatra runs - # as an embedded service within another framework. The agent detects the Sinatra + # down is forcibly installed. + # This is true even when it detects scenarios where it generally should not be. + # The known use case for this + # option is when Sinatra runs as an embedded service within another framework. + # The agent detects the Sinatra # app and skips 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. + # 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. # force_install_exit_handler: false - # Ordinarily the agent reports dyno names with a trailing dot and process ID (for - # example, worker.3). You can remove this trailing data by specifying the prefixes - # you want to report without trailing data (for example, worker). + # Ordinarily the agent reports dyno names with a trailing dot and process ID + # (for example, worker.3). You can remove this trailing data by specifying the + # prefixes you want to report without trailing data (for example, worker). # heroku.dyno_name_prefixes_to_shorten: ["scheduler", "run"] # If true, the agent uses Heroku dyno names as the hostname. @@ -395,8 +420,8 @@ common: &default_settings # Configures the TCP/IP port for the trace observer Host # infinite_tracing.trace_observer.port: 443 - # Controls auto-instrumentation of ActiveSupport::BroadcastLogger at start up. May - # be one of: auto, prepend, chain, disabled. Used in Rails versions >= 7.1. + # Controls auto-instrumentation of ActiveSupport::BroadcastLogger at start up. + # May be one of: auto, prepend, chain, disabled. Used in Rails versions >= 7.1. # instrumentation.active_support_broadcast_logger: auto # Controls auto-instrumentation of ActiveSupport::Logger at start up. May be one @@ -407,20 +432,20 @@ common: &default_settings # prepend, chain, disabled. # instrumentation.async_http: auto - # Controls auto-instrumentation of the aws-sdk-sqs library at start-up. May be one - # of: auto, prepend, chain, disabled. + # Controls auto-instrumentation of the aws-sdk-sqs library at start-up. May be + # one of: auto, prepend, chain, disabled. # instrumentation.aws_sqs: auto # Controls auto-instrumentation of bunny at start-up. May be one of: auto, # prepend, chain, disabled. # instrumentation.bunny: auto - # Controls auto-instrumentation of the concurrent-ruby library at start-up. May be - # one of: auto, prepend, chain, disabled. + # Controls auto-instrumentation of the concurrent-ruby library at start-up. May + # be one of: auto, prepend, chain, disabled. # instrumentation.concurrent_ruby: auto - # Controls auto-instrumentation of Curb at start-up. May be one of: auto, prepend, - # chain, disabled. + # Controls auto-instrumentation of Curb at start-up. May be one of: auto, + # prepend, chain, disabled. # instrumentation.curb: auto # Controls auto-instrumentation of Delayed Job at start-up. May be one of: auto, @@ -435,8 +460,8 @@ common: &default_settings # one of: auto, prepend, chain, disabled. # instrumentation.elasticsearch: auto - # Controls auto-instrumentation of ethon at start up. May be one of auto, prepend, - # chain, disabled + # Controls auto-instrumentation of ethon at start up. May be one of auto, + # prepend, chain, disabled # instrumentation.ethon: auto # Controls auto-instrumentation of Excon at start-up. May be one of: enabled, @@ -454,18 +479,18 @@ common: &default_settings # Specifies a list of hostname patterns separated by commas that will match gRPC # hostnames that traffic is to be ignored by New Relic for. New Relic's gRPC # client instrumentation will ignore traffic streamed to a host matching any of - # these patterns, and New Relic's gRPC server instrumentation will ignore traffic - # for a server running on a host whose hostname matches any of these patterns. By - # default, no traffic is ignored when gRPC instrumentation is itself enabled. For - # example, "private.com$,exception.*" + # these patterns, and New Relic's gRPC server instrumentation will ignore + # traffic for a server running on a host whose hostname matches any of these + # patterns. By default, no traffic is ignored when gRPC instrumentation is + # itself enabled. For example, "private.com$,exception.*" # instrumentation.grpc.host_denylist: [] - # Controls auto-instrumentation of gRPC clients at start-up. May be one of: auto, - # prepend, chain, disabled. + # Controls auto-instrumentation of gRPC clients at start-up. May be one of: + # auto, prepend, chain, disabled. # instrumentation.grpc_client: auto - # Controls auto-instrumentation of gRPC servers at start-up. May be one of: auto, - # prepend, chain, disabled. + # Controls auto-instrumentation of gRPC servers at start-up. May be one of: + # auto, prepend, chain, disabled. # instrumentation.grpc_server: auto # Controls auto-instrumentation of HTTPClient at start-up. May be one of: auto, @@ -476,24 +501,28 @@ common: &default_settings # prepend, chain, disabled. # instrumentation.httprb: auto - # Controls auto-instrumentation of httpx at start up. May be one of auto, prepend, - # chain, disabled + # Controls auto-instrumentation of httpx at start up. May be one of auto, + # prepend, chain, disabled # instrumentation.httpx: auto # Controls auto-instrumentation of Ruby standard library Logger at start-up. May # be one of: auto, prepend, chain, disabled. # instrumentation.logger: auto - # Controls auto-instrumentation of dalli gem for Memcache at start-up. May be one - # of: auto, prepend, chain, disabled. + # Controls auto-instrumentation of the LogStasher library at start-up. May be + # one of [auto|prepend|chain|disabled]. + # instrumentation.logstasher: auto + + # Controls auto-instrumentation of dalli gem for Memcache at start-up. May be + # one of: auto, prepend, chain, disabled. # instrumentation.memcache: auto # Controls auto-instrumentation of memcache-client gem for Memcache at start-up. # May be one of: auto, prepend, chain, disabled. # instrumentation.memcache_client: auto - # Controls auto-instrumentation of memcached gem for Memcache at start-up. May be - # one of: auto, prepend, chain, disabled. + # Controls auto-instrumentation of memcached gem for Memcache at start-up. May + # be one of: auto, prepend, chain, disabled. # instrumentation.memcached: auto # Controls auto-instrumentation of Mongo at start-up. May be one of: enabled, @@ -504,13 +533,13 @@ common: &default_settings # prepend, chain, disabled. # instrumentation.net_http: auto - # Controls auto-instrumentation of Puma::Rack. When enabled, the agent hooks into - # the to_app method in Puma::Rack::Builder to find gems to instrument during - # application startup. May be one of: auto, prepend, chain, disabled. + # Controls auto-instrumentation of Puma::Rack. When enabled, the agent hooks + # into the to_app method in Puma::Rack::Builder to find gems to instrument + # during application startup. May be one of: auto, prepend, chain, disabled. # instrumentation.puma_rack: auto - # Controls auto-instrumentation of Puma::Rack::URLMap at start-up. May be one of: - # auto, prepend, chain, disabled. + # Controls auto-instrumentation of Puma::Rack::URLMap at start-up. May be one + # of: auto, prepend, chain, disabled. # instrumentation.puma_rack_urlmap: auto # Controls auto-instrumentation of Rack. When enabled, the agent hooks into the @@ -518,12 +547,12 @@ common: &default_settings # startup. May be one of: auto, prepend, chain, disabled. # instrumentation.rack: auto - # Controls auto-instrumentation of Rack::URLMap at start-up. May be one of: auto, - # prepend, chain, disabled. + # Controls auto-instrumentation of Rack::URLMap at start-up. May be one of: + # auto, prepend, chain, disabled. # instrumentation.rack_urlmap: auto - # Controls auto-instrumentation of rake at start-up. May be one of: auto, prepend, - # chain, disabled. + # Controls auto-instrumentation of rake at start-up. May be one of: auto, + # prepend, chain, disabled. # instrumentation.rake: auto # Controls auto-instrumentation of Redis at start-up. May be one of: auto, @@ -534,12 +563,13 @@ common: &default_settings # prepend, chain, disabled. # instrumentation.resque: auto - # Controls auto-instrumentation of Roda at start-up. May be one of: auto, prepend, - # chain, disabled. + # Controls auto-instrumentation of Roda at start-up. May be one of: auto, + # prepend, chain, disabled. # instrumentation.roda: auto - # 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. + # 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. # instrumentation.ruby_openai: auto # Controls auto-instrumentation of Sinatra at start-up. May be one of: auto, @@ -548,12 +578,13 @@ common: &default_settings # Controls auto-instrumentation of Stripe at startup. May be one of: enabled, # disabled. - # instrumentation.stripe: enabled + # instrumentation.stripe: auto - # Controls auto-instrumentation of the Thread class at start-up to allow the agent - # to correctly nest spans inside of an asynchronous transaction. This does not - # enable the agent to automatically trace all threads created (see - # instrumentation.thread.tracing). May be one of: auto, prepend, chain, disabled. + # Controls auto-instrumentation of the Thread class at start-up to allow the + # agent to correctly nest spans inside of an asynchronous transaction. This does + # not enable the agent to automatically trace all threads created (see + # instrumentation.thread.tracing). May be one of: auto, prepend, chain, + # disabled. # instrumentation.thread: auto # Controls auto-instrumentation of the Thread class at start-up to automatically @@ -568,8 +599,8 @@ common: &default_settings # prepend, chain, disabled. # instrumentation.typhoeus: auto - # Controls auto-instrumentation of ViewComponent at startup. May be one of: auto, - # prepend, chain, disabled. + # Controls auto-instrumentation of ViewComponent at startup. May be one of: + # auto, prepend, chain, disabled. # instrumentation.view_component: auto # A dictionary of label names and values that will be applied to the data sent @@ -628,8 +659,8 @@ common: &default_settings # Specify an Array of Rake tasks to automatically instrument. This configuration # option converts the Array to a RegEx list. If you'd like to allow all tasks by - # default, use rake.tasks: [.+]. No rake tasks will be instrumented unless they're - # added to this list. For more information, visit the New Relic Rake + # default, use rake.tasks: [.+]. No rake tasks will be instrumented unless + # they're added to this list. For more information, visit the New Relic Rake # Instrumentation docs. # rake.tasks: [] @@ -638,6 +669,36 @@ common: &default_settings # ignoring specific transactions. # rules.ignore_url_regexes: [] + # If true, the security agent is loaded (a Ruby 'require' is performed) + # security.agent.enabled: false + + # The port the application is listening on. This setting is mandatory for + # Passenger servers. Other servers should be detected by default. + # security.application_info.port: nil + + # If true, enables deserialization detection + # security.detection.deserialization.enabled: true + + # If true, enables RCI (remote code injection) detection + # security.detection.rci.enabled: true + + # If true, enables RXSS (reflected cross-site scripting) detection + # security.detection.rxss.enabled: true + + # If true, the security agent is started (the agent runs in its event loop) + # security.enabled: false + + # Defines the mode for the security agent to operate in. Currently only IAST is + # supported + # security.mode: IAST + + # Defines the request body limit to process in security events (in KB). The + # default value is 300, for 300KB. + # security.request.body_limit: 300 + + # Defines the endpoint URL for posting security-related data + # security.validator_service_url: wss://csec.nr-data.net + # Applies Language Agent Security Policy settings. # security_policies_token: "" @@ -646,29 +707,32 @@ common: &default_settings # send_data_on_exit: true # If true, the agent will operate in a streamlined mode suitable for use with - # short-lived serverless functions. NOTE: Only AWS Lambda functions are supported - # currently and this option is not intended for use without New Relic's Ruby - # Lambda layer offering. + # short-lived serverless + # functions. NOTE: Only AWS Lambda functions are supported currently and this + # option is not intended for use + # without + # New Relic's Ruby Lambda layer based instrumentation + # offering. # serverless_mode.enabled: false # An array of strings that will collectively serve as a denylist for filtering # which Sidekiq job arguments get reported to New Relic. To capture any Sidekiq # arguments, 'job.sidekiq.args.*' must be added to the separate # :'attributes.include' configuration option. Each string in this array will be - # turned into a regular expression via Regexp.new to permit advanced matching. For - # job argument hashes, if either a key or value matches the pair will be excluded. - # All matching job argument array elements and job argument scalars will be - # excluded. + # turned into a regular expression via Regexp.new to permit advanced matching. + # For job argument hashes, if either a key or value matches the pair will be + # excluded. All matching job argument array elements and job argument scalars + # will be excluded. # sidekiq.args.exclude: [] # An array of strings that will collectively serve as an allowlist for filtering # which Sidekiq job arguments get reported to New Relic. To capture any Sidekiq # arguments, 'job.sidekiq.args.*' must be added to the separate # :'attributes.include' configuration option. Each string in this array will be - # turned into a regular expression via Regexp.new to permit advanced matching. For - # job argument hashes, if either a key or value matches the pair will be included. - # All matching job argument array elements and job argument scalars will be - # included. + # turned into a regular expression via Regexp.new to permit advanced matching. + # For job argument hashes, if either a key or value matches the pair will be + # included. All matching job argument array elements and job argument scalars + # will be included. # sidekiq.args.include: [] # If true, the agent collects slow SQL queries. @@ -679,16 +743,16 @@ common: &default_settings # the default setting for explain plans in slow SQL as well. # slow_sql.explain_enabled: true - # Specify a threshold in seconds. The agent collects slow SQL queries and explain - # plans that exceed this threshold. + # Specify a threshold in seconds. The agent collects slow SQL queries and + # explain plans that exceed this threshold. # slow_sql.explain_threshold: 0.5 - # Defines an obfuscation level for slow SQL queries. Valid options are obfuscated, - # raw, or none. + # Defines an obfuscation level for slow SQL queries. Valid options are + # obfuscated, raw, or none. # slow_sql.record_sql: obfuscated - # Generate a longer sql_id for slow SQL traces. sql_id is used for aggregation of - # similar queries. + # Generate a longer sql_id for slow SQL traces. sql_id is used for aggregation + # of similar queries. # slow_sql.use_longer_sql_id: false # If true, the agent captures attributes on span events. @@ -703,10 +767,12 @@ common: &default_settings # If true, enables span event sampling. # span_events.enabled: true - # * Defines the maximum number of span events reported from a single harvest. Any - # Integer between 1 and 10000 is valid.' - # * When configuring the agent for AI monitoring, set to max value 10000.This - # ensures the agent captures the maximum amount of distributed traces. + # * Defines the maximum number of span events reported from a single harvest. + # Any Integer between 1 and + # 10000 is valid. + # * When configuring the agent for AI monitoring, set to max + # value 10000. This ensures the agent captures the maximum amount of distributed + # traces. # span_events.max_samples_stored: 2000 # Sets the maximum number of span events to buffer when streaming to the trace @@ -714,30 +780,31 @@ common: &default_settings # span_events.queue_size: 10000 # Specify a list of exceptions you do not want the agent to strip when - # strip_exception_messages is true. Separate exceptions with a comma. For example, - # "ImportantException,PreserveMessageException". + # strip_exception_messages is true. Separate exceptions with a comma. For + # example, "ImportantException,PreserveMessageException". # strip_exception_messages.allowed_classes: "" # If true, the agent strips messages from all exceptions except those in the # allowlist. Enabled automatically in high security mode. # strip_exception_messages.enabled: false - # An array of strings to specify which keys and/or values inside a Stripe event's - # user_data hash should + # An array of strings to specify which keys and/or values inside a Stripe + # event's user_data hash should # not be reported to New Relic. Each string in this array will be turned into a # regular expression via - # Regexp.new to permit advanced matching. For each hash pair, if either the key or - # value is matched the - # pair will not be reported. By default, no user_data is reported, so this option - # should only be used if + # Regexp.new to permit advanced matching. For each hash pair, if either the key + # or value is matched the + # pair will not be reported. By default, no user_data is reported, so this + # option should only be used if # the stripe.user_data.include option is being used. # stripe.user_data.exclude: [] - # An array of strings to specify which keys inside a Stripe event's user_data hash - # should be reported - # to New Relic. Each string in this array will be turned into a regular expression - # via Regexp.new to - # permit advanced matching. Setting the value to ["."] will report all user_data. + # An array of strings to specify which keys inside a Stripe event's user_data + # hash should be reported + # to New Relic. Each string in this array will be turned into a regular + # expression via Regexp.new to + # permit advanced matching. Setting the value to ["."] will report all + # user_data. # stripe.user_data.include: [] # When set to true, forces a synchronous connection to the New Relic collector @@ -758,8 +825,8 @@ common: &default_settings # If true, the agent captures attributes from transaction events. # transaction_events.attributes.enabled: true - # Prefix of attributes to exclude from transaction events. Allows * as wildcard at - # end. + # Prefix of attributes to exclude from transaction events. Allows * as wildcard + # at end. # transaction_events.attributes.exclude: [] # Prefix of attributes to include in transaction events. Allows * as wildcard at @@ -769,25 +836,26 @@ common: &default_settings # If true, enables transaction event sampling. # transaction_events.enabled: true - # Defines the maximum number of transaction events reported from a single harvest. + # Defines the maximum number of transaction events reported from a single + # harvest. # transaction_events.max_samples_stored: 1200 # If true, the agent captures attributes on transaction segments. # transaction_segments.attributes.enabled: true - # Prefix of attributes to exclude from transaction segments. Allows * as wildcard - # at end. + # Prefix of attributes to exclude from transaction segments. Allows * as + # wildcard at end. # transaction_segments.attributes.exclude: [] - # Prefix of attributes to include on transaction segments. Allows * as wildcard at - # end. + # Prefix of attributes to include on transaction segments. Allows * as wildcard + # at end. # transaction_segments.attributes.include: [] # If true, the agent captures attributes from transaction traces. # transaction_tracer.attributes.enabled: true - # Prefix of attributes to exclude from transaction traces. Allows * as wildcard at - # end. + # Prefix of attributes to exclude from transaction traces. Allows * as wildcard + # at end. # transaction_tracer.attributes.exclude: [] # Prefix of attributes to include in transaction traces. Allows * as wildcard at @@ -853,55 +921,6 @@ common: &default_settings # Foundry environment. # utilization.detect_pcf: true - # - # BEGIN security agent - # - # NOTE: At this time, the security agent is intended for use only within - # a dedicated security testing environment with data that can tolerate - # modification or deletion. The security agent is available as a - # separate Ruby gem, newrelic_security. It is recommended that this - # separate gem only be introduced to a security testing environment - # by leveraging Bundler grouping like so: - # - # # Gemfile - # gem 'newrelic_rpm' # New Relic APM observability agent - # gem 'newrelic-infinite_tracing' # New Relic Infinite Tracing - # - # group :security do - # gem 'newrelic_security' # New Relic security agent - # end - # - # NOTE: All "security.*" configuration parameters are related only to the - # security agent, and all other configuration parameters that may - # have "security" in the name some where are related to the APM agent. - # - - # If true, the security agent is loaded (a Ruby 'require' is performed) - # security.agent.enabled: false - - # If true, the security agent is started (the agent runs in its event loop) - # security.enabled: false - - # Defines the mode for the security agent to operate in. Currently only 'IAST' is supported - # security.mode: IAST - - # Defines the endpoint URL for posting security related data - # security.validator_service_url: wss://csec.nr-data.net - - # If `true`, enables RCI(Remote Code Injection) detection - # security.detection.rci.enabled: true - - # If `true`, enables RXSS(Reflected Cross-site Scripting) detection - # security.detection.rxss.enabled: true - - # If `true`, enables deserialization detection - # security.detection.deserialization.enabled: true - - # The port the application is listening on. This setting is mandatory for Passenger servers. Other servers should be detected by default. - # security.application_info.port: nil - - # END security agent - # Environment-specific settings are in this section. # RAILS_ENV or RACK_ENV (as appropriate) is used to determine the environment. # If your application has other named environments, configure them here. From 50611c6bdc66aa2de84c23c98fb292550dd8afc2 Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Mon, 22 Jul 2024 15:33:13 -0700 Subject: [PATCH 103/109] Add newrelic_security gem to changelog --- CHANGELOG.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee5489d1ce..6a823a18d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,63 @@ # New Relic Ruby Agent Release Notes ## -Version introduces instrumentation for the LogStasher gem, improves instrumentation for the `redis-clustering` gem, and updates the Elasticsearch instrumentation to only attempt to get the cluster name once per client, even if it fails. +Version adds support for the `newrelic_security` agent, introduces instrumentation for the LogStasher gem, improves instrumentation for the `redis-clustering` gem, and updates the Elasticsearch instrumentation to only attempt to get the cluster name once per client, even if it fails. + +- **Feature: Add support for the newrelic_security agent** + + [New Relic Interactive Application Security Testing (IAST)](https://docs.newrelic.com/docs/iast/introduction/) can help you prevent cyberattacks and breaches on your applications by probing your running code for exploitable vulnerabilities. + + The `newrelic_security` gem provides this feature for Ruby. It depends on `newrelic_rpm`. This is the first version of `newrelic_rpm` compatible with `newrelic_security`. + + At this time, the security agent is intended for use only within a dedicated security testing environment with data that can tolerate modification or deletion. The security agent is available as a separate Ruby gem, newrelic_security. It is recommended that this separate gem only be introduced to a security testing environment by leveraging Bundler grouping like so: + + ```ruby + # Gemfile + gem 'newrelic_rpm' # New Relic APM observability agent + gem 'newrelic-infinite_tracing' # New Relic Infinite Tracing + + group :security do + gem 'newrelic_security' # New Relic security agent + end + ``` + + In order to run the security agent, you need to update your configuration. At a minimum, `security.agent.enabled` and `security.enabled` must be set to `true`. They are `false` by default. Similar to the gem installation, we recommend you set these configurations for a special security testing environment only. + + Here's an example using `newrelic.yml`: + + ```yaml + common: &default_settings + license_key: <%= ENV['NEW_RELIC_LICENSE_KEY'] %> + app_name: "Example app" + + development: + <<: *default_settings + app_name: <%= app_name %> (Development) + + security: + <<: *default_settings + security.enabled: true + security.agent.enabled: true + + production: + <<: *default_settings + ``` + + The following configuration relate to the `newrelic_security` gem: + + | Configuration name | Default | Behavior | + | ------------------ | ------- |----------| + | security.agent.enabled | `false` | If `true`, the security agent is loaded (a Ruby 'require' is performed) | + | security.enabled | `false` | If `true`, the security agent is started (the agent runs in its event loop) | + | security.mode | `'IAST'` | Defines the mode for the security agent to operate in. Currently only 'IAST' is supported | + | security.validator_service_url | `'wss://csec.nr-data.net'` | Defines the endpoint URL for posting security related data | + | security.detection.rci.enabled | `true` | If `true`, enables RCI (remote code injection) detection | + | security.detection.rxss.enabled | `true` | If `true`, enables RXSS (reflected cross-site scripting) detection | + | security.detection.deserialization.enabled | `true` | If `true`, enables deserialization detection | + | security.application_info.port | `nil` | An Integer representing the port the application is listening on. This setting is mandatory for Passenger servers. Other servers should be detected by default. | - **Feature: Add instrumentation for LogStasher** - + The agent will now record logs generated by [LogStasher](https://github.com/shadabahmed/logstasher). Versions 1.0.0 and above of the LogStasher gem are supported. [PR#2559](https://github.com/newrelic/newrelic-ruby-agent/pull/2559) - **Feature: Add instrumentation for redis-clustering** From 98bf902929514e11d33eb0343b6c2a97fae4ddec Mon Sep 17 00:00:00 2001 From: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> Date: Mon, 22 Jul 2024 15:48:52 -0700 Subject: [PATCH 104/109] Update CHANGELOG.md Co-authored-by: James Bunch --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a823a18d0..7853d39783 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ Version adds support for the `newrelic_security` agent, introduces instrum The `newrelic_security` gem provides this feature for Ruby. It depends on `newrelic_rpm`. This is the first version of `newrelic_rpm` compatible with `newrelic_security`. - At this time, the security agent is intended for use only within a dedicated security testing environment with data that can tolerate modification or deletion. The security agent is available as a separate Ruby gem, newrelic_security. It is recommended that this separate gem only be introduced to a security testing environment by leveraging Bundler grouping like so: + At this time, the security agent is intended for use only within a dedicated security testing environment with data that can tolerate modification or deletion. The security agent is available as a separate Ruby gem, `newrelic_security`. It is recommended that this separate gem only be introduced to a security testing environment by leveraging Bundler grouping like so: ```ruby # Gemfile From 65217ec8852c8c39b5955e0852b887f956f44adb Mon Sep 17 00:00:00 2001 From: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> Date: Mon, 22 Jul 2024 22:30:29 -0700 Subject: [PATCH 105/109] Apply suggestions from code review Co-authored-by: Prateek Sen <33506953+prateeksen@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03e39b0f6c..64fd57650c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ Version 9.12.0 adds support for the `newrelic_security` agent, introduces instru gem 'newrelic-infinite_tracing' # New Relic Infinite Tracing group :security do - gem 'newrelic_security' # New Relic security agent + gem 'newrelic_security', require: false # New Relic security agent end ``` From be2b5be3f454f2447b221e39da84dbee5393ecf0 Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Tue, 23 Jul 2024 12:08:25 -0700 Subject: [PATCH 106/109] Revert spacing changes Previously, config descriptions were edited to adhere to a 120 character line length. This caused problems for some descriptions when the newrelic.yml file was generated. The newrelic.yml task handles its own line lengths. We should revisit this another time. --- .../agent/configuration/default_source.rb | 85 ++++++------------- 1 file changed, 27 insertions(+), 58 deletions(-) diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index b104da010c..75a119d875 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -388,14 +388,13 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Boolean, :allowed_from_server => false, :description => <<~DESCRIPTION - If `false`, LLM instrumentation (OpenAI only for now) will not capture input and output content on specific - LLM events. + If `false`, LLM instrumentation (OpenAI only for now) will not capture input and output content on specific LLM events. The excluded attributes include: * `content` from LlmChatCompletionMessage events * `input` from LlmEmbedding events - This is an optional security setting to prevent recording sensitive data sent to and received from your LLMs. + This is an optional security setting to prevent recording sensitive data sent to and received from your LLMs. DESCRIPTION }, # this is only set via server side config @@ -441,16 +440,10 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Boolean, :allowed_from_server => false, :description => <<~DESCRIPTION - When `true`, the agent captures HTTP request parameters and attaches them to transaction traces, traced - errors, and [`TransactionError` events](/attribute-dictionary?attribute_name=&events_tids%5B%5D=8241). + When `true`, the agent captures HTTP request parameters and attaches them to transaction traces, traced errors, and [`TransactionError` events](/attribute-dictionary?attribute_name=&events_tids%5B%5D=8241). - When using the `capture_params` setting, the Ruby agent will not attempt to filter secret information. - `Recommendation:` To filter secret information from request parameters, use the - [`attributes.include` setting](/docs/agents/ruby-agent/attributes/enable-disable-attributes-ruby) - instead. For more information, see the - Ruby attribute - examples. + When using the `capture_params` setting, the Ruby agent will not attempt to filter secret information. `Recommendation:` To filter secret information from request parameters, use the [`attributes.include` setting](/docs/agents/ruby-agent/attributes/enable-disable-attributes-ruby) instead. For more information, see the Ruby attribute examples. DESCRIPTION }, @@ -487,14 +480,12 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Boolean, :allowed_from_server => false, :description => <<~DESC - The exit handler that sends all cached data to the collector before shutting down is forcibly installed. - This is true even when it detects scenarios where it generally should not be. The known use case for this - option is when Sinatra runs as an embedded service within another framework. The agent detects the Sinatra - app and skips 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. + The exit handler that sends all cached data to the collector before shutting down is forcibly installed. \ + This is true even when it detects scenarios where it generally should not be. The known use case for this \ + option is when Sinatra runs as an embedded service within another framework. The agent detects the Sinatra \ + app and skips 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. DESC }, :high_security => { @@ -732,9 +723,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :allowed_from_server => true, :dynamic_name => true, :description => <<~DESCRIPTION - A map of error classes to a list of messages. When an error of one of the classes specified here occurs, if - its error message contains one of the strings corresponding to it here, that error will be treated as - expected. + A map of error classes to a list of messages. When an error of one of the classes specified here occurs, if its error message contains one of the strings corresponding to it here, that error will be treated as expected. This option can't be set via environment variable. @@ -757,8 +746,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :allowed_from_server => true, :dynamic_name => true, :description => <<~DESCRIPTION - A map of error classes to a list of messages. When an error of one of the classes specified here occurs, if - its error message contains one of the strings corresponding to it here, that error will be ignored. + A map of error classes to a list of messages. When an error of one of the classes specified here occurs, if its error message contains one of the strings corresponding to it here, that error will be ignored. This option can't be set via environment variable. @@ -844,14 +832,11 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :description => <<~DESCRIPTION Sets the minimum level a log event must have to be forwarded to New Relic. - This is based on the integer values of Ruby's `Logger::Severity` constants: - https://github.com/ruby/ruby/blob/master/lib/logger/severity.rb + This is based on the integer values of Ruby's `Logger::Severity` constants: https://github.com/ruby/ruby/blob/master/lib/logger/severity.rb - The intention is to forward logs with the level given to the configuration, as well as any logs with a - higher level of severity. + The intention is to forward logs with the level given to the configuration, as well as any logs with a higher level of severity. - For example, setting this value to "debug" will forward all log events to New Relic. Setting this value to - "error" will only forward log events with the levels "error", "fatal", and "unknown". + For example, setting this value to "debug" will forward all log events to New Relic. Setting this value to "error" will only forward log events with the levels "error", "fatal", and "unknown". Valid values (ordered lowest to highest): * "debug" @@ -1305,12 +1290,10 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Boolean, :allowed_from_server => false, :description => <<~DESCRIPTION - If `true`, the agent won't wrap third-party middlewares in instrumentation (regardless of whether they are - installed via `Rack::Builder` or Rails). + If `true`, the agent won't wrap third-party middlewares in instrumentation (regardless of whether they are installed via `Rack::Builder` or Rails). - When middleware instrumentation is disabled, if an application is using middleware that could alter the - response code, the HTTP status code reported on the transaction may not reflect the altered value. + When middleware instrumentation is disabled, if an application is using middleware that could alter the response code, the HTTP status code reported on the transaction may not reflect the altered value. DESCRIPTION }, @@ -1348,20 +1331,12 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Boolean, :allowed_from_server => false, :description => <<~DESCRIPTION - If `true`, disables agent middleware for Sinatra. This middleware is responsible for advanced feature - support such as - [cross application tracing](/docs/apm/transactions/cross-application-traces/cross-application-tracing), - [page load timing](/docs/browser/new-relic-browser/getting-started/new-relic-browser), and - [error collection](/docs/apm/applications-menu/events/view-apm-error-analytics). + If `true`, disables agent middleware for Sinatra. This middleware is responsible for advanced feature support such as [cross application tracing](/docs/apm/transactions/cross-application-traces/cross-application-tracing), [page load timing](/docs/browser/new-relic-browser/getting-started/new-relic-browser), and [error collection](/docs/apm/applications-menu/events/view-apm-error-analytics). - Cross application tracing is deprecated in favor of - [distributed tracing](/docs/apm/distributed-tracing/getting-started/introduction-distributed-tracing). - Distributed tracing is on by default for Ruby agent versions 8.0.0 and above. Middlewares are not - required to support distributed tracing. + Cross application tracing is deprecated in favor of [distributed tracing](/docs/apm/distributed-tracing/getting-started/introduction-distributed-tracing). Distributed tracing is on by default for Ruby agent versions 8.0.0 and above. Middlewares are not required to support distributed tracing. - To continue using cross application tracing, update the following options in your `newrelic.yml` - configuration file: + To continue using cross application tracing, update the following options in your `newrelic.yml` configuration file: ```yaml # newrelic.yml @@ -1643,7 +1618,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => String, :dynamic_name => true, :allowed_from_server => false, - :description => 'Controls auto-instrumentation of the LogStasher library at start-up. May be one of [auto|prepend|chain|disabled].' + :description => 'Controls auto-instrumentation of the LogStasher library at start-up. May be one of: `auto`, `prepend`, `chain`, `disabled`.' }, :'instrumentation.memcache' => { :default => 'auto', @@ -1786,7 +1761,6 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) }, :'instrumentation.stripe' => { :default => 'enabled', - :documentation_default => 'auto', :public => true, :type => String, :allowed_from_server => false, @@ -1952,13 +1926,9 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Boolean, :allowed_from_server => false, :transform => proc { |bool| NewRelic::Agent::ServerlessHandler.env_var_set? || bool }, - :description => <<~DESC - If `true`, the agent will operate in a streamlined mode suitable for use with short-lived serverless - functions. NOTE: Only AWS Lambda functions are supported currently and this option is not intended for use - without - [New Relic's Ruby Lambda layer based instrumentation](https://docs.newrelic.com/docs/serverless-function-monitoring/aws-lambda-monitoring/instrument-lambda-function/instrument-your-own/) - offering. - DESC + :description => 'If `true`, the agent will operate in a streamlined mode suitable for use with short-lived ' \ + 'serverless functions. NOTE: Only AWS Lambda functions are supported currently and this ' \ + "option is not intended for use without [New Relic's Ruby Lambda layer](https://docs.newrelic.com/docs/serverless-function-monitoring/aws-lambda-monitoring/get-started/monitoring-aws-lambda-serverless-monitoring/) offering." }, # Sidekiq :'sidekiq.args.include' => { @@ -2053,10 +2023,9 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :type => Integer, :allowed_from_server => true, :description => <<~DESC - * Defines the maximum number of span events reported from a single harvest. Any Integer between `1` and - `10000` is valid. - * When configuring the agent for [AI monitoring](/docs/ai-monitoring/intro-to-ai-monitoring), set to max - value `10000`. This ensures the agent captures the maximum amount of distributed traces. + * Defines the maximum number of span events reported from a single harvest. Any Integer between `1` and `10000` is valid.' + * When configuring the agent for [AI monitoring](/docs/ai-monitoring/intro-to-ai-monitoring), set to max value `10000`.\ + This ensures the agent captures the maximum amount of distributed traces. DESC }, # Strip exception messages From 18b33c0e360958dd1a72910ae4eeabeb65175bf1 Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Tue, 23 Jul 2024 12:10:38 -0700 Subject: [PATCH 107/109] Regenerate newrelic.yml --- newrelic.yml | 99 +++++++++++++++++++--------------------------------- 1 file changed, 35 insertions(+), 64 deletions(-) diff --git a/newrelic.yml b/newrelic.yml index 71d5f215fc..c33c57a0e1 100644 --- a/newrelic.yml +++ b/newrelic.yml @@ -39,8 +39,7 @@ common: &default_settings # ai_monitoring.enabled: false # If false, LLM instrumentation (OpenAI only for now) will not capture input and - # output content on specific - # LLM events. + # output content on specific LLM events. # The excluded attributes include: # * content from LlmChatCompletionMessage events # * input from LlmEmbedding events @@ -70,12 +69,10 @@ common: &default_settings # This is based on the integer values of Ruby's Logger::Severity constants: # https://github.com/ruby/ruby/blob/master/lib/logger/severity.rb # The intention is to forward logs with the level given to the configuration, as - # well as any logs with a - # higher level of severity. + # well as any logs with a higher level of severity. # For example, setting this value to "debug" will forward all log events to New - # Relic. Setting this value to - # "error" will only forward log events with the levels "error", "fatal", and - # "unknown". + # Relic. Setting this value to "error" will only forward log events with the + # levels "error", "fatal", and "unknown". # Valid values (ordered lowest to highest): # * "debug" # * "info" @@ -162,17 +159,11 @@ common: &default_settings # capture_memcache_keys: false # When true, the agent captures HTTP request parameters and attaches them to - # transaction traces, traced - # errors, and TransactionError events. + # transaction traces, traced errors, and TransactionError events. # When using the capture_params setting, the Ruby agent will not attempt to - # filter secret information. - # Recommendation: To filter secret information from request parameters, use the - # attributes.include setting - # instead. For more information, see the - # Ruby - # attribute - # examples. + # filter secret information. Recommendation: To filter secret information from + # request parameters, use the attributes.include setting instead. For more + # information, see the Ruby attribute examples. # capture_params: false # If true, the agent will clear Tracer::State in Agent.drop_buffered_data. @@ -251,12 +242,10 @@ common: &default_settings # disable_memory_sampler: false # If true, the agent won't wrap third-party middlewares in instrumentation - # (regardless of whether they are - # installed via Rack::Builder or Rails). + # (regardless of whether they are installed via Rack::Builder or Rails). # When middleware instrumentation is disabled, if an application is using - # middleware that could alter the - # response code, the HTTP status code reported on the transaction may not - # reflect the altered value. + # middleware that could alter the response code, the HTTP status code reported + # on the transaction may not reflect the altered value. # disable_middleware_instrumentation: false # If true, disables agent middleware for Roda. This middleware is responsible @@ -274,19 +263,13 @@ common: &default_settings # disable_sidekiq: false # If true, disables agent middleware for Sinatra. This middleware is responsible - # for advanced feature - # support such as - # cross application tracing, - # page load timing, and - # error collection. - # Cross application tracing is deprecated in favor of - # distributed tracing. + # for advanced feature support such as cross application tracing, page load + # timing, and error collection. + # Cross application tracing is deprecated in favor of distributed tracing. # Distributed tracing is on by default for Ruby agent versions 8.0.0 and above. - # Middlewares are not - # required to support distributed tracing. + # Middlewares are not required to support distributed tracing. # To continue using cross application tracing, update the following options in - # your newrelic.yml - # configuration file: + # your newrelic.yml configuration file: # ``yaml # # newrelic.yml # cross_application_tracer: @@ -336,10 +319,8 @@ common: &default_settings # error_collector.expected_classes: [] # A map of error classes to a list of messages. When an error of one of the - # classes specified here occurs, if - # its error message contains one of the strings corresponding to it here, that - # error will be treated as - # expected. + # classes specified here occurs, if its error message contains one of the + # strings corresponding to it here, that error will be treated as expected. # This option can't be set via environment variable. # error_collector.expected_messages: {} @@ -353,9 +334,8 @@ common: &default_settings # error_collector.ignore_classes: ["ActionController::RoutingError", "Sinatra::NotFound"] # A map of error classes to a list of messages. When an error of one of the - # classes specified here occurs, if - # its error message contains one of the strings corresponding to it here, that - # error will be ignored. + # classes specified here occurs, if its error message contains one of the + # strings corresponding to it here, that error will be ignored. # This option can't be set via environment variable. # error_collector.ignore_messages: {} @@ -377,17 +357,13 @@ common: &default_settings # exclude_newrelic_header: false # The exit handler that sends all cached data to the collector before shutting - # down is forcibly installed. - # This is true even when it detects scenarios where it generally should not be. - # The known use case for this - # option is when Sinatra runs as an embedded service within another framework. - # The agent detects the Sinatra - # app and skips 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 + # down is forcibly installed. This is true even when it detects scenarios where + # it generally should not be. The known use case for this option is when Sinatra + # runs as an embedded service within another framework. The agent detects the + # Sinatra app and skips 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. # force_install_exit_handler: false @@ -510,7 +486,7 @@ common: &default_settings # instrumentation.logger: auto # Controls auto-instrumentation of the LogStasher library at start-up. May be - # one of [auto|prepend|chain|disabled]. + # one of: auto, prepend, chain, disabled. # instrumentation.logstasher: auto # Controls auto-instrumentation of dalli gem for Memcache at start-up. May be @@ -578,7 +554,7 @@ common: &default_settings # Controls auto-instrumentation of Stripe at startup. May be one of: enabled, # disabled. - # instrumentation.stripe: auto + # instrumentation.stripe: enabled # Controls auto-instrumentation of the Thread class at start-up to allow the # agent to correctly nest spans inside of an asynchronous transaction. This does @@ -707,12 +683,9 @@ common: &default_settings # send_data_on_exit: true # If true, the agent will operate in a streamlined mode suitable for use with - # short-lived serverless - # functions. NOTE: Only AWS Lambda functions are supported currently and this - # option is not intended for use - # without - # New Relic's Ruby Lambda layer based instrumentation - # offering. + # short-lived serverless functions. NOTE: Only AWS Lambda functions are + # supported currently and this option is not intended for use without New + # Relic's Ruby Lambda layer offering. # serverless_mode.enabled: false # An array of strings that will collectively serve as a denylist for filtering @@ -768,11 +741,9 @@ common: &default_settings # span_events.enabled: true # * Defines the maximum number of span events reported from a single harvest. - # Any Integer between 1 and - # 10000 is valid. - # * When configuring the agent for AI monitoring, set to max - # value 10000. This ensures the agent captures the maximum amount of distributed - # traces. + # Any Integer between 1 and 10000 is valid.' + # * When configuring the agent for AI monitoring, set to max value 10000.This + # ensures the agent captures the maximum amount of distributed traces. # span_events.max_samples_stored: 2000 # Sets the maximum number of span events to buffer when streaming to the trace From 4d99f75b8970aa4cfa5472a3f3d2bbfdd692407c Mon Sep 17 00:00:00 2001 From: Kayla Reopelle Date: Wed, 24 Jul 2024 09:13:13 -0700 Subject: [PATCH 108/109] Add security agent content back to newrelic.yml --- newrelic.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/newrelic.yml b/newrelic.yml index c33c57a0e1..ccddfde376 100644 --- a/newrelic.yml +++ b/newrelic.yml @@ -645,6 +645,28 @@ common: &default_settings # ignoring specific transactions. # rules.ignore_url_regexes: [] + # BEGIN security agent + # + # NOTE: At this time, the security agent is intended for use only within + # a dedicated security testing environment with data that can tolerate + # modification or deletion. The security agent is available as a + # separate Ruby gem, newrelic_security. It is recommended that this + # separate gem only be introduced to a security testing environment + # by leveraging Bundler grouping like so: + # + # # Gemfile + # gem 'newrelic_rpm' # New Relic APM observability agent + # gem 'newrelic-infinite_tracing' # New Relic Infinite Tracing + # + # group :security do + # gem 'newrelic_security', require: false # New Relic security agent + # end + # + # NOTE: All "security.*" configuration parameters are related only to the + # security agent, and all other configuration parameters that may + # have "security" in the name some where are related to the APM agent. + # + # If true, the security agent is loaded (a Ruby 'require' is performed) # security.agent.enabled: false @@ -675,6 +697,8 @@ common: &default_settings # Defines the endpoint URL for posting security-related data # security.validator_service_url: wss://csec.nr-data.net + # END security agent + # Applies Language Agent Security Policy settings. # security_policies_token: "" From a957d6896113e097613a066b14a83e76eaadd3dd Mon Sep 17 00:00:00 2001 From: Hannah Ramadan <76922290+hannahramadan@users.noreply.github.com> Date: Wed, 24 Jul 2024 09:20:50 -0700 Subject: [PATCH 109/109] Add Security Agent to config.rake (#2766) * Add Security Agent to config.rake --- lib/tasks/config.rake | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/tasks/config.rake b/lib/tasks/config.rake index 9ba66bbcb2..4ef9da672b 100644 --- a/lib/tasks/config.rake +++ b/lib/tasks/config.rake @@ -23,13 +23,16 @@ namespace :newrelic do 'browser_monitoring' => "The [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.", '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:", '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.', - 'ai_monitoring' => "This section includes Ruby agent configurations for setting up AI monitoring.\n\nYou 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." + 'ai_monitoring' => "This section includes Ruby agent configurations for setting up AI monitoring.\n\nYou 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.", + 'security_agent' => "[New Relic Interactive Application Security Testing](https://docs.newrelic.com/docs/iast/introduction/) (IAST) tests your applications for any exploitable vulnerability by replaying the generated HTTP request with vulnerable payloads.\n\nRun IAST with non-production deployments only to avoid exposing vulnerabilities on your production software. \ + IAST mode requires Ruby agent version 9.12.0 or higher and the [newrelic_security](https://rubygems.org/gems/newrelic_security) gem. Security agent configurations are disabled by default." } NAME_OVERRIDES = { 'slow_sql' => 'Slow SQL [#slow-sql]', 'custom_insights_events' => 'Custom Events [#custom-events]', - 'ai_monitoring' => 'AI Monitoring [#ai-monitoring]' + 'ai_monitoring' => 'AI Monitoring [#ai-monitoring]', + 'security_agent' => 'Security Agent [#security-agent]' } desc 'Describe available New Relic configuration settings'