diff --git a/.github/versions.yml b/.github/versions.yml index 467f91ad92..fa8f0ce7cb 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.191.0 - :sha: 52753b7da854d5c07df37391a986c76ab4615999 + :tag: v1.196.0 + :sha: f26937343756480a8cb3ae1f623b9c8d89ed6984 actions/checkout: :tag: v4.1.7 :sha: 692973e3d937129bcbf40652eb9f2f61becf3332 @@ -36,3 +36,9 @@ adriangl/check-new-commits-action: softprops/action-gh-release: :tag: v2.0.8 :sha: c062e08bd532815e2082a85e87e3ef29c3e6d191 +aquasecurity/trivy-action: + :tag: v0.28.0 + :sha: 915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 +github/codeql-action/upload-sarif: + :tag: v3.27.0 + :sha: 662472033e021d55d94146f66f6058822b0b39fd diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0be439be24..c652217e59 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@692973e3d937129bcbf40652eb9f2f61becf3332 # tag v4.1.7 - - uses: ruby/setup-ruby@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + - uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.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@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -216,7 +216,7 @@ jobs: strategy: fail-fast: false matrix: - multiverse: [agent, ai, background, background_2, database, frameworks, httpclients, httpclients_2, rails, rest] + multiverse: [agent, ai, background, background_2, kafka, database, frameworks, httpclients, httpclients_2, rails, rest] ruby-version: [2.4.10, 3.3.5] steps: @@ -231,7 +231,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@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -324,7 +324,7 @@ jobs: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # tag v4.1.7 - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -364,7 +364,7 @@ jobs: - name: Configure git run: 'git config --global init.defaultBranch main' - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # tag v4.1.7 - - uses: ruby/setup-ruby@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + - uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 with: ruby-version: '3.3' - run: bundle diff --git a/.github/workflows/ci_cron.yml b/.github/workflows/ci_cron.yml index 02dd0a08aa..4a81061d2f 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@692973e3d937129bcbf40652eb9f2f61becf3332 # tag v4.1.7 - - uses: ruby/setup-ruby@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + - uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.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.5, 3.3.5, 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.5, 3.3.5, 3.4.0-preview2] 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@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -84,7 +84,7 @@ jobs: "3.3.5": { "rails": "norails,rails61,rails70,rails71,rails72,railsedge" }, - "3.4.0-preview1": { + "3.4.0-preview2": { "rails": "norails,rails61,rails70,rails71,rails72" } } @@ -229,8 +229,8 @@ jobs: strategy: 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.5, 3.3.5, 3.4.0-preview1] + multiverse: [agent, ai, background, background_2, database, kafka, 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.5, 3.3.5, 3.4.0-preview2] steps: - name: Configure git run: 'git config --global init.defaultBranch main' @@ -243,7 +243,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@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 with: ruby-version: ${{ matrix.ruby-version }} @@ -308,14 +308,14 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: [2.7.8, 3.0.7, 3.1.6, 3.2.5, 3.3.5, 3.4.0-preview1] + ruby-version: [2.7.8, 3.0.7, 3.1.6, 3.2.5, 3.3.5, 3.4.0-preview2] steps: - name: Configure git run: 'git config --global init.defaultBranch main' - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # tag v4.1.7 - name: Install Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 with: ruby-version: ${{ matrix.ruby-version }} diff --git a/.github/workflows/ci_jruby.yml b/.github/workflows/ci_jruby.yml index 4f48127c64..ca72ecb3d2 100644 --- a/.github/workflows/ci_jruby.yml +++ b/.github/workflows/ci_jruby.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # tag v4.1.7 - name: Install JRuby - uses: ruby/setup-ruby@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 with: ruby-version: jruby-9.4.8.0 @@ -49,7 +49,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # tag v4.1.7 - name: Install JRuby - uses: ruby/setup-ruby@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 with: ruby-version: jruby-9.4.8.0 diff --git a/.github/workflows/ci_special.yml b/.github/workflows/ci_special.yml index 46e3e0c9f3..c584f6d7b5 100644 --- a/.github/workflows/ci_special.yml +++ b/.github/workflows/ci_special.yml @@ -20,15 +20,15 @@ jobs: - 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@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + - name: Install Ruby 3.4.0-preview2 + uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 with: - ruby-version: 3.4.0-preview1 + ruby-version: 3.4.0-preview2 - name: Setup bundler run: ./.github/workflows/scripts/setup_bundler env: - RUBY_VERSION: 3.4.0-preview1 + RUBY_VERSION: 3.4.0-preview2 - name: Run Unit Tests uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # tag v3.0.0 diff --git a/.github/workflows/config_docs.yml b/.github/workflows/config_docs.yml index 22aee84aec..b45984345c 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@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 with: ruby-version: 3.3 diff --git a/.github/workflows/performance_tests.yml b/.github/workflows/performance_tests.yml index 1aceb9e60d..19987a61c8 100644 --- a/.github/workflows/performance_tests.yml +++ b/.github/workflows/performance_tests.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # tag v4.1.7 with: ref: 'main' - - uses: ruby/setup-ruby@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + - uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 with: ruby-version: '3.3' - run: bundle diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 8ceb0aced4..1dbb8d5c6e 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@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 with: ruby-version: 3.3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a96f4a10c7..c0505d04ac 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,7 @@ jobs: with: fetch-depth: 0 - - uses: ruby/setup-ruby@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + - uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 with: ruby-version: 3.3 diff --git a/.github/workflows/release_notes.yml b/.github/workflows/release_notes.yml index ed77a6748e..a70fa4b4d3 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@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + - uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 with: ruby-version: 3.3 - name: Checkout code diff --git a/.github/workflows/release_pr.yml b/.github/workflows/release_pr.yml index ec1015ecbf..e2507ae607 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@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 with: ruby-version: 3.3 diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000000..18423fbf79 --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,69 @@ +name: Security scan +on: + push: + branches: + - main + - dev + pull_request: + schedule: + - cron: '0 9 * * *' # Same time as CI Cron + +jobs: + build: + name: Trivy Scan + runs-on: ubuntu-latest + steps: + - name: Install Ruby 3.3 + uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 + with: + ruby-version: 3.3 + + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # tag v4.1.7 + + - run: bundle # Generate a Gemfile.lock to scan + + - name: Run Trivy in table mode + # Table output is only useful when running on a pull request or push. + if: contains(fromJSON('["push", "pull_request"]'), github.event_name) + uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # tag v.0.28.0 + with: + scan-type: fs + format: table + exit-code: 1 + ignore-unfixed: true + severity: CRITICAL,HIGH,MEDIUM,LOW + + - name: Run Trivy in report mode + # Only generate sarif when running nightly on the dev branch. + if: ${{ github.event_name == 'schedule' }} + uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # tag v.0.28.0 + with: + scan-type: fs + format: sarif + output: trivy-results.sarif + ignore-unfixed: true + severity: 'CRITICAL,HIGH,MEDIUM,LOW' + + - name: Upload Trivy scan results to GitHub Security tab + # Only upload sarif when running nightly on the dev branch. + if: ${{ github.event_name == 'schedule' }} + uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # tag v3.27.0 + with: + sarif_file: trivy-results.sarif + + notify_slack_fail: + name: Notify slack fail + needs: [build] + runs-on: ubuntu-22.04 + if: ${{ github.event_name == 'schedule' && failure() }} + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # tag v4.1.7 + - uses: ./.github/actions/workflow-conclusion + - uses: voxmedia/github-action-slack-notify-build@3665186a8c1a022b28a1dbe0954e73aa9081ea9e # tag v1.6.0 + if: ${{ env.WORKFLOW_CONCLUSION == 'failure' }} + env: + SLACK_BOT_TOKEN: ${{ secrets.RUBY_GITHUB_ACTIONS_BOT_WEBHOOK }} + with: + channel: ruby-agent-notifications + status: FAILED + color: danger diff --git a/.github/workflows/slack_notifications.yml b/.github/workflows/slack_notifications.yml index 0dd7074859..5b53187943 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@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + - uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 with: ruby-version: 3.3 - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # tag v4.1.7 @@ -47,7 +47,7 @@ jobs: cve_notifications: runs-on: ubuntu-22.04 steps: - - uses: ruby/setup-ruby@52753b7da854d5c07df37391a986c76ab4615999 # tag v1.191.0 + - uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # tag v1.196.0 with: ruby-version: 3.3 - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # tag v4.1.7 diff --git a/.gitignore b/.gitignore index 695e0997f6..4927f66ad7 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ lib/new_relic/build.rb .tm_properties .bundle .yardoc +.vscode/ artifacts/ test/performance/log/ test/performance/script/log/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cec4b666f..c2a9f7b273 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,36 @@ # New Relic Ruby Agent Release Notes +## v9.15.0 + +Version 9.15.0 updates View Componment instrumentation to use a default metric name when one is unavailable, adds a configuration option to associate the AWS account ID with the DynamoDB calls from the AWS SDK, resolves a bug in rdkafka instrumentation when using the karafka-rdkafka gem, resolves a bug in the ruby-kafka instrumentation, fixes a bug with Grape instrumentation, and addresses a bug preventing the agent from running in serverless mode in an AWS Lambda layer. + +- **Feature: New configuration option cloud.aws.account_id** + + A new configuration option has been added, `cloud.aws.account_id`, that will allow New Relic to provide more details about certain calls made using the AWS SDK. One example, is that relationships between AWS services instrumented with New Relic's CloudWatch Metric Streams will have relationships formed in the service map with APM applications. Currently, the DynamoDB instrumentation is the only instrumentation that will make use of this configuration option, but this will be used in future instrumentation as well. [PR#2904](https://github.com/newrelic/newrelic-ruby-agent/pull/2904) + +- **Feature: Use default `View/component` metric name for unidentified View Components** + + Previously, when a View Component metric name could not be identified, the agent would set the name as `nil`. Now, the agent defaults to using `View/component` as the metric name when one can not be identified. [PR#2907](https://github.com/newrelic/newrelic-ruby-agent/pull/2907) + +- **Bugfix: Instrumentation errors when using the karafka-rdkafka gem** + + Due to version differences between the rdkafka gem and karafka-rdkafka gem, the agent could encounter an error when it tried to install rdkafka instrumentation. This has now been resolved. Thank you to @krisdigital for bringing this issue to our attention. [PR#2880](https://github.com/newrelic/newrelic-ruby-agent/pull/2880) + +- **Bugfix: Stop calling deprecated all_specs method to check for the presence of newrelic-grape** + + In 9.14.0, we released a fix for calls to the deprecated `Bundler.rubygems.all_specs`, but the fix fell short for the agent's Grape instrumentation and deprecation warnings could still be raised. The condition has been simplified and deprecation warnings should no longer be raised. Thank you, [@excelsior](https://github.com/excelsior) for bringing this to our attention. [Issue#2885](https://github.com/newrelic/newrelic-ruby-agent/issues/2885) [PR#2906](https://github.com/newrelic/newrelic-ruby-agent/pull/2906) + +- **Bugfix: Instrumentation errors when using the ruby-kafka gem** + + Kafka::Consumer#each_message takes keyword arguments, while the prepended method is defined with a single splat positional argument. In Ruby >= 3.0, this signature mismatch raises an ArgumentError. Thank you [@patrickarnett](https://github.com/patrickarnett) for providing this bugfix. [PR#2915](https://github.com/newrelic/newrelic-ruby-agent/pull/2915) + +- **Bugfix: Restore AWS Lambda layer operational functionality** + + Version 9.14.0 of the agent introduced an optimization related to how the agent handles boolean configuration parameters which inadvertently caused the agent to stop operating properly in an AWS Lambda layer context. [Issue#2919](https://github.com/newrelic/newrelic-ruby-agent/issues/2919)[PR#2920](https://github.com/newrelic/newrelic-ruby-agent/pull/2920) + ## v9.14.0 -Version 9.14.0 adds Apache Kafka instrumentation for the rdkafka and ruby-kafka gems, introduces a configuration-based, automatic way to add custom instrumentation method tracers, correctly captures MIME type for AcionDispatch 7.0+ requests, properly handles Boolean coercion for `newrelic.yml` configuration, fixes a JRuby bug in the configuration manager, fixes a bug related to `Bundler.rubygems.installed_specs`, and fixes a bug to make the agent compatible with ViewComponent v3.15.0+. +Version 9.14.0 adds Apache Kafka instrumentation for the rdkafka and ruby-kafka gems, introduces a configuration-based, automatic way to add custom instrumentation method tracers, correctly captures MIME type for ActionDispatch 7.0+ requests, properly handles Boolean coercion for `newrelic.yml` configuration, fixes a JRuby bug in the configuration manager, fixes a bug related to `Bundler.rubygems.installed_specs`, and fixes a bug to make the agent compatible with ViewComponent v3.15.0+. - **Feature: Add Apache Kafka instrumentation for the rdkafka and ruby-kafka gems** @@ -42,13 +70,13 @@ Version 9.14.0 adds Apache Kafka instrumentation for the rdkafka and ruby-kafka - MyCompany::User.notify ``` - That configuration example uses YAML array syntax to specify both methods. Alternatively, a comma-delimited string can be used instead: + That configuration example uses YAML array syntax to specify both methods. Alternatively, you can use a comma-delimited string: ``` automatic_custom_instrumentation_method_list: 'MyCompany::Image#render_png, MyCompany::User.notify' ``` - Whitespace around the comma(s) in the list is optional. When configuring the agent with a list of methods via the `NEW_RELIC_AUTOMATIC_CUSTOM_INSTRUMENTATION_METHOD_LIST` environment variable, this comma-delimited string format should be used: + Whitespace around the comma(s) in the list is optional. When configuring the agent with a list of methods via the `NEW_RELIC_AUTOMATIC_CUSTOM_INSTRUMENTATION_METHOD_LIST` environment variable, use this comma-delimited string format: ``` export NEW_RELIC_AUTOMATIC_CUSTOM_INSTRUMENTATION_METHOD_LIST='MyCompany::Image#render_png, MyCompany::User.notify' @@ -56,7 +84,7 @@ Version 9.14.0 adds Apache Kafka instrumentation for the rdkafka and ruby-kafka [PR#2851](https://github.com/newrelic/newrelic-ruby-agent/pull/2851) -- **Feature: Collect just MIME type for AcionDispatch 7.0+ requests** +- **Feature: Collect just MIME type for ActionDispatch 7.0+ requests** Rails 7.0 [introduced changes](https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#actiondispatch-request-content-type-now-returns-content-type-header-as-it-is) to the behavior of `ActionDispatch::Request#content_type`, adding extra request-related details the agent wasn't expecting to collect. Additionally, the agent's use of `content_type ` was triggering deprecation warnings. The agent now uses `ActionDispatch::Request#media_type` to capture the MIME type. Thanks to [@internethostage](https://github.com/internethostage) for letting us know about this change. [Issue#2500](https://github.com/newrelic/newrelic-ruby-agent/issues/2500) [PR#2855](https://github.com/newrelic/newrelic-ruby-agent/pull/2855) diff --git a/docker-compose.yml b/docker-compose.yml index 4fd6bdaf0c..bc4a30774f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -101,7 +101,7 @@ services: depends_on: - elasticsearch7 - elasticsearch8 - - opensearch + # - opensearch - mysql - memcached - mongodb diff --git a/lib/new_relic/agent/aws.rb b/lib/new_relic/agent/aws.rb index 81dcd9e862..cb1d4f53a9 100644 --- a/lib/new_relic/agent/aws.rb +++ b/lib/new_relic/agent/aws.rb @@ -5,58 +5,13 @@ module NewRelic module Agent module Aws - CHARACTERS = %w[A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 2 3 4 5 6 7].freeze - HEX_MASK = '7fffffffff80' + def self.create_arn(service, resource, region) + return unless NewRelic::Agent.config[:'cloud.aws.account_id'] - def self.create_arn(service, resource, region, account_id) - "arn:aws:#{service}:#{region}:#{account_id}:#{resource}" + "arn:aws:#{service}:#{region}:#{NewRelic::Agent.config[:'cloud.aws.account_id']}:#{resource}" rescue => e NewRelic::Agent.logger.warn("Failed to create ARN: #{e}") end - - def self.get_account_id(config) - access_key_id = config.credentials.credentials.access_key_id if config&.credentials&.credentials&.respond_to?(:access_key_id) - return unless access_key_id - - NewRelic::Agent::Aws.convert_access_key_to_account_id(access_key_id) - rescue => e - NewRelic::Agent.logger.debug("Failed to create account id: #{e}") - end - - def self.convert_access_key_to_account_id(access_key) - decoded_key = Integer(decode_to_hex(access_key[4..-1]), 16) - mask = Integer(HEX_MASK, 16) - (decoded_key & mask) >> 7 - end - - def self.decode_to_hex(access_key) - bytes = access_key.delete('=').each_char.map { |c| CHARACTERS.index(c) } - - bytes.each_slice(8).map do |section| - convert_section(section) - end.flatten[0...6].join - end - - def self.convert_section(section) - buffer = 0 - section.each do |chunk| - buffer = (buffer << 5) + chunk - end - - chunk_count = (section.length * 5.0 / 8.0).floor - - if section.length < 8 - buffer >>= (5 - (chunk_count * 8)) % 5 - end - - decoded = [] - chunk_count.times do |i| - shift = 8 * (chunk_count - 1 - i) - decoded << ((buffer >> shift) & 255).to_s(16) - end - - decoded - end end end end diff --git a/lib/new_relic/agent/configuration/default_source.rb b/lib/new_relic/agent/configuration/default_source.rb index 246af67829..d8e7389116 100644 --- a/lib/new_relic/agent/configuration/default_source.rb +++ b/lib/new_relic/agent/configuration/default_source.rb @@ -427,6 +427,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :public => true, :type => String, :allowed_from_server => false, + :exclude_from_reported_settings => true, :description => 'Your New Relic . Required when using the New Relic REST API v2 to record deployments using the `newrelic deployments` command.' }, :backport_fast_active_record_connection_lookup => { @@ -471,6 +472,14 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :allowed_from_server => false, :description => 'If `true`, the agent will clear `Tracer::State` in `Agent.drop_buffered_data`.' }, + :'cloud.aws.account_id' => { + :default => nil, + :public => true, + :type => String, + :allow_nil => true, + :allowed_from_server => false, + :description => 'The AWS account ID for the AWS account associated with this app' + }, :config_path => { :default => DefaultSource.config_path, :public => true, @@ -1159,7 +1168,7 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil) :allowed_from_server => false, :transform => proc { |arr| NewRelic::Agent.add_automatic_method_tracers(arr) }, :description => <<~DESCRIPTION - An array of `CLASS#METHOD` (for instance methods) and/or `CLASS.METHOD` (for class methods) strings representing Ruby methods for the agent to automatically add custom instrumentation to without the need for altering any of the source code that defines the methods. + An array of `CLASS#METHOD` (for instance methods) and/or `CLASS.METHOD` (for class methods) strings representing Ruby methods that the agent can automatically add custom instrumentation to. This doesn't require any modifications of the source code that defines the methods. Use fully qualified class names (using the `::` delimiter) that include any module or class namespacing. @@ -1189,13 +1198,13 @@ def self.notify - MyCompany::User.notify ``` - That configuration example uses YAML array syntax to specify both methods. Alternatively, a comma-delimited string can be used instead: + That configuration example uses YAML array syntax to specify both methods. Alternatively, you can use a comma-delimited string: ``` automatic_custom_instrumentation_method_list: 'MyCompany::Image#render_png, MyCompany::User.notify' ``` - Whitespace around the comma(s) in the list is optional. When configuring the agent with a list of methods via the `NEW_RELIC_AUTOMATIC_CUSTOM_INSTRUMENTATION_METHOD_LIST` environment variable, this comma-delimited string format should be used: + Whitespace around the comma(s) in the list is optional. When configuring the agent with a list of methods via the `NEW_RELIC_AUTOMATIC_CUSTOM_INSTRUMENTATION_METHOD_LIST` environment variable, use this comma-delimited string format: ``` export NEW_RELIC_AUTOMATIC_CUSTOM_INSTRUMENTATION_METHOD_LIST='MyCompany::Image#render_png, MyCompany::User.notify' diff --git a/lib/new_relic/agent/configuration/manager.rb b/lib/new_relic/agent/configuration/manager.rb index f1c5b6bb24..c4f849ff28 100644 --- a/lib/new_relic/agent/configuration/manager.rb +++ b/lib/new_relic/agent/configuration/manager.rb @@ -143,7 +143,7 @@ def evaluate_and_apply_transformations(key, value) return default if default boolean = enforce_boolean(key, value) - return boolean if [true, false].include?(boolean) + evaluated = boolean if [true, false].include?(boolean) apply_transformations(key, evaluated) end diff --git a/lib/new_relic/agent/instrumentation/active_support_broadcast_logger.rb b/lib/new_relic/agent/instrumentation/active_support_broadcast_logger.rb index 8505dd2d72..3e51c1abd6 100644 --- a/lib/new_relic/agent/instrumentation/active_support_broadcast_logger.rb +++ b/lib/new_relic/agent/instrumentation/active_support_broadcast_logger.rb @@ -12,8 +12,6 @@ depends_on { defined?(ActiveSupport::BroadcastLogger) } executes do - NewRelic::Agent.logger.info('Installing ActiveSupport::BroadcastLogger instrumentation') - if use_prepend? prepend_instrument ActiveSupport::BroadcastLogger, NewRelic::Agent::Instrumentation::ActiveSupportBroadcastLogger::Prepend else diff --git a/lib/new_relic/agent/instrumentation/active_support_logger.rb b/lib/new_relic/agent/instrumentation/active_support_logger.rb index a89effca96..73c8f66159 100644 --- a/lib/new_relic/agent/instrumentation/active_support_logger.rb +++ b/lib/new_relic/agent/instrumentation/active_support_logger.rb @@ -14,8 +14,6 @@ end executes do - NewRelic::Agent.logger.info('Installing ActiveSupport::Logger instrumentation') - if use_prepend? # the only method currently instrumented is a class method prepend_instrument ActiveSupport::Logger.singleton_class, NewRelic::Agent::Instrumentation::ActiveSupportLogger::Prepend diff --git a/lib/new_relic/agent/instrumentation/async_http.rb b/lib/new_relic/agent/instrumentation/async_http.rb index 0087877e95..82aa620915 100644 --- a/lib/new_relic/agent/instrumentation/async_http.rb +++ b/lib/new_relic/agent/instrumentation/async_http.rb @@ -16,9 +16,8 @@ end executes do - NewRelic::Agent.logger.info('Installing async_http instrumentation') - require 'async/http/internet' + if use_prepend? prepend_instrument Async::HTTP::Internet, NewRelic::Agent::Instrumentation::AsyncHttp::Prepend else diff --git a/lib/new_relic/agent/instrumentation/aws_sqs.rb b/lib/new_relic/agent/instrumentation/aws_sqs.rb index 7f5acb82c3..35d55428e2 100644 --- a/lib/new_relic/agent/instrumentation/aws_sqs.rb +++ b/lib/new_relic/agent/instrumentation/aws_sqs.rb @@ -14,8 +14,6 @@ end executes do - NewRelic::Agent.logger.info('Installing aws-sdk-sqs instrumentation') - if use_prepend? prepend_instrument Aws::SQS::Client, NewRelic::Agent::Instrumentation::AwsSqs::Prepend else diff --git a/lib/new_relic/agent/instrumentation/bunny.rb b/lib/new_relic/agent/instrumentation/bunny.rb index b7cf291eb0..c9486acf0b 100644 --- a/lib/new_relic/agent/instrumentation/bunny.rb +++ b/lib/new_relic/agent/instrumentation/bunny.rb @@ -14,7 +14,6 @@ end executes do - NewRelic::Agent.logger.info('Installing Bunny instrumentation') require 'new_relic/agent/distributed_tracing/cross_app_tracing' require 'new_relic/agent/messaging' require 'new_relic/agent/transaction/message_broker_segment' @@ -22,9 +21,9 @@ executes do if use_prepend? - prepend_instrument Bunny::Exchange, NewRelic::Agent::Instrumentation::Bunny::Prepend::Exchange - prepend_instrument Bunny::Queue, NewRelic::Agent::Instrumentation::Bunny::Prepend::Queue - prepend_instrument Bunny::Consumer, NewRelic::Agent::Instrumentation::Bunny::Prepend::Consumer + prepend_instrument Bunny::Exchange, NewRelic::Agent::Instrumentation::Bunny::Prepend::Exchange, 'Bunny::Exchange' + prepend_instrument Bunny::Queue, NewRelic::Agent::Instrumentation::Bunny::Prepend::Queue, 'Bunny::Queue' + prepend_instrument Bunny::Consumer, NewRelic::Agent::Instrumentation::Bunny::Prepend::Consumer, 'Bunny::Consumer' else chain_instrument NewRelic::Agent::Instrumentation::Bunny::Chain end diff --git a/lib/new_relic/agent/instrumentation/concurrent_ruby.rb b/lib/new_relic/agent/instrumentation/concurrent_ruby.rb index 0937bcd73b..0e8c661940 100644 --- a/lib/new_relic/agent/instrumentation/concurrent_ruby.rb +++ b/lib/new_relic/agent/instrumentation/concurrent_ruby.rb @@ -16,8 +16,6 @@ end executes do - NewRelic::Agent.logger.info('Installing concurrent-ruby instrumentation') - if use_prepend? prepend_instrument(Concurrent::ThreadPoolExecutor, NewRelic::Agent::Instrumentation::ConcurrentRuby::Prepend) diff --git a/lib/new_relic/agent/instrumentation/curb.rb b/lib/new_relic/agent/instrumentation/curb.rb index 2aa2699e67..aa38d183c9 100644 --- a/lib/new_relic/agent/instrumentation/curb.rb +++ b/lib/new_relic/agent/instrumentation/curb.rb @@ -16,17 +16,16 @@ end executes do - NewRelic::Agent.logger.info('Installing Curb instrumentation') require 'new_relic/agent/distributed_tracing/cross_app_tracing' require 'new_relic/agent/http_clients/curb_wrappers' end executes do if use_prepend? - prepend_instrument Curl::Easy, NewRelic::Agent::Instrumentation::Curb::Easy::Prepend - prepend_instrument Curl::Multi, NewRelic::Agent::Instrumentation::Curb::Multi::Prepend + prepend_instrument Curl::Easy, NewRelic::Agent::Instrumentation::Curb::Easy::Prepend, 'Curb::Easy' + prepend_instrument Curl::Multi, NewRelic::Agent::Instrumentation::Curb::Multi::Prepend, 'Curb::Multi' else - chain_instrument NewRelic::Agent::Instrumentation::Curb::Chain + chain_instrument NewRelic::Agent::Instrumentation::Curb::Chain, NewRelic::Agent::Instrumentation::Curb::Multi::INSTRUMENTATION_NAME end end end diff --git a/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb b/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb index e5c88644e5..b9bde8ac1d 100644 --- a/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +++ b/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb @@ -82,10 +82,6 @@ def method_name(payload_object) defined?(Delayed) && defined?(Delayed::Worker) end - executes do - NewRelic::Agent.logger.info('Installing DelayedJob instrumentation [part 1/2]') - end - executes do if use_prepend? prepend_instrument Delayed::Worker, NewRelic::Agent::Instrumentation::DelayedJob::Prepend diff --git a/lib/new_relic/agent/instrumentation/dynamodb.rb b/lib/new_relic/agent/instrumentation/dynamodb.rb index 7f74e76f08..dedd1f3c43 100644 --- a/lib/new_relic/agent/instrumentation/dynamodb.rb +++ b/lib/new_relic/agent/instrumentation/dynamodb.rb @@ -14,8 +14,6 @@ end executes do - NewRelic::Agent.logger.info('Installing DynamoDB instrumentation') - if use_prepend? prepend_instrument Aws::DynamoDB::Client, NewRelic::Agent::Instrumentation::DynamoDB::Prepend else diff --git a/lib/new_relic/agent/instrumentation/dynamodb/instrumentation.rb b/lib/new_relic/agent/instrumentation/dynamodb/instrumentation.rb index cf869660f4..721c41e582 100644 --- a/lib/new_relic/agent/instrumentation/dynamodb/instrumentation.rb +++ b/lib/new_relic/agent/instrumentation/dynamodb/instrumentation.rb @@ -31,9 +31,8 @@ def instrument_method_with_new_relic(method_name, *args) collection: args[0][:table_name] ) - # TODO: Update this when it has been decided how to handle account id for ARN - # arn = get_arn(args[0]) - # segment&.add_agent_attribute('cloud.resource_id', arn) if arn + arn = get_arn(args[0]) + segment&.add_agent_attribute('cloud.resource_id', arn) if arn @nr_captured_request = nil # clear request just in case begin @@ -50,16 +49,10 @@ def build_request_with_new_relic(*args) @nr_captured_request = yield end - def nr_account_id - return @nr_account_id if defined?(@nr_account_id) - - @nr_account_id = NewRelic::Agent::Aws.get_account_id(config) - end - def get_arn(params) - return unless params[:table_name] && nr_account_id + return unless params[:table_name] - NewRelic::Agent::Aws.create_arn(PRODUCT.downcase, "table/#{params[:table_name]}", config&.region, nr_account_id) + NewRelic::Agent::Aws.create_arn(PRODUCT.downcase, "table/#{params[:table_name]}", config&.region) end end end diff --git a/lib/new_relic/agent/instrumentation/elasticsearch.rb b/lib/new_relic/agent/instrumentation/elasticsearch.rb index dca764b752..3c34f3c442 100644 --- a/lib/new_relic/agent/instrumentation/elasticsearch.rb +++ b/lib/new_relic/agent/instrumentation/elasticsearch.rb @@ -14,8 +14,6 @@ end executes do - NewRelic::Agent.logger.info('Installing Elasticsearch instrumentation') - to_instrument = if Gem::Version.create(Elasticsearch::VERSION) < Gem::Version.create('8.0.0') Elasticsearch::Transport::Client else diff --git a/lib/new_relic/agent/instrumentation/ethon.rb b/lib/new_relic/agent/instrumentation/ethon.rb index 20daa492d5..8af7469ced 100644 --- a/lib/new_relic/agent/instrumentation/ethon.rb +++ b/lib/new_relic/agent/instrumentation/ethon.rb @@ -21,10 +21,6 @@ defined?(Ethon) && Gem::Version.new(Ethon::VERSION) >= Gem::Version.new('0.12.0') end - executes do - NewRelic::Agent.logger.info('Installing ethon instrumentation') - end - executes do if use_prepend? # NOTE: by default prepend_instrument will go with the module name that diff --git a/lib/new_relic/agent/instrumentation/fiber.rb b/lib/new_relic/agent/instrumentation/fiber.rb index ada212afb0..2412cbe891 100644 --- a/lib/new_relic/agent/instrumentation/fiber.rb +++ b/lib/new_relic/agent/instrumentation/fiber.rb @@ -14,8 +14,6 @@ end executes do - NewRelic::Agent.logger.info('Installing Fiber instrumentation') - if use_prepend? prepend_instrument Fiber, NewRelic::Agent::Instrumentation::MonitoredFiber::Prepend else diff --git a/lib/new_relic/agent/instrumentation/grape.rb b/lib/new_relic/agent/instrumentation/grape.rb index 1424ffa06b..75bae0a0df 100644 --- a/lib/new_relic/agent/instrumentation/grape.rb +++ b/lib/new_relic/agent/instrumentation/grape.rb @@ -19,9 +19,7 @@ depends_on do begin - if defined?(Bundler) && - ((Bundler.rubygems.respond_to?(:installed_specs) && Bundler.rubygems.installed_specs.map(&:name).include?('newrelic-grape')) || - Bundler.rubygems.all_specs.map(&:name).include?('newrelic-grape')) + if NewRelic::Helper.rubygems_specs.map(&:name).include?('newrelic-grape') NewRelic::Agent.logger.info('Not installing New Relic supported Grape instrumentation because the third party newrelic-grape gem is present') false else diff --git a/lib/new_relic/agent/instrumentation/httpclient.rb b/lib/new_relic/agent/instrumentation/httpclient.rb index 9dc9678d86..dc6e1fc871 100644 --- a/lib/new_relic/agent/instrumentation/httpclient.rb +++ b/lib/new_relic/agent/instrumentation/httpclient.rb @@ -23,7 +23,6 @@ end executes do - NewRelic::Agent.logger.info('Installing HTTPClient instrumentation') require 'new_relic/agent/distributed_tracing/cross_app_tracing' require 'new_relic/agent/http_clients/httpclient_wrappers' end diff --git a/lib/new_relic/agent/instrumentation/httprb.rb b/lib/new_relic/agent/instrumentation/httprb.rb index 822a2b0469..0def79c154 100644 --- a/lib/new_relic/agent/instrumentation/httprb.rb +++ b/lib/new_relic/agent/instrumentation/httprb.rb @@ -14,7 +14,6 @@ end executes do - NewRelic::Agent.logger.info('Installing http.rb Wrappers') require 'new_relic/agent/distributed_tracing/cross_app_tracing' require 'new_relic/agent/http_clients/http_rb_wrappers' end diff --git a/lib/new_relic/agent/instrumentation/httpx.rb b/lib/new_relic/agent/instrumentation/httpx.rb index d709532ef0..ed58385230 100644 --- a/lib/new_relic/agent/instrumentation/httpx.rb +++ b/lib/new_relic/agent/instrumentation/httpx.rb @@ -13,10 +13,6 @@ defined?(HTTPX) && Gem::Version.new(HTTPX::VERSION) >= Gem::Version.new('1.0.0') end - executes do - NewRelic::Agent.logger.info('Installing httpx instrumentation') - end - executes do if use_prepend? prepend_instrument HTTPX::Session, NewRelic::Agent::Instrumentation::HTTPX::Prepend diff --git a/lib/new_relic/agent/instrumentation/logger.rb b/lib/new_relic/agent/instrumentation/logger.rb index c351fa6f59..a92b978660 100644 --- a/lib/new_relic/agent/instrumentation/logger.rb +++ b/lib/new_relic/agent/instrumentation/logger.rb @@ -15,12 +15,10 @@ end executes do - NewRelic::Agent.logger.info('Installing Logger instrumentation') - if use_prepend? prepend_instrument Logger, NewRelic::Agent::Instrumentation::Logger::Prepend else - chain_instrument NewRelic::Agent::Instrumentation::Logger + chain_instrument NewRelic::Agent::Instrumentation::Logger, NewRelic::Agent::Instrumentation::Logger::INSTRUMENTATION_NAME end end end diff --git a/lib/new_relic/agent/instrumentation/logstasher.rb b/lib/new_relic/agent/instrumentation/logstasher.rb index 2799996e5e..81129cabce 100644 --- a/lib/new_relic/agent/instrumentation/logstasher.rb +++ b/lib/new_relic/agent/instrumentation/logstasher.rb @@ -16,8 +16,6 @@ end executes do - NewRelic::Agent.logger.info('Installing LogStasher instrumentation') - if use_prepend? prepend_instrument LogStasher.singleton_class, NewRelic::Agent::Instrumentation::LogStasher::Prepend else diff --git a/lib/new_relic/agent/instrumentation/memcache.rb b/lib/new_relic/agent/instrumentation/memcache.rb index f5a9caa2b8..6d2e470a98 100644 --- a/lib/new_relic/agent/instrumentation/memcache.rb +++ b/lib/new_relic/agent/instrumentation/memcache.rb @@ -74,7 +74,6 @@ depends_on { NewRelic::Agent::Instrumentation::Memcache::DalliCAS.should_instrument? } executes do - NewRelic::Agent.logger.info('Installing Dalli CAS Client Memcache instrumentation') if use_prepend? prepend_module = NewRelic::Agent::Instrumentation::Memcache::Prepend prepend_module.dalli_cas_prependers do |client_class, instrumenting_module| diff --git a/lib/new_relic/agent/instrumentation/opensearch.rb b/lib/new_relic/agent/instrumentation/opensearch.rb index 0b10f1914a..0871fe1b15 100644 --- a/lib/new_relic/agent/instrumentation/opensearch.rb +++ b/lib/new_relic/agent/instrumentation/opensearch.rb @@ -14,8 +14,6 @@ end executes do - NewRelic::Agent.logger.info('Installing opensearch-ruby instrumentation') - if use_prepend? prepend_instrument OpenSearch::Transport::Client, NewRelic::Agent::Instrumentation::OpenSearch::Prepend else diff --git a/lib/new_relic/agent/instrumentation/padrino.rb b/lib/new_relic/agent/instrumentation/padrino.rb index 912c0a9487..a81f8ff5b2 100644 --- a/lib/new_relic/agent/instrumentation/padrino.rb +++ b/lib/new_relic/agent/instrumentation/padrino.rb @@ -22,11 +22,11 @@ depends_on { defined?(Padrino) && defined?(Padrino::Routing::InstanceMethods) } executes do - NewRelic::Agent.logger.info('Installing Padrino instrumentation') + supportability_name = NewRelic::Agent::Instrumentation::Padrino::INSTRUMENTATION_NAME if use_prepend? - prepend_instrument Padrino::Application, NewRelic::Agent::Instrumentation::PadrinoTracer::Prepend + prepend_instrument Padrino::Application, NewRelic::Agent::Instrumentation::PadrinoTracer::Prepend, supportability_name else - chain_instrument NewRelic::Agent::Instrumentation::PadrinoTracer::Chain + chain_instrument NewRelic::Agent::Instrumentation::PadrinoTracer::Chain, supportability_name end end end diff --git a/lib/new_relic/agent/instrumentation/rake.rb b/lib/new_relic/agent/instrumentation/rake.rb index 543b52b50d..0581a64153 100644 --- a/lib/new_relic/agent/instrumentation/rake.rb +++ b/lib/new_relic/agent/instrumentation/rake.rb @@ -17,7 +17,6 @@ depends_on { NewRelic::Agent::Instrumentation::Rake.safe_from_third_party_gem? } executes do - NewRelic::Agent.logger.info('Installing Rake instrumentation') NewRelic::Agent.logger.debug("Instrumenting Rake tasks: #{NewRelic::Agent.config[:'rake.tasks']}") end diff --git a/lib/new_relic/agent/instrumentation/rdkafka.rb b/lib/new_relic/agent/instrumentation/rdkafka.rb index 51b8dae73d..e42cc774be 100644 --- a/lib/new_relic/agent/instrumentation/rdkafka.rb +++ b/lib/new_relic/agent/instrumentation/rdkafka.rb @@ -10,8 +10,6 @@ end executes do - NewRelic::Agent.logger.info('Installing rdkafka instrumentation') - require_relative 'rdkafka/instrumentation' require_relative 'rdkafka/chain' require_relative 'rdkafka/prepend' diff --git a/lib/new_relic/agent/instrumentation/rdkafka/chain.rb b/lib/new_relic/agent/instrumentation/rdkafka/chain.rb index fc9b826aa8..8652987fed 100644 --- a/lib/new_relic/agent/instrumentation/rdkafka/chain.rb +++ b/lib/new_relic/agent/instrumentation/rdkafka/chain.rb @@ -40,7 +40,8 @@ def each(**kwargs) alias_method(:producer_without_new_relic, :producer) alias_method(:consumer_without_new_relic, :consumer) - if Gem::Version.new(::Rdkafka::VERSION) >= Gem::Version.new('0.16.0') + if Gem::Version.new(::Rdkafka::VERSION) >= Gem::Version.new('0.16.0') || + (Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7.0')) def producer(**kwargs) producer_without_new_relic(**kwargs).tap do |producer| set_nr_config(producer) diff --git a/lib/new_relic/agent/instrumentation/rdkafka/prepend.rb b/lib/new_relic/agent/instrumentation/rdkafka/prepend.rb index 3397c2436c..24dfba9037 100644 --- a/lib/new_relic/agent/instrumentation/rdkafka/prepend.rb +++ b/lib/new_relic/agent/instrumentation/rdkafka/prepend.rb @@ -36,7 +36,8 @@ module RdkafkaConfig module Prepend include NewRelic::Agent::Instrumentation::RdkafkaConfig - if defined?(::Rdkafka) && Gem::Version.new(::Rdkafka::VERSION) >= Gem::Version.new('0.16.0') + if (defined?(::Rdkafka) && Gem::Version.new(::Rdkafka::VERSION) >= Gem::Version.new('0.16.0')) || + (Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7.0')) def producer(**kwargs) super.tap do |producer| set_nr_config(producer) diff --git a/lib/new_relic/agent/instrumentation/redis.rb b/lib/new_relic/agent/instrumentation/redis.rb index fa435855c3..fdfd43a2a8 100644 --- a/lib/new_relic/agent/instrumentation/redis.rb +++ b/lib/new_relic/agent/instrumentation/redis.rb @@ -31,7 +31,6 @@ end executes do - NewRelic::Agent.logger.info('Installing Redis Instrumentation') if NewRelic::Agent::Instrumentation::Redis::Constants::HAS_REDIS_CLIENT RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::Middleware) diff --git a/lib/new_relic/agent/instrumentation/resque.rb b/lib/new_relic/agent/instrumentation/resque.rb index 8ccd3a8933..3c4158d17e 100644 --- a/lib/new_relic/agent/instrumentation/resque.rb +++ b/lib/new_relic/agent/instrumentation/resque.rb @@ -18,10 +18,6 @@ defined?(Airbrake) && defined?(Airbrake::AIRBRAKE_VERSION) && Gem::Version.create(Airbrake::AIRBRAKE_VERSION) < Gem::Version.create('11.0.3') end - executes do - NewRelic::Agent.logger.info('Installing Resque instrumentation') - end - executes do if NewRelic::Agent.config[:'resque.use_ruby_dns'] && NewRelic::Agent.config[:dispatcher] == :resque NewRelic::Agent.logger.info('Requiring resolv-replace') diff --git a/lib/new_relic/agent/instrumentation/roda.rb b/lib/new_relic/agent/instrumentation/roda.rb index c9f85b263f..2e82f6288a 100644 --- a/lib/new_relic/agent/instrumentation/roda.rb +++ b/lib/new_relic/agent/instrumentation/roda.rb @@ -20,15 +20,15 @@ require_relative '../../rack/agent_hooks' require_relative '../../rack/browser_monitoring' - NewRelic::Agent.logger.info('Installing Roda instrumentation') - if use_prepend? require_relative 'roda/prepend' - prepend_instrument Roda.singleton_class, NewRelic::Agent::Instrumentation::Roda::Build::Prepend + + supportability_name = NewRelic::Agent::Instrumentation::Roda::Tracer::INSTRUMENTATION_NAME + prepend_instrument Roda.singleton_class, NewRelic::Agent::Instrumentation::Roda::Build::Prepend, supportability_name prepend_instrument Roda, NewRelic::Agent::Instrumentation::Roda::Prepend else require_relative 'roda/chain' - chain_instrument NewRelic::Agent::Instrumentation::Roda::Build::Chain + chain_instrument NewRelic::Agent::Instrumentation::Roda::Build::Chain, supportability_name chain_instrument NewRelic::Agent::Instrumentation::Roda::Chain end Roda.class_eval { extend NewRelic::Agent::Instrumentation::Roda::Ignorer } diff --git a/lib/new_relic/agent/instrumentation/ruby_kafka.rb b/lib/new_relic/agent/instrumentation/ruby_kafka.rb index 6ab2c88654..42da1c2c86 100644 --- a/lib/new_relic/agent/instrumentation/ruby_kafka.rb +++ b/lib/new_relic/agent/instrumentation/ruby_kafka.rb @@ -14,8 +14,6 @@ end executes do - NewRelic::Agent.logger.info('Installing ruby-kafka instrumentation') - if use_prepend? prepend_instrument Kafka::Producer, NewRelic::Agent::Instrumentation::RubyKafkaProducer::Prepend prepend_instrument Kafka::Consumer, NewRelic::Agent::Instrumentation::RubyKafkaConsumer::Prepend diff --git a/lib/new_relic/agent/instrumentation/ruby_kafka/prepend.rb b/lib/new_relic/agent/instrumentation/ruby_kafka/prepend.rb index 66cec78a33..063fb6e511 100644 --- a/lib/new_relic/agent/instrumentation/ruby_kafka/prepend.rb +++ b/lib/new_relic/agent/instrumentation/ruby_kafka/prepend.rb @@ -20,10 +20,20 @@ module RubyKafkaConsumer module Prepend include NewRelic::Agent::Instrumentation::RubyKafka - def each_message(*args) - super do |message| - each_message_with_new_relic(message) do - yield(message) + if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3') + def each_message(**args) + super do |message| + each_message_with_new_relic(message) do + yield(message) + end + end + end + else + def each_message(*args) + super do |message| + each_message_with_new_relic(message) do + yield(message) + end end end end diff --git a/lib/new_relic/agent/instrumentation/sinatra.rb b/lib/new_relic/agent/instrumentation/sinatra.rb index ceb743e574..29e83370fa 100644 --- a/lib/new_relic/agent/instrumentation/sinatra.rb +++ b/lib/new_relic/agent/instrumentation/sinatra.rb @@ -16,10 +16,6 @@ depends_on { Sinatra::Base.private_method_defined?(:process_route) } depends_on { Sinatra::Base.private_method_defined?(:route_eval) } - executes do - NewRelic::Agent.logger.info('Installing Sinatra instrumentation') - end - executes do if use_prepend? prepend_instrument Sinatra::Base, NewRelic::Agent::Instrumentation::Sinatra::Prepend @@ -32,14 +28,15 @@ end executes do + supportability_name = NewRelic::Agent::Instrumentation::Sinatra::Tracer::INSTRUMENTATION_NAME # These requires are inside an executes block because they require rack, and # we can't be sure that rack is available when this file is first required. require 'new_relic/rack/agent_hooks' require 'new_relic/rack/browser_monitoring' if use_prepend? - prepend_instrument Sinatra::Base.singleton_class, NewRelic::Agent::Instrumentation::Sinatra::Build::Prepend + prepend_instrument Sinatra::Base.singleton_class, NewRelic::Agent::Instrumentation::Sinatra::Build::Prepend, supportability_name else - chain_instrument NewRelic::Agent::Instrumentation::Sinatra::Build::Chain + chain_instrument NewRelic::Agent::Instrumentation::Sinatra::Build::Chain, supportability_name end end end diff --git a/lib/new_relic/agent/instrumentation/thread.rb b/lib/new_relic/agent/instrumentation/thread.rb index e5880206c6..536c5b7467 100644 --- a/lib/new_relic/agent/instrumentation/thread.rb +++ b/lib/new_relic/agent/instrumentation/thread.rb @@ -9,8 +9,6 @@ named :thread executes do - NewRelic::Agent.logger.info('Installing Thread Instrumentation') - if use_prepend? prepend_instrument Thread, NewRelic::Agent::Instrumentation::MonitoredThread::Prepend else diff --git a/lib/new_relic/agent/instrumentation/tilt.rb b/lib/new_relic/agent/instrumentation/tilt.rb index f9c9d2765f..5f27e9b442 100644 --- a/lib/new_relic/agent/instrumentation/tilt.rb +++ b/lib/new_relic/agent/instrumentation/tilt.rb @@ -11,10 +11,6 @@ depends_on { defined?(Tilt) } - executes do - NewRelic::Agent.logger.info('Installing Tilt instrumentation') - end - executes do if use_prepend? prepend_instrument Tilt::Template, NewRelic::Agent::Instrumentation::Tilt::Prepend diff --git a/lib/new_relic/agent/instrumentation/typhoeus.rb b/lib/new_relic/agent/instrumentation/typhoeus.rb index def686f7a3..0699e1e34d 100644 --- a/lib/new_relic/agent/instrumentation/typhoeus.rb +++ b/lib/new_relic/agent/instrumentation/typhoeus.rb @@ -18,7 +18,6 @@ end executes do - NewRelic::Agent.logger.info('Installing Typhoeus instrumentation') require 'new_relic/agent/distributed_tracing/cross_app_tracing' require 'new_relic/agent/http_clients/typhoeus_wrappers' end diff --git a/lib/new_relic/agent/instrumentation/view_component.rb b/lib/new_relic/agent/instrumentation/view_component.rb index 900336c67a..d9f09c0f52 100644 --- a/lib/new_relic/agent/instrumentation/view_component.rb +++ b/lib/new_relic/agent/instrumentation/view_component.rb @@ -15,8 +15,6 @@ end executes do - NewRelic::Agent.logger.info('Installing ViewComponent instrumentation') - if use_prepend? prepend_instrument ViewComponent::Base, NewRelic::Agent::Instrumentation::ViewComponent::Prepend else diff --git a/lib/new_relic/agent/instrumentation/view_component/instrumentation.rb b/lib/new_relic/agent/instrumentation/view_component/instrumentation.rb index 3005214c36..b565f81e10 100644 --- a/lib/new_relic/agent/instrumentation/view_component/instrumentation.rb +++ b/lib/new_relic/agent/instrumentation/view_component/instrumentation.rb @@ -10,12 +10,7 @@ def render_in_with_tracing(*args) NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME) begin - segment = NewRelic::Agent::Tracer.start_segment( - name: metric_name( - self.class.respond_to?(:identifier) ? self.class.identifier : nil, - self.class.name - ) - ) + segment = NewRelic::Agent::Tracer.start_segment(name: metric_name) yield rescue => e NewRelic::Agent.notice_error(e) @@ -25,8 +20,12 @@ def render_in_with_tracing(*args) end end - def metric_name(identifier, component) - "View/#{metric_path(identifier)}/#{component}" + def metric_name + "View/#{metric_path(self.class.source_location)}/#{self.class.name}" + rescue => e + NewRelic::Agent.logger.error('Error identifying View Component metric name', e) + + 'View/component' end def metric_path(identifier) diff --git a/lib/new_relic/agent/span_event_primitive.rb b/lib/new_relic/agent/span_event_primitive.rb index 09c96fcf0b..ef2ef8882b 100644 --- a/lib/new_relic/agent/span_event_primitive.rb +++ b/lib/new_relic/agent/span_event_primitive.rb @@ -52,6 +52,8 @@ module SpanEventPrimitive DATASTORE_CATEGORY = 'datastore' CLIENT = 'client' + DB_STATEMENT_MAX_BYTES = 4096 + # Builds a Hash of error attributes as well as the Span ID when # an error is present. Otherwise, returns nil when no error present. def error_attributes(segment) @@ -114,9 +116,9 @@ def for_datastore_segment(segment) # rubocop:disable Metrics/AbcSize agent_attributes[DB_SYSTEM_KEY] = segment.product if allowed?(DB_SYSTEM_KEY) if segment.sql_statement && allowed?(DB_STATEMENT_KEY) - agent_attributes[DB_STATEMENT_KEY] = truncate(segment.sql_statement.safe_sql, 2000) + agent_attributes[DB_STATEMENT_KEY] = truncate(segment.sql_statement.safe_sql, DB_STATEMENT_MAX_BYTES) elsif segment.nosql_statement && allowed?(DB_STATEMENT_KEY) - agent_attributes[DB_STATEMENT_KEY] = truncate(segment.nosql_statement, 2000) + agent_attributes[DB_STATEMENT_KEY] = truncate(segment.nosql_statement, DB_STATEMENT_MAX_BYTES) end [intrinsics, custom_attributes(segment), agent_attributes.merge(agent_attributes(segment))] diff --git a/lib/new_relic/control/frameworks/rails4.rb b/lib/new_relic/control/frameworks/rails4.rb index 23d403dd69..b8545f92df 100644 --- a/lib/new_relic/control/frameworks/rails4.rb +++ b/lib/new_relic/control/frameworks/rails4.rb @@ -9,11 +9,7 @@ class Control module Frameworks class Rails4 < NewRelic::Control::Frameworks::Rails3 def rails_gem_list - if Bundler.rubygems.respond_to?(:installed_specs) - Bundler.rubygems.installed_specs.map { |gem| "#{gem.name} (#{gem.version})" } - else - Bundler.rubygems.all_specs.map { |gem| "#{gem.name} (#{gem.version})" } - end + NewRelic::Helper.rubygems_specs.map { |gem| "#{gem.name} (#{gem.version})" } end def append_plugin_list diff --git a/lib/new_relic/dependency_detection.rb b/lib/new_relic/dependency_detection.rb index 5cd93f705c..d9c7dff358 100644 --- a/lib/new_relic/dependency_detection.rb +++ b/lib/new_relic/dependency_detection.rb @@ -25,11 +25,9 @@ def defer(&block) def detect! @items.each do |item| - if item.dependencies_satisfied? - item.execute - else - item.configure_as_unsatisfied unless item.disabled_configured? - end + next if item.executed || item.disabled_configured? + + item.dependencies_satisfied? ? item.execute : item.configure_as_unsatisfied end end @@ -65,6 +63,13 @@ def dependencies_satisfied? end def configure_as_unsatisfied + # TODO: currently using :unsatisfied for Padrino will clobber the value + # already set for Sinatra, so skip Padrino and circle back with a + # new Padrino specific solution in the future. + # + # https://github.com/newrelic/newrelic-ruby-agent/issues/2912 + return if name == :padrino + NewRelic::Agent.config.instance_variable_get(:@cache)[config_key] = :unsatisfied end diff --git a/lib/new_relic/environment_report.rb b/lib/new_relic/environment_report.rb index 1661bebeb6..301fe83c0f 100644 --- a/lib/new_relic/environment_report.rb +++ b/lib/new_relic/environment_report.rb @@ -44,11 +44,7 @@ def self.registered_reporters=(logic) #################################### report_on('Gems') do begin - if Bundler.rubygems.respond_to?(:installed_specs) - Bundler.rubygems.installed_specs.map { |gem| "#{gem.name}(#{gem.version})" } - else - Bundler.rubygems.all_specs.map { |gem| "#{gem.name}(#{gem.version})" } - end + NewRelic::Helper.rubygems_specs.map { |gem| "#{gem.name}(#{gem.version})" } rescue # There are certain rubygem, bundler, rails combinations (e.g. gem # 1.6.2, rails 2.3, bundler 1.2.3) where the code above throws an error diff --git a/lib/new_relic/helper.rb b/lib/new_relic/helper.rb index 7d17c89908..3f89b9e36b 100644 --- a/lib/new_relic/helper.rb +++ b/lib/new_relic/helper.rb @@ -82,5 +82,20 @@ def executable_in_path?(executable) File.exist?(executable_path) && File.file?(executable_path) && File.executable?(executable_path) end end + + # Bundler version 2.5.12 deprecated all_specs and added installed_specs. + # To support newer Bundler versions, try to use installed_specs first, + # then fall back to all_specs. + # All callers expect this to be an array, so return an array if Bundler isn't defined + # @api private + def rubygems_specs + return [] unless defined?(Bundler) + + if Bundler.rubygems.respond_to?(:installed_specs) + Bundler.rubygems.installed_specs + else + Bundler.rubygems.all_specs + end + end end end diff --git a/lib/new_relic/language_support.rb b/lib/new_relic/language_support.rb index 140d2455d2..31377e831a 100644 --- a/lib/new_relic/language_support.rb +++ b/lib/new_relic/language_support.rb @@ -90,11 +90,7 @@ def snakeize(string) def bundled_gem?(gem_name) return false unless defined?(Bundler) - if Bundler.rubygems.respond_to?(:installed_specs) - Bundler.rubygems.installed_specs.map(&:name).include?(gem_name) - else - Bundler.rubygems.all_specs.map(&:name).include?(gem_name) - end + NewRelic::Helper.rubygems_specs.map(&:name).include?(gem_name) rescue => e ::NewRelic::Agent.logger.info("Could not determine if third party #{gem_name} gem is installed", e) false diff --git a/lib/new_relic/version.rb b/lib/new_relic/version.rb index a64d74cf2e..9e720e3211 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 = 14 + MINOR = 15 TINY = 0 STRING = "#{MAJOR}.#{MINOR}.#{TINY}" diff --git a/lib/sequel/extensions/new_relic_instrumentation.rb b/lib/sequel/extensions/new_relic_instrumentation.rb index 11a465b7af..13602c11ac 100644 --- a/lib/sequel/extensions/new_relic_instrumentation.rb +++ b/lib/sequel/extensions/new_relic_instrumentation.rb @@ -79,7 +79,7 @@ def notice_sql(sql) THREAD_SAFE_CONNECTION_POOL_CLASSES = [ (defined?(::Sequel::ThreadedConnectionPool) && ::Sequel::ThreadedConnectionPool), - (defined?(::Sequel::TimedQueueConnectionPool) && RUBY_VERSION >= '3.4' && ::Sequel::TimedQueueConnectionPool) + (defined?(::Sequel::TimedQueueConnectionPool) && RUBY_VERSION >= '3.2' && ::Sequel::TimedQueueConnectionPool) ].compact.freeze def explainer_for(sql) diff --git a/lib/tasks/instrumentation_generator/templates/dependency_detection.tt b/lib/tasks/instrumentation_generator/templates/dependency_detection.tt index 2b17a16e80..be9ad8a8df 100644 --- a/lib/tasks/instrumentation_generator/templates/dependency_detection.tt +++ b/lib/tasks/instrumentation_generator/templates/dependency_detection.tt @@ -2,12 +2,8 @@ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details. # frozen_string_literal: true -require_relative '<%= @snake_name.downcase %>/instrumentation' -require_relative '<%= @snake_name.downcase %>/chain' -require_relative '<%= @snake_name.downcase %>/prepend' - DependencyDetection.defer do - named :<%= @name.match?(/\-|\_/) ? "'#{@snake_name}'" : @name.downcase %> + named :<%= @snake_name %> depends_on do # The class that needs to be defined to prepend/chain onto. This can be used @@ -18,11 +14,18 @@ DependencyDetection.defer do end executes do - NewRelic::Agent.logger.info('Installing <%= @name.downcase %> instrumentation') + require_relative '<%= @snake_name.downcase %>/instrumentation' + # prepend_instrument and chain_instrument call extract_supportability_name + # to get the library name for supportability metrics and info-level logging. + # This is done by spliting on the 2nd to last spot of the instrumented + # module. If this isn't how we want the name to appear, pass in the desired + # name as a third argument. if use_prepend? + require_relative '<%= @snake_name.downcase %>/prepend' prepend_instrument <%= @class_name %>, NewRelic::Agent::Instrumentation::<%= @class_name %>::Prepend else + require_relative '<%= @snake_name.downcase %>/chain' chain_instrument NewRelic::Agent::Instrumentation::<%= @class_name %>::Chain end end diff --git a/newrelic.yml b/newrelic.yml index a9f475437d..d23ae4183f 100644 --- a/newrelic.yml +++ b/newrelic.yml @@ -114,9 +114,9 @@ common: &default_settings # audit_log.path: log/newrelic_audit.log # An array of CLASS#METHOD (for instance methods) and/or CLASS.METHOD (for class - # methods) strings representing Ruby methods for the agent to automatically add - # custom instrumentation to without the need for altering any of the source code - # that defines the methods. + # methods) strings representing Ruby methods for the agent to automatically + # add custom instrumentation to without the need for altering any of the + # source code that defines the methods. # # Use fully qualified class names (using the :: delimiter) that include any # module or class namespacing. @@ -138,10 +138,10 @@ common: &default_settings # end # end # end - # + # # Given that source code, the newrelic.yml config file might request # instrumentation for both of these methods like so: - # + # # automatic_custom_instrumentation_method_list: # - MyCompany::Image#render_png # - MyCompany::User.notify @@ -216,6 +216,9 @@ common: &default_settings # If true, the agent will clear Tracer::State in Agent.drop_buffered_data. # clear_transaction_state_after_fork: false + # The AWS account ID for the AWS account associated with this app + # cloud.aws.account_id: nil + # If true, the agent will report source code level metrics for traced methods. # See: # https://docs.newrelic.com/docs/apm/agents/ruby-agent/features/ruby-codestream-integration/ diff --git a/test/agent_helper.rb b/test/agent_helper.rb index f53f4b7af3..ae7dfea555 100644 --- a/test/agent_helper.rb +++ b/test/agent_helper.rb @@ -112,7 +112,7 @@ def assert_log_contains(log, message) lines = log.array assert (lines.any? { |line| line.match(message) }), - "Could not find message. Log contained: #{lines.join("\n")}" + "Could not find message: '#{message.inspect}'. Log contained: #{lines.join("\n")}" end def assert_audit_log_contains(audit_log_contents, needle) diff --git a/test/multiverse/lib/multiverse/runner.rb b/test/multiverse/lib/multiverse/runner.rb index 1224a1c1bd..a7470ed51e 100644 --- a/test/multiverse/lib/multiverse/runner.rb +++ b/test/multiverse/lib/multiverse/runner.rb @@ -102,6 +102,7 @@ def execute_suites(filter, opts) 'ai' => %w[ruby_openai], 'background' => %w[delayed_job sidekiq resque], 'background_2' => %w[rake], + 'kafka' => %w[rdkafka], 'database' => %w[elasticsearch mongo redis sequel], 'rails' => %w[active_record active_record_pg active_support_broadcast_logger active_support_logger rails rails_prepend activemerchant], 'frameworks' => %w[grape padrino roda sinatra], diff --git a/test/multiverse/lib/multiverse/suite.rb b/test/multiverse/lib/multiverse/suite.rb index 5a3efd9005..05489b019f 100755 --- a/test/multiverse/lib/multiverse/suite.rb +++ b/test/multiverse/lib/multiverse/suite.rb @@ -553,7 +553,7 @@ def child_command_line(env, instrumentation_method) def check_for_failure(env) if $? != 0 - OutputCollector.write(suite, env, red("#{suite.inspect} for Envfile entry #{env} failed!")) + OutputCollector.write(suite, env, red("#{suite.inspect} for Envfile entry #{env} failed! (exit: #{$?})")) OutputCollector.failed(suite, env) end Multiverse::Runner.notice_exit_status($?) diff --git a/test/multiverse/suites/config_file_loading/Envfile b/test/multiverse/suites/config_file_loading/Envfile index 819a8a1039..c90f1707e8 100644 --- a/test/multiverse/suites/config_file_loading/Envfile +++ b/test/multiverse/suites/config_file_loading/Envfile @@ -4,20 +4,34 @@ omit_collector! +# TODO: RUBY 3.4 +# The CI has a prism-related error when it tries to run this suite +# The problem may be a bug fixed in future preview releases +# Disable ths suite for now, and try again when the next version +# is out. PSYCH_VERSIONS = [ - [nil], - ['4.0.0', 2.4], - ['3.3.0', 2.4] + [nil, 2.4, 3.3], + ['4.0.0', 2.4, 3.3], + ['3.3.0', 2.4, 3.3] ] +def stringio_version + if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.4') + "gem 'stringio', '3.1.2.dev'" + else + "gem 'stringio'" + end +end + def gem_list(psych_version = nil) <<~RB + #{stringio_version} # stub file system so we can test that newrelic.yml can be loaded from # various places. gem 'fakefs', :require => false gem 'psych'#{psych_version} - gem 'jar-dependencies', '0.4.1' if RUBY_PLATFORM == 'java' + gem 'jar-dependencies', '0.4.1' if RUBY_PLATFORM == 'java' # don't start the agent gem 'newrelic_rpm', :require => false, :path => File.expand_path('../../../../') diff --git a/test/multiverse/suites/config_file_loading/config_file_loading_test.rb b/test/multiverse/suites/config_file_loading/config_file_loading_test.rb index 15b18c5cd2..953427bea7 100644 --- a/test/multiverse/suites/config_file_loading/config_file_loading_test.rb +++ b/test/multiverse/suites/config_file_loading/config_file_loading_test.rb @@ -158,15 +158,20 @@ def test_warning_logged_when_config_file_yaml_parsing_error assert_log_contains(log, /ERROR.*Failed to read or parse configuration file at config\/newrelic\.yml/) end - def test_warning_logged_when_config_file_erb_error - path = File.join(@cwd, 'config', 'newrelic.yml') - setup_config(path, {}, "\n\n\n<%= this is not ruby %>") # the error is on line 4 - setup_agent - - log = with_array_logger { NewRelic::Agent.manual_start } - - assert_log_contains(log, /ERROR.*Failed ERB processing/) - assert_log_contains(log, /\(erb\):4/) + # TODO: RUBY 3.4 SUPPORT + # Both error class and output have changes in Ruby 3.4 + # See Issue: https://github.com/newrelic/newrelic-ruby-agent/issues/2902 + unless Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.4.0') + def test_warning_logged_when_config_file_erb_error + path = File.join(@cwd, 'config', 'newrelic.yml') + setup_config(path, {}, "\n\n\n<%= this is not ruby %>") # the error is on line 4 + setup_agent + + log = with_array_logger { NewRelic::Agent.manual_start } + + assert_log_contains(log, /ERROR.*Failed ERB processing/) + assert_log_contains(log, /\(erb\):4/) + end end def test_exclude_commented_out_erb_lines diff --git a/test/multiverse/suites/dynamodb/dynamodb_instrumentation_test.rb b/test/multiverse/suites/dynamodb/dynamodb_instrumentation_test.rb index 9da2e08885..73c421ac4a 100644 --- a/test/multiverse/suites/dynamodb/dynamodb_instrumentation_test.rb +++ b/test/multiverse/suites/dynamodb/dynamodb_instrumentation_test.rb @@ -8,7 +8,6 @@ class DynamodbInstrumentationTest < Minitest::Test def setup Aws.config.update(stub_responses: true) NewRelic::Agent::Aws.stubs(:create_arn).returns('test-arn') - NewRelic::Agent::Aws.stubs(:get_account_id).returns('123456789') @stats_engine = NewRelic::Agent.instance.stats_engine end @@ -42,8 +41,7 @@ def test_all_attributes_added_to_segment assert_equal 'us-east-2', span[2]['aws.region'] assert_equal 'query', span[2]['aws.operation'] assert_equal '1234321', span[2]['aws.requestId'] - # TODO: Uncomment this when the ARN is added to the segment - # assert_equal 'test-arn', span[2]['cloud.resource_id'] + assert_equal 'test-arn', span[2]['cloud.resource_id'] end def test_create_table_table_name_operation diff --git a/test/multiverse/suites/sinatra/sinatra_test_cases.rb b/test/multiverse/suites/sinatra/sinatra_test_cases.rb index c7a04e98fe..e3b629d801 100644 --- a/test/multiverse/suites/sinatra/sinatra_test_cases.rb +++ b/test/multiverse/suites/sinatra/sinatra_test_cases.rb @@ -128,6 +128,13 @@ def test_with_regex_pattern assert_metrics_recorded(["Controller/Sinatra/#{app_name}/#{regex_segment}"]) end + def test_that_the_actively_configured_instrumentation_is_not_marked_as_unsatsfied + get('/pass') + + assert_equal 200, last_response.status + assert_includes(%w[chain prepend], NewRelic::Agent.config[:'instrumentation.sinatra'].to_s) + end + # https://support.newrelic.com/tickets/31061 def test_precondition_not_over_called get('/precondition') diff --git a/test/multiverse/suites/stripe/Envfile b/test/multiverse/suites/stripe/Envfile index 8d8a605713..ef6692375d 100644 --- a/test/multiverse/suites/stripe/Envfile +++ b/test/multiverse/suites/stripe/Envfile @@ -8,6 +8,7 @@ instrumentation_methods :chain STRIPE_VERSIONS = [ [nil, 2.4], + ['12.6.0', 2.4], ['5.38.0', 2.4] ] diff --git a/test/multiverse/suites/stripe/stripe_instrumentation_test.rb b/test/multiverse/suites/stripe/stripe_instrumentation_test.rb index c6b5bd207e..db6c0dc991 100644 --- a/test/multiverse/suites/stripe/stripe_instrumentation_test.rb +++ b/test/multiverse/suites/stripe/stripe_instrumentation_test.rb @@ -199,9 +199,19 @@ def stripe_segment_from_transaction(txn) end def with_stubbed_connection_manager(&block) - Stripe::StripeClient.stub(:default_connection_manager, @connection) do - @connection.stub(:execute_request, @response) do - yield + # Stripe moved StripeClient and requestor logic to APIRequestor in v13.0.0 + # https://github.com/stripe/stripe-ruby/pull/1458 + if Gem::Version.new(Stripe::VERSION) >= Gem::Version.new('13.0.0') + Stripe::APIRequestor.stub(:default_connection_manager, @connection) do + @connection.stub(:execute_request, @response) do + yield + end + end + else + Stripe::StripeClient.stub(:default_connection_manager, @connection) do + @connection.stub(:execute_request, @response) do + yield + end end end end diff --git a/test/multiverse/suites/view_component/view_component_instrumentation_test.rb b/test/multiverse/suites/view_component/view_component_instrumentation_test.rb index 01e36d291c..f446a1d469 100644 --- a/test/multiverse/suites/view_component/view_component_instrumentation_test.rb +++ b/test/multiverse/suites/view_component/view_component_instrumentation_test.rb @@ -58,14 +58,12 @@ def test_error_raised end end - # Test metric name being built when the controller class doesn't respond to :identifier - # https://github.com/newrelic/newrelic-ruby-agent/pull/2870 - def test_the_metric_name_omits_the_identifier_when_absent + def test_the_metric_name_records_default_name_on_error in_transaction do |txn| FAKE_CLASS.render_in_with_tracing { 11 * 38 } actual_name = txn.segments.last.name - assert_equal 'View/component/DummyViewComponentInstrumentationClass', actual_name + assert_equal 'View/component', actual_name end end end diff --git a/test/new_relic/agent/aws_test.rb b/test/new_relic/agent/aws_test.rb index 61f32c81d0..7af8b8247f 100644 --- a/test/new_relic/agent/aws_test.rb +++ b/test/new_relic/agent/aws_test.rb @@ -10,22 +10,16 @@ def test_create_arn region = 'us-test-region-1' account_id = '123456789' resource = 'test/test-resource' - arn = NewRelic::Agent::Aws.create_arn(service, resource, region, account_id) - expected = 'arn:aws:test-service:us-test-region-1:123456789:test/test-resource' - assert_equal expected, arn - end - - def test_get_account_id - config = mock - mock_credentials = mock - mock_credentials.stubs(:credentials).returns(mock_credentials) - mock_credentials.stubs(:access_key_id).returns('AKIAIOSFODNN7EXAMPLE') # this is a fake access key id from aws docs - config.stubs(:credentials).returns(mock_credentials) + with_config('cloud.aws.account_id': account_id) do + arn = NewRelic::Agent::Aws.create_arn(service, resource, region) - account_id = NewRelic::Agent::Aws.get_account_id(config) + assert_equal expected, arn + end + end - assert_equal 36315003739, account_id + def test_doesnt_create_arn_no_account_id + assert_nil NewRelic::Agent::Aws.create_arn('service', 'resource', 'region') end end diff --git a/test/new_relic/agent/configuration/manager_test.rb b/test/new_relic/agent/configuration/manager_test.rb index b574690a98..f5adc12654 100644 --- a/test/new_relic/agent/configuration/manager_test.rb +++ b/test/new_relic/agent/configuration/manager_test.rb @@ -492,20 +492,22 @@ def test_apply_transformations_reraises_errors end def test_auto_determined_values_stay_cached - name = :knockbreck_manse + with_config(:'security.agent.enabled' => true) do + name = :knockbreck_manse - DependencyDetection.defer do - named(name) - executes { use_prepend? } - end + DependencyDetection.defer do + named(name) + executes { use_prepend? } + end - key = :"instrumentation.#{name}" - with_config(key => 'auto') do - DependencyDetection.detect! + key = :"instrumentation.#{name}" + with_config(key => 'auto') do + DependencyDetection.detect! - @manager.replace_or_add_config(ServerSource.new({})) + @manager.replace_or_add_config(ServerSource.new({})) - assert_equal :prepend, @manager.instance_variable_get(:@cache)[key] + assert_equal :prepend, @manager.instance_variable_get(:@cache)[key] + end end end @@ -533,8 +535,8 @@ def test_unsatisfied_values_stay_cached def test_logger_does_not_receive_excluded_settings log = with_array_logger(:debug) { @manager.log_config('direction', 'source') }.array.join('') - assert_includes(log, ':app_name') - refute_includes(log, ':license_key') + assert_includes(log, 'app_name') + refute_includes(log, 'license_key') end def test_reset_cache_return_early_for_jruby @@ -550,6 +552,23 @@ def phony_cache.dup; self[:dup_called] = true; self; end @manager.new_cache end + # https://github.com/newrelic/newrelic-ruby-agent/issues/2919 + def test_that_boolean_based_params_always_go_through_any_defined_transform_sequence + key = :soundwave + defaults = {key => {default: false, + public: true, + type: Boolean, + allowed_from_server: false, + transform: proc { |bool| bool.to_s.reverse }, + description: 'Param what transforms'}} + NewRelic::Agent::Configuration.stub_const(:DEFAULTS, defaults) do + mgr = NewRelic::Agent::Configuration::Manager.new + value = mgr[key] + + assert_equal 'eslaf', value, 'Expected `false` boolean value to be transformed!' + end + end + private def assert_parsed_labels(expected) diff --git a/test/new_relic/agent/serverless_handler_test.rb b/test/new_relic/agent/serverless_handler_test.rb index 75d363d152..5255e6d9d6 100644 --- a/test/new_relic/agent/serverless_handler_test.rb +++ b/test/new_relic/agent/serverless_handler_test.rb @@ -467,6 +467,18 @@ def test_http_uri_handles_errors logger_mock.verify end + # https://github.com/newrelic/newrelic-ruby-agent/issues/2919 + def test_env_var_will_properly_enable_serverless_mode + NewRelic::Agent.config.remove_config(@test_config) + + ENV.stub(:key?, NewRelic::Agent::ServerlessHandler::LAMBDA_ENVIRONMENT_VARIABLE, true) do + NewRelic::Agent.config.send(:reset_cache) + + assert NewRelic::Agent.config[:'serverless_mode.enabled'], + 'Expected the presence of an env var to enable serverless mode!' + end + end + private def handler diff --git a/test/new_relic/agent/transaction/datastore_segment_test.rb b/test/new_relic/agent/transaction/datastore_segment_test.rb index 9385d92db8..a888034664 100644 --- a/test/new_relic/agent/transaction/datastore_segment_test.rb +++ b/test/new_relic/agent/transaction/datastore_segment_test.rb @@ -383,6 +383,7 @@ def test_nosql_statement_added_to_span_event_if_present end def test_span_event_truncates_long_sql_statement + select = 'select * from ' with_config(:'transaction_tracer.record_sql' => 'raw') do in_transaction('wat') do |txn| txn.stubs(:sampled?).returns(true) @@ -392,7 +393,7 @@ def test_span_event_truncates_long_sql_statement operation: 'select' ) - sql_statement = "select * from #{'a' * 2500}" + sql_statement = "#{select}#{'a' * (SpanEventPrimitive::DB_STATEMENT_MAX_BYTES + 500)}" segment.notice_sql(sql_statement) segment.finish @@ -401,12 +402,15 @@ def test_span_event_truncates_long_sql_statement last_span_events = NewRelic::Agent.agent.span_event_aggregator.harvest![1] _, _, agent_attributes = last_span_events[0] + ellipsis = '...' - assert_equal 2000, agent_attributes['db.statement'].bytesize - assert_equal "select * from #{'a' * 1983}...", agent_attributes['db.statement'] + assert_equal SpanEventPrimitive::DB_STATEMENT_MAX_BYTES, agent_attributes['db.statement'].bytesize + assert_equal "#{select}#{'a' * (SpanEventPrimitive::DB_STATEMENT_MAX_BYTES - select.size - ellipsis.size)}#{ellipsis}", + agent_attributes['db.statement'] end def test_span_event_truncates_long_nosql_statement + set_mykey = 'set mykey ' in_transaction('wat') do |txn| txn.stubs(:sampled?).returns(true) @@ -414,7 +418,7 @@ def test_span_event_truncates_long_nosql_statement product: 'Redis', operation: 'set' ) - statement = "set mykey #{'a' * 2500}" + statement = "#{set_mykey}#{'a' * (SpanEventPrimitive::DB_STATEMENT_MAX_BYTES + 500)}" segment.notice_nosql_statement(statement) segment.finish @@ -422,9 +426,11 @@ def test_span_event_truncates_long_nosql_statement last_span_events = NewRelic::Agent.agent.span_event_aggregator.harvest![1] _, _, agent_attributes = last_span_events[0] + ellipsis = '...' - assert_equal 2000, agent_attributes['db.statement'].bytesize - assert_equal "set mykey #{'a' * 1987}...", agent_attributes['db.statement'] + assert_equal SpanEventPrimitive::DB_STATEMENT_MAX_BYTES, agent_attributes['db.statement'].bytesize + assert_equal "#{set_mykey}#{'a' * (SpanEventPrimitive::DB_STATEMENT_MAX_BYTES - set_mykey.size - ellipsis.size)}#{ellipsis}", + agent_attributes['db.statement'] end def test_span_event_truncates_long_attributes diff --git a/test/new_relic/dependency_detection_test.rb b/test/new_relic/dependency_detection_test.rb index b4223340a5..d60a0cbadc 100644 --- a/test/new_relic/dependency_detection_test.rb +++ b/test/new_relic/dependency_detection_test.rb @@ -488,4 +488,21 @@ def test_prepend_is_replaced_by_unsatisfied_when_appropriate assert_equal :unsatisfied, dd.config_value end end + + def test_already_executed_items_are_not_executed_again + unexecuted = Minitest::Mock.new + unexecuted.expect :executed, false + unexecuted.expect :dependencies_satisfied?, true + unexecuted.expect :disabled_configured?, false + unexecuted.expect :execute, -> { execution_took_place = true } + executed = Minitest::Mock.new + executed.expect :executed, true + unexecuted.expect :disabled_configured?, false + + DependencyDetection.instance_variable_set(:@items, [unexecuted, executed]) + DependencyDetection.detect! + + unexecuted.verify + executed.verify + end end diff --git a/test/new_relic/helper_test.rb b/test/new_relic/helper_test.rb index e47a838a40..2ec6dcef94 100644 --- a/test/new_relic/helper_test.rb +++ b/test/new_relic/helper_test.rb @@ -77,4 +77,28 @@ def test_run_command_sad_exception NewRelic::Helper.run_command('executable that existed at detection time but is not there now') end end + + # + # rubygems_specs + # + def test_rubygems_specs_returns_empty_array_without_bundler + stub(:defined?, nil, ['Bundler']) do + result = NewRelic::Helper.rubygems_specs + + assert_instance_of Array, result + assert_empty Array, result + end + end + + def test_rubygems_specs_works_with_all_specs_when_installed_specs_is_absent + Bundler.rubygems.stub(:respond_to?, nil) do + assert_equal Bundler.rubygems.all_specs, NewRelic::Helper.rubygems_specs + end + end + + def test_rubygems_specs_works_with_installed_specs + skip 'running a version of Bundler that has not defined installed_specs' unless Bundler.rubygems.respond_to?(:installed_specs) + + assert_equal Bundler.rubygems.installed_specs, NewRelic::Helper.rubygems_specs + end end diff --git a/test/script/run_tests b/test/script/run_tests index 45e8e437a9..3bbcc2f6f9 100755 --- a/test/script/run_tests +++ b/test/script/run_tests @@ -51,7 +51,6 @@ help() { echo " " } - unit_command() { # echo "ENV TEST="$TEST" TESTOPTS="$TESTOPTS"" # echo "bundle exec rake test -q;" @@ -78,6 +77,8 @@ set_test_opts() { # organizes the args for mutiverse and calls the command run_multiverse() { + clean + if [[ -n "$3" ]]; then # echo "running file and name" multiverse_command "$1",file="$2",name="$3"; @@ -104,6 +105,8 @@ run_multiverse_quick() { # organizes the args for env tests and calls the command run_env_tests() { + clean + # this will add "rails" before any number so you can pass in just "61" or "61,70" ENVARGS=$(echo "$1" | sed -E -e 's/(\,)|(\,rails)/,rails/g' | sed '/^rails/!s/^/rails/'); @@ -126,6 +129,8 @@ run_env_tests() { # organizes the args for the unit tests and calls the command run_unit_tests() { + clean + find_test_file "$1" "new_relic" if [[ -n "$2" ]]; then # echo "running file and name" @@ -144,6 +149,15 @@ run_unit_tests() { fi } +clean() { + echo 'Cleaning...' + # xargs over -exec to avoid warnings on already-deleted content + find . -name \*.log | xargs rm -f + find . -name tmp -type d | xargs rm -rf + rm -rf lib/coverage test/minitest/minitest_time_report test/multiverse/lib/multiverse/errors.txt + echo 'Done.' +} + # from a given space/newline delimited string of file paths, return the # shortest path #