diff --git a/.github/actions/test_gem/action.yml b/.github/actions/test_gem/action.yml index 25418da4c..d68836326 100644 --- a/.github/actions/test_gem/action.yml +++ b/.github/actions/test_gem/action.yml @@ -66,7 +66,7 @@ runs: # ...but not for appraisals, sadly. - name: Install Ruby ${{ inputs.ruby }} with dependencies if: "${{ steps.setup.outputs.appraisals == 'false' }}" - uses: ruby/setup-ruby@v1.191.0 + uses: ruby/setup-ruby@v1.202.0 with: ruby-version: "${{ inputs.ruby }}" working-directory: "${{ steps.setup.outputs.gem_dir }}" @@ -77,7 +77,7 @@ runs: # If we're using appraisals, do it all manually. - name: Install Ruby ${{ inputs.ruby }} without dependencies if: "${{ steps.setup.outputs.appraisals == 'true' }}" - uses: ruby/setup-ruby@v1.191.0 + uses: ruby/setup-ruby@v1.202.0 with: ruby-version: "${{ inputs.ruby }}" bundler: "latest" @@ -95,6 +95,7 @@ runs: run: | # 💎 Install dependencies and generate appraisals 💎 bundle install --quiet --jobs=3 --retry=4 + bundle exec appraisal clean bundle exec appraisal generate working-directory: "${{ steps.setup.outputs.gem_dir }}" diff --git a/.github/workflows/ci-contrib.yml b/.github/workflows/ci-contrib.yml index b74aa6f57..1c8593069 100644 --- a/.github/workflows/ci-contrib.yml +++ b/.github/workflows/ci-contrib.yml @@ -58,7 +58,7 @@ jobs: uses: ./.github/actions/test_gem with: gem: "opentelemetry-helpers-${{ matrix.gem }}" - ruby: "jruby-9.4.8.0" + ruby: "jruby-9.4.9.0" propagators: strategy: @@ -103,7 +103,7 @@ jobs: uses: ./.github/actions/test_gem with: gem: "opentelemetry-propagator-${{ matrix.gem }}" - ruby: "jruby-9.4.8.0" + ruby: "jruby-9.4.9.0" resource-detectors: strategy: @@ -148,7 +148,7 @@ jobs: uses: ./.github/actions/test_gem with: gem: "opentelemetry-${{ matrix.gem }}" - ruby: "jruby-9.4.8.0" + ruby: "jruby-9.4.9.0" processors: strategy: @@ -191,4 +191,4 @@ jobs: uses: ./.github/actions/test_gem with: gem: "opentelemetry-processor-${{ matrix.gem }}" - ruby: "jruby-9.4.8.0" + ruby: "jruby-9.4.9.0" diff --git a/.github/workflows/ci-instrumentation-with-services.yml b/.github/workflows/ci-instrumentation-with-services.yml index 4eb5a1215..74ba690d2 100644 --- a/.github/workflows/ci-instrumentation-with-services.yml +++ b/.github/workflows/ci-instrumentation-with-services.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/test_gem with: gem: "opentelemetry-instrumentation-${{ matrix.gem }}" - ruby: "jruby-9.4.8.0" + ruby: "jruby-9.4.9.0" services: memcached: image: memcached:alpine diff --git a/.github/workflows/ci-instrumentation.yml b/.github/workflows/ci-instrumentation.yml index e5b044764..5413b555f 100644 --- a/.github/workflows/ci-instrumentation.yml +++ b/.github/workflows/ci-instrumentation.yml @@ -111,4 +111,4 @@ jobs: uses: ./.github/actions/test_gem with: gem: "opentelemetry-instrumentation-${{ matrix.gem }}" - ruby: "jruby-9.4.8.0" + ruby: "jruby-9.4.9.0" diff --git a/.github/workflows/ci-markdownlint.yml b/.github/workflows/ci-markdownlint.yml index 646484a9b..037b2fa9e 100644 --- a/.github/workflows/ci-markdownlint.yml +++ b/.github/workflows/ci-markdownlint.yml @@ -11,7 +11,7 @@ jobs: # equivalent cli: markdownlint-cli2 "**/*.md" "#**/CHANGELOG.md" --config .markdownlint.json - name: "Markdown Lint Check" - uses: DavidAnson/markdownlint-cli2-action@v17 + uses: DavidAnson/markdownlint-cli2-action@v18 with: fix: false globs: | diff --git a/.github/workflows/installation-tests.yml b/.github/workflows/installation-tests.yml index e71acac29..3135ab25e 100644 --- a/.github/workflows/installation-tests.yml +++ b/.github/workflows/installation-tests.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/checkout@v4 # ATTENTION: Dependabot does not know how to update shared actions file. # If you see it update setup-ruby here also update it as part of actions/test_gem/action.yml - - uses: ruby/setup-ruby@v1.191.0 + - uses: ruby/setup-ruby@v1.202.0 with: ruby-version: ${{ matrix.ruby-version }} - name: "Install Latest Gem Versions on ${{ matrix.ruby-version }}" diff --git a/.github/workflows/release-hook-on-closed.yml b/.github/workflows/release-hook-on-closed.yml index ef5cb741e..e75031e80 100644 --- a/.github/workflows/release-hook-on-closed.yml +++ b/.github/workflows/release-hook-on-closed.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Install Ruby ${{ env.ruby_version }} - uses: ruby/setup-ruby@v1.191.0 + uses: ruby/setup-ruby@v1.202.0 with: ruby-version: ${{ env.ruby_version }} - name: Checkout repo diff --git a/.github/workflows/release-hook-on-push.yml b/.github/workflows/release-hook-on-push.yml index bbe48deb2..956938e3e 100644 --- a/.github/workflows/release-hook-on-push.yml +++ b/.github/workflows/release-hook-on-push.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Install Ruby ${{ env.ruby_version }} - uses: ruby/setup-ruby@v1.191.0 + uses: ruby/setup-ruby@v1.202.0 with: ruby-version: ${{ env.ruby_version }} - name: Checkout repo diff --git a/.github/workflows/release-perform.yml b/.github/workflows/release-perform.yml index c4b13ca12..dd1a72511 100644 --- a/.github/workflows/release-perform.yml +++ b/.github/workflows/release-perform.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Install Ruby ${{ env.ruby_version }} - uses: ruby/setup-ruby@v1.191.0 + uses: ruby/setup-ruby@v1.202.0 with: ruby-version: ${{ env.ruby_version }} - name: Checkout repo diff --git a/.github/workflows/release-please.yaml b/.github/workflows/release-please.yaml index c8cfb286f..b42ab8153 100644 --- a/.github/workflows/release-please.yaml +++ b/.github/workflows/release-please.yaml @@ -50,7 +50,7 @@ jobs: chmod 0600 $HOME/.gem/credentials printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials - - uses: ruby/setup-ruby@v1.191.0 + - uses: ruby/setup-ruby@v1.202.0 with: ruby-version: "3.0" bundler: latest diff --git a/.github/workflows/release-request-weekly.yml b/.github/workflows/release-request-weekly.yml index 6865df226..d230a0279 100644 --- a/.github/workflows/release-request-weekly.yml +++ b/.github/workflows/release-request-weekly.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Install Ruby ${{ env.ruby_version }} - uses: ruby/setup-ruby@v1.191.0 + uses: ruby/setup-ruby@v1.202.0 with: ruby-version: ${{ env.ruby_version }} - name: Checkout repo diff --git a/.github/workflows/release-request.yml b/.github/workflows/release-request.yml index d2b0c3ea5..e5520216a 100644 --- a/.github/workflows/release-request.yml +++ b/.github/workflows/release-request.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Install Ruby ${{ env.ruby_version }} - uses: ruby/setup-ruby@v1.191.0 + uses: ruby/setup-ruby@v1.202.0 with: ruby-version: ${{ env.ruby_version }} - name: Checkout repo diff --git a/.github/workflows/release-retry.yml b/.github/workflows/release-retry.yml index 626146815..fd1e81b46 100644 --- a/.github/workflows/release-retry.yml +++ b/.github/workflows/release-retry.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Install Ruby ${{ env.ruby_version }} - uses: ruby/setup-ruby@v1.191.0 + uses: ruby/setup-ruby@v1.202.0 with: ruby-version: ${{ env.ruby_version }} - name: Checkout repo diff --git a/.gitignore b/.gitignore index a14376cfb..616fb0f93 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ # Appraisals instrumentation/**/gemfiles +instrumentation/**/tmp/**/* # Sqlite file for tests instrumentation/active_record/db @@ -26,3 +27,4 @@ instrumentation/active_record/db .ruby-version tags +!**/*/.gitkeep diff --git a/.instrumentation_generator/templates/gemspec.tt b/.instrumentation_generator/templates/gemspec.tt index fb51740b9..fdc83c9e2 100644 --- a/.instrumentation_generator/templates/gemspec.tt +++ b/.instrumentation_generator/templates/gemspec.tt @@ -37,7 +37,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'rubocop', '~> 1.66.0' spec.add_development_dependency 'rubocop-performance', '~> 1.19.1' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.7.6' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b72270bee..f514eef2c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,53 +1,54 @@ { "helpers/mysql": "0.1.1", - "helpers/sql_obfuscation": "0.1.1", - "instrumentation/base": "0.22.4", - "instrumentation/graphql": "0.28.2", + "helpers/sql-obfuscation": "0.2.0", + "instrumentation/action_mailer": "0.2.0", + "instrumentation/action_pack": "0.10.0", + "instrumentation/action_view": "0.7.3", + "instrumentation/active_job": "0.7.8", + "instrumentation/active_model_serializers": "0.20.2", + "instrumentation/active_record": "0.8.1", + "instrumentation/active_support": "0.6.0", + "instrumentation/all": "0.69.0", + "instrumentation/aws_lambda": "0.1.1", + "instrumentation/aws_sdk": "0.7.0", + "instrumentation/base": "0.22.6", + "instrumentation/bunny": "0.21.4", + "instrumentation/concurrent_ruby": "0.21.4", + "instrumentation/dalli": "0.25.4", + "instrumentation/delayed_job": "0.22.4", + "instrumentation/ethon": "0.21.8", + "instrumentation/excon": "0.22.4", + "instrumentation/faraday": "0.24.6", + "instrumentation/grape": "0.2.0", + "instrumentation/graphql": "0.28.4", "instrumentation/gruf": "0.2.1", - "instrumentation/racecar": "0.3.2", - "instrumentation/rake": "0.2.2", - "instrumentation/rdkafka": "0.4.6", - "instrumentation/trilogy": "0.59.3", - "instrumentation/active_support": "0.5.1", - "instrumentation/action_mailer": "0.1.0", - "instrumentation/action_view": "0.7.0", - "instrumentation/action_pack": "0.9.0", - "instrumentation/active_job": "0.7.1", - "instrumentation/resque": "0.5.2", - "instrumentation/bunny": "0.21.3", - "instrumentation/active_record": "0.7.2", - "instrumentation/aws_sdk": "0.5.2", - "instrumentation/aws_lambda": "0.1.0", - "instrumentation/lmdb": "0.22.2", - "instrumentation/http": "0.23.3", - "instrumentation/http_client": "0.22.6", + "instrumentation/http": "0.23.4", + "instrumentation/http_client": "0.22.7", "instrumentation/httpx": "0.1.2", "instrumentation/koala": "0.20.5", - "instrumentation/active_model_serializers": "0.20.1", - "instrumentation/concurrent_ruby": "0.21.3", - "instrumentation/dalli": "0.25.3", - "instrumentation/delayed_job": "0.22.2", - "instrumentation/ethon": "0.21.7", - "instrumentation/excon": "0.22.3", - "instrumentation/faraday": "0.24.4", - "instrumentation/mongo": "0.22.3", - "instrumentation/mysql2": "0.27.1", - "instrumentation/net_http": "0.22.6", - "instrumentation/pg": "0.27.3", - "instrumentation/que": "0.8.1", - "instrumentation/rack": "0.24.5", - "instrumentation/rails": "0.30.2", - "instrumentation/grape": "0.1.8", - "instrumentation/redis": "0.25.6", - "instrumentation/restclient": "0.22.6", + "instrumentation/lmdb": "0.22.3", + "instrumentation/mongo": "0.22.4", + "instrumentation/mysql2": "0.28.0", + "instrumentation/net_http": "0.22.7", + "instrumentation/pg": "0.29.0", + "instrumentation/que": "0.8.4", + "instrumentation/racecar": "0.3.4", + "instrumentation/rack": "0.25.0", + "instrumentation/rails": "0.33.0", + "instrumentation/rake": "0.2.2", + "instrumentation/rdkafka": "0.4.8", + "instrumentation/redis": "0.25.7", + "instrumentation/resque": "0.5.2", + "instrumentation/restclient": "0.22.7", "instrumentation/rspec": "0.3.3", - "instrumentation/ruby_kafka": "0.21.1", - "instrumentation/sidekiq": "0.25.5", - "instrumentation/sinatra": "0.23.5", - "instrumentation/all": "0.56.0", + "instrumentation/ruby_kafka": "0.21.3", + "instrumentation/sidekiq": "0.25.7", + "instrumentation/sinatra": "0.24.1", + "instrumentation/trilogy": "0.60.0", "processor/baggage": "0.2.0", - "propagator/ottrace": "0.21.2", - "propagator/xray": "0.22.1", + "propagator/ottrace": "0.21.3", + "propagator/vitess": "0.1.0", + "propagator/xray": "0.22.2", "resources/azure": "0.1.0", "resources/container": "0.1.1", "resources/google_cloud_platform": "0.1.0" diff --git a/CODEOWNERS b/CODEOWNERS index 732650bfb..96e9c51be 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -16,7 +16,7 @@ resources/container/ @scbjans @open-telemetry/ruby-contrib-maintainers @open-telemetry/ruby-contrib-approvers @fbogsany @mwear @robertlaurin @dazuma @ericmustin @arielvalentin @ahayworth @plantfansam @robbkidd @simi @kaylareopelle @xuan-cao-swi -instrumentation/aws_sdk/ @NathanielRN @open-telemetry/ruby-contrib-maintainers @open-telemetry/ruby-contrib-approvers @fbogsany @mwear @robertlaurin @dazuma @ericmustin @arielvalentin @ahayworth @plantfansam @robbkidd @simi @kaylareopelle @xuan-cao-swi +instrumentation/aws_sdk/ @jterapin @alextwoods @NathanielRN @open-telemetry/ruby-contrib-maintainers @open-telemetry/ruby-contrib-approvers @fbogsany @mwear @robertlaurin @dazuma @ericmustin @arielvalentin @ahayworth @plantfansam @robbkidd @simi @kaylareopelle @xuan-cao-swi instrumentation/grape/ @muripic @open-telemetry/ruby-contrib-maintainers @open-telemetry/ruby-contrib-approvers @fbogsany @mwear @robertlaurin @dazuma @ericmustin @arielvalentin @ahayworth @plantfansam @robbkidd @simi @kaylareopelle @xuan-cao-swi diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 58466f717..dc7c281c7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -80,6 +80,12 @@ For example, to test `opentelemetry-instrumentation-action_pack` you would: 2. Install the bundle with `bundle install` 3. Run the tests with `bundle exec rake` +Note: Some test suites make use of [Appraisal](https://github.com/thoughtbot/appraisal), a library for testing against different versions of dependencies. To run tests in suites that use Appraisal: + + 1. Change directory to the instrumentation you'd like to test, ex: `instrumentation/action_pack` + 2. Install the bundle with `bundle exec appraisal install` + 3. Run the tests with `bundle exec appraisal rake test` + ### Docker setup We use Docker Compose to configure and build services used in development and diff --git a/Gemfile b/Gemfile index be94fd2e5..b68ccbbeb 100644 --- a/Gemfile +++ b/Gemfile @@ -7,5 +7,5 @@ source 'https://rubygems.org' gem 'rake', '~> 13.0' -gem 'rubocop', '~> 1.66.0' -gem 'rubocop-performance', '~> 1.21.0' +gem 'rubocop', '~> 1.68.0' +gem 'rubocop-performance', '~> 1.23.0' diff --git a/bin/sync-release-please b/bin/sync-release-please new file mode 100755 index 000000000..8e669df50 --- /dev/null +++ b/bin/sync-release-please @@ -0,0 +1,36 @@ +#!/usr/bin/env ruby + +require 'json' + +# Function to extract VERSION constant from a file +def extract_version(file_path) + version = nil + File.open(file_path, 'r') do |file| + file.each_line do |line| + if line =~ /VERSION\s*=\s*['"]([^'"]+)['"]/ + version = $1 + break + end + end + end + version +end + +# Hash to store the directory names and their versions +versions = {} + +# Find all version.rb files +Dir.glob('**/version.rb').each do |file_path| + # Extract the top 2 level directories + top_dirs = file_path.split('/')[0..1].join('/') + # Extract the version + version = extract_version(file_path) + # Store in the hash + versions[top_dirs] = version if version +end + +# Write the hash to a JSON file +File.open('.release-please-manifest.json', 'w') do |file| + file.write(JSON.pretty_generate(versions)) + file.write("\n") +end diff --git a/docker-compose.yml b/docker-compose.yml index af815eabe..a2fb5633f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: "3.5" - x-shared-config: base: &base command: /bin/bash @@ -217,7 +215,7 @@ services: image: memcached:alpine command: memcached -m 64 ports: - - "11211:11211" + - "11211:11211" zookeeper: image: confluentinc/cp-zookeeper:latest @@ -248,8 +246,8 @@ services: - "16686:16686" otelcol: - image: otel/opentelemetry-collector:0.54.0 - command: [ "--config=/etc/otelcol-config.yml" ] + image: otel/opentelemetry-collector:0.109.0 + command: ["--config=/etc/otelcol-config.yml"] volumes: - ./otelcol-config.yml:/etc/otelcol-config.yml ports: diff --git a/helpers/mysql/opentelemetry-helpers-mysql.gemspec b/helpers/mysql/opentelemetry-helpers-mysql.gemspec index 5cebc24d6..ff93af073 100644 --- a/helpers/mysql/opentelemetry-helpers-mysql.gemspec +++ b/helpers/mysql/opentelemetry-helpers-mysql.gemspec @@ -32,8 +32,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.21.0' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.22.0' spec.add_development_dependency 'yard', '~> 0.9' spec.add_development_dependency 'yard-doctest', '~> 0.1.6' diff --git a/helpers/sql-obfuscation/opentelemetry-helpers-sql-obfuscation.gemspec b/helpers/sql-obfuscation/opentelemetry-helpers-sql-obfuscation.gemspec index 1ce168184..89ea0b8b1 100644 --- a/helpers/sql-obfuscation/opentelemetry-helpers-sql-obfuscation.gemspec +++ b/helpers/sql-obfuscation/opentelemetry-helpers-sql-obfuscation.gemspec @@ -31,8 +31,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.21.0' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'yard', '~> 0.9' spec.add_development_dependency 'yard-doctest', '~> 0.1.6' diff --git a/instrumentation/action_mailer/Appraisals b/instrumentation/action_mailer/Appraisals index e6c48d017..bd32cbe25 100644 --- a/instrumentation/action_mailer/Appraisals +++ b/instrumentation/action_mailer/Appraisals @@ -4,20 +4,20 @@ # # SPDX-License-Identifier: Apache-2.0 -appraise 'rails-6.1' do - gem 'rails', '~> 6.1.0' -end - -appraise 'rails-7.0' do - gem 'rails', '~> 7.0.0' -end - -appraise 'rails-7.1' do - gem 'rails', '~> 7.1.0' +%w[6.1.0 7.0.0 7.1.0].each do |version| + appraise "action_mailer-#{version}" do + gem 'rails', "~> #{version}" + end end if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.1.0') - appraise 'rails-7.2' do - gem 'rails', '~> 7.2.0' + %w[7.2.0].each do |version| + appraise "action_mailer-#{version}" do + gem 'rails', "~> #{version}" + end + end + + appraise 'action_mailer-latest' do + gem 'rails' end end diff --git a/instrumentation/action_mailer/CHANGELOG.md b/instrumentation/action_mailer/CHANGELOG.md index 8f0fc70b8..00f95806c 100644 --- a/instrumentation/action_mailer/CHANGELOG.md +++ b/instrumentation/action_mailer/CHANGELOG.md @@ -1,5 +1,9 @@ # Release History: opentelemetry-instrumentation-action_mailer +### v0.2.0 / 2024-10-22 + +* ADDED: Subscribe to process.action_mailer notifications + ### v0.1.0 / 2024-05-13 Initial release. diff --git a/instrumentation/action_mailer/README.md b/instrumentation/action_mailer/README.md index 63c13d810..3d429e7d2 100644 --- a/instrumentation/action_mailer/README.md +++ b/instrumentation/action_mailer/README.md @@ -21,7 +21,7 @@ To use the instrumentation, call `use` with the name of the instrumentation: ```ruby OpenTelemetry::SDK.configure do |c| - # Use only the ActionMailer instrumentation + # Use only the ActionMailer instrumentation c.use 'OpenTelemetry::Instrumentation::ActionMailer' # Use the ActionMailer instrumentation along with the rest of the Rails-related instrumentation c.use 'OpenTelemetry::Instrumentation::Rails' @@ -44,8 +44,8 @@ See the table below for details of what [Rails Framework Hook Events](https://gu | Event Name | Creates Span? | Notes | | - | - | - | -| `deliver.action_mailer` | :white_check_mark: | Creates an span with kind `internal` and email content and status| -| `process.action_mailer` | :x: | Lack of useful info so ignored | +| `deliver.action_mailer` | :white_check_mark: | Creates a span with kind `internal` and email content and status | +| `process.action_mailer` | :white_check_mark: | Creates a span with kind `internal` that will include email rendering spans | ### Options @@ -67,9 +67,9 @@ end ## Semantic Conventions -Internal spans are named using the name of the `ActiveSupport` event that was provided (e.g. `action_mailer deliver`). +Internal spans are named using the name of the `ActiveSupport` event that was provided (e.g. `deliver.action_mailer`). -The following attributes from the notification payload for the `deliver.action_mailer` event are attached to `action_mailer deliver` spans: +### Attributes attached to the `deliver.action_mailer` event payload | Attribute Name | Type | Notes | | - | - | - | @@ -79,7 +79,15 @@ The following attributes from the notification payload for the `deliver.action_m | `email.to.address` | Array | Receiver for mail (omit by default, include when `email_address` set to `:include`) | | `email.from.address` | Array | Sender for mail (omit by default, include when `email_address` set to `:include`) | | `email.cc.address` | Array | mail CC (omit by default, include when `email_address` set to `:include`) | -| `email.bcc.address` | Array | mail BCC (omit by default, include when `email_address` set to `:include`) | +| `email.bcc.address` | Array | mail BCC (omit by default, include when `email_address` set to `:include`) | + +### Attributes attached to the `process.action_mailer` event payload + +| Attribute Name | Type | Notes | +| - | - | - | +| `mailer` | String | Mailer class that is used to render the mail | +| `action` | String | Method from the mailer class called to render the mail | +| `args` | Array | Arguments passed to the method to render the email | ## Examples diff --git a/instrumentation/action_mailer/Rakefile b/instrumentation/action_mailer/Rakefile index 1a64ba842..4b0e9b5a8 100644 --- a/instrumentation/action_mailer/Rakefile +++ b/instrumentation/action_mailer/Rakefile @@ -15,6 +15,7 @@ Rake::TestTask.new :test do |t| t.libs << 'test' t.libs << 'lib' t.test_files = FileList['test/**/*_test.rb'] + t.warning = false end YARD::Rake::YardocTask.new do |t| diff --git a/instrumentation/action_mailer/lib/opentelemetry/instrumentation/action_mailer/instrumentation.rb b/instrumentation/action_mailer/lib/opentelemetry/instrumentation/action_mailer/instrumentation.rb index 2b33478aa..3ba3cb714 100644 --- a/instrumentation/action_mailer/lib/opentelemetry/instrumentation/action_mailer/instrumentation.rb +++ b/instrumentation/action_mailer/lib/opentelemetry/instrumentation/action_mailer/instrumentation.rb @@ -7,7 +7,53 @@ module OpenTelemetry module Instrumentation module ActionMailer - # The Instrumentation class contains logic to detect and install the ActionMailer instrumentation + # The {OpenTelemetry::Instrumentation::ActionMailer::Instrumentation} class contains logic to detect and install the ActionMailer instrumentation + # + # Installation and configuration of this instrumentation is done within the + # {https://www.rubydoc.info/gems/opentelemetry-sdk/OpenTelemetry/SDK#configure-instance_method OpenTelemetry::SDK#configure} + # block, calling {https://www.rubydoc.info/gems/opentelemetry-sdk/OpenTelemetry%2FSDK%2FConfigurator:use use()} + # or {https://www.rubydoc.info/gems/opentelemetry-sdk/OpenTelemetry%2FSDK%2FConfigurator:use_all use_all()}. + # + # ## Configuration keys and options + # + # ### `:disallowed_notification_payload_keys` + # + # Specifies an array of keys that should be excluded from the `deliver.action_mailer` notification payload as span attributes. + # + # ### `:disallowed_process_payload_keys` + # + # Specifies an array of keys that should be excluded from the `process.action_mailer` notification payload as span attributes. + # + # ### `:notification_payload_transform` + # + # - `proc` **default** `nil` + # + # Specifies custom proc used to extract span attributes form the `deliver.action_mailer` notification payload. Use this to rename keys, extract nested values, or perform any other custom logic. + # + # ### `:process_payload_transform` + # + # - `proc` **default** `nil` + # + # Specifies custom proc used to extract span attributes form the `process.action_mailer` notification payload. Use this to rename keys, extract nested values, or perform any other custom logic. + # + # ### `:email_address` + # + # - `symbol` **default** `:omit` + # + # Specifies whether to include email addresses in the notification payload. Valid values are `:omit` and `:include`. + # + # @example An explicit default configuration + # OpenTelemetry::SDK.configure do |c| + # c.use_all({ + # 'OpenTelemetry::Instrumentation::ActionMailer' => { + # disallowed_notification_payload_keys: [], + # disallowed_process_payload_keys: [], + # notification_payload_transform: nil, + # process_payload_transform: nil, + # email_address: :omit, + # }, + # }) + # end class Instrumentation < OpenTelemetry::Instrumentation::Base MINIMUM_VERSION = Gem::Version.new('6.1.0') EMAIL_ATTRIBUTE = %w[email.to.address email.from.address email.cc.address email.bcc.address].freeze @@ -27,7 +73,9 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base end option :disallowed_notification_payload_keys, default: [], validate: :array + option :disallowed_process_payload_keys, default: [], validate: :array option :notification_payload_transform, default: nil, validate: :callable + option :process_payload_transform, default: nil, validate: :callable option :email_address, default: :omit, validate: %I[omit include] private diff --git a/instrumentation/action_mailer/lib/opentelemetry/instrumentation/action_mailer/railtie.rb b/instrumentation/action_mailer/lib/opentelemetry/instrumentation/action_mailer/railtie.rb index 0b036d0e9..724e2a162 100644 --- a/instrumentation/action_mailer/lib/opentelemetry/instrumentation/action_mailer/railtie.rb +++ b/instrumentation/action_mailer/lib/opentelemetry/instrumentation/action_mailer/railtie.rb @@ -7,24 +7,39 @@ module OpenTelemetry module Instrumentation module ActionMailer - SUBSCRIPTIONS = %w[ - deliver.action_mailer - ].freeze + DELIVER_SUBSCRIPTION = 'deliver.action_mailer' + PROCESS_SUBSCRIPTION = 'process.action_mailer' # This Railtie sets up subscriptions to relevant ActionMailer notifications class Railtie < ::Rails::Railtie config.after_initialize do ::OpenTelemetry::Instrumentation::ActiveSupport::Instrumentation.instance.install({}) + subscribe_to_deliver + subscribe_to_process + end - SUBSCRIPTIONS.each do |subscription_name| - config = ActionMailer::Instrumentation.instance.config + class << self + def subscribe_to_deliver ::OpenTelemetry::Instrumentation::ActiveSupport.subscribe( ActionMailer::Instrumentation.instance.tracer, - subscription_name, + DELIVER_SUBSCRIPTION, config[:notification_payload_transform], config[:disallowed_notification_payload_keys] ) end + + def subscribe_to_process + ::OpenTelemetry::Instrumentation::ActiveSupport.subscribe( + ActionMailer::Instrumentation.instance.tracer, + PROCESS_SUBSCRIPTION, + config[:process_payload_transform], + config[:disallowed_process_payload_keys] + ) + end + + def config + ActionMailer::Instrumentation.instance.config + end end end end diff --git a/instrumentation/action_mailer/lib/opentelemetry/instrumentation/action_mailer/version.rb b/instrumentation/action_mailer/lib/opentelemetry/instrumentation/action_mailer/version.rb index 20756b5f2..ff958a4cc 100644 --- a/instrumentation/action_mailer/lib/opentelemetry/instrumentation/action_mailer/version.rb +++ b/instrumentation/action_mailer/lib/opentelemetry/instrumentation/action_mailer/version.rb @@ -7,7 +7,7 @@ module OpenTelemetry module Instrumentation module ActionMailer - VERSION = '0.1.0' + VERSION = '0.2.0' end end end diff --git a/instrumentation/action_mailer/opentelemetry-instrumentation-action_mailer.gemspec b/instrumentation/action_mailer/opentelemetry-instrumentation-action_mailer.gemspec index 2a00a1534..5d4ee2bcc 100644 --- a/instrumentation/action_mailer/opentelemetry-instrumentation-action_mailer.gemspec +++ b/instrumentation/action_mailer/opentelemetry-instrumentation-action_mailer.gemspec @@ -35,10 +35,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/action_mailer/test/opentelemetry/instrumentation/action_mailer/subscription_test.rb b/instrumentation/action_mailer/test/opentelemetry/instrumentation/action_mailer/subscription_test.rb new file mode 100644 index 000000000..2d22098c6 --- /dev/null +++ b/instrumentation/action_mailer/test/opentelemetry/instrumentation/action_mailer/subscription_test.rb @@ -0,0 +1,142 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'test_helper' +require 'opentelemetry-instrumentation-active_support' + +describe OpenTelemetry::Instrumentation::ActionMailer do + let(:exporter) { EXPORTER } + let(:spans) { exporter.finished_spans } + let(:instrumentation) { OpenTelemetry::Instrumentation::ActionMailer::Instrumentation.instance } + + before do + exporter.reset + end + + describe 'deliver.action_mailer' do + describe 'with default configuration' do + it 'generates a deliver span' do + subscribing_to_deliver do + TestMailer.hello_world.deliver_now + end + + _(spans.length).must_equal(1) + span = spans.find { |s| s.name == 'deliver.action_mailer' } + + _(span).wont_be_nil + + _(span.attributes['email.x_mailer']).must_equal('TestMailer') + _(span.attributes['email.subject']).must_equal('Hello world') + _(span.attributes['email.message_id']).wont_be_empty + end + end + + describe 'with custom configuration' do + it 'with email_address: :include' do + with_configuration(email_address: :include, disallowed_notification_payload_keys: []) do + subscribing_to_deliver do + TestMailer.hello_world.deliver_now + end + end + + _(spans.length).must_equal(1) + span = spans.find { |s| s.name == 'deliver.action_mailer' } + + _(span).wont_be_nil + + _(span.attributes['email.x_mailer']).must_equal('TestMailer') + _(span.attributes['email.subject']).must_equal('Hello world') + _(span.attributes['email.message_id']).wont_be_empty + _(span.attributes['email.to.address']).must_equal(['to@example.com']) + _(span.attributes['email.from.address']).must_equal(['from@example.com']) + _(span.attributes['email.cc.address']).must_equal(['cc@example.com']) + _(span.attributes['email.bcc.address']).must_equal(['bcc@example.com']) + end + + it 'with a custom transform proc' do + transform = ->(payload) { payload.transform_keys(&:upcase) } + with_configuration(notification_payload_transform: transform) do + instrumentation.send(:ecs_mail_convention) + subscribing_to_deliver do + TestMailer.hello_world.deliver_now + end + end + + _(spans.length).must_equal(1) + span = spans.find { |s| s.name == 'deliver.action_mailer' } + + _(span).wont_be_nil + + _(span.attributes['EMAIL.X_MAILER']).must_equal('TestMailer') + _(span.attributes['EMAIL.SUBJECT']).must_equal('Hello world') + _(span.attributes['EMAIL.MESSAGE_ID']).wont_be_empty + end + end + end + + describe 'process.action_mailer' do + describe 'with default configuration' do + it 'generates a process span' do + transform = ->(payload) { payload.transform_keys(&:upcase) } + with_configuration(disallowed_process_payload_keys: [:ARGS], process_payload_transform: transform) do + subscribing_to_process do + TestMailer.hello_world('Hola mundo').deliver_now + end + end + + _(spans.length).must_equal(1) + span = spans.find { |s| s.name == 'process.action_mailer' } + + _(span).wont_be_nil + + _(span.attributes['MAILER']).must_equal('TestMailer') + _(span.attributes['ACTION']).must_equal('hello_world') + _(span.attributes['ARGS']).must_be_nil + end + end + + describe 'with custom configuration' do + it 'generates a process span' do + subscribing_to_process do + TestMailer.hello_world('Hola mundo').deliver_now + end + + _(spans.length).must_equal(1) + span = spans.find { |s| s.name == 'process.action_mailer' } + + _(span).wont_be_nil + + _(span.attributes['mailer']).must_equal('TestMailer') + _(span.attributes['action']).must_equal('hello_world') + _(span.attributes['args']).must_equal(['Hola mundo']) + end + end + end + + def with_configuration(values, &block) + original_config = instrumentation.instance_variable_get(:@config) + modified_config = original_config.merge(values) + instrumentation.instance_variable_set(:@config, modified_config) + + yield + + instrumentation.instance_variable_set(:@config, original_config) + end + + def subscribing_to_deliver(&block) + subscription = OpenTelemetry::Instrumentation::ActionMailer::Railtie.subscribe_to_deliver + yield + ensure + ActiveSupport::Notifications.unsubscribe(subscription) + end + + def subscribing_to_process(&block) + subscription = OpenTelemetry::Instrumentation::ActionMailer::Railtie.subscribe_to_process + yield + ensure + ActiveSupport::Notifications.unsubscribe(subscription) + end +end diff --git a/instrumentation/action_mailer/test/test_helper.rb b/instrumentation/action_mailer/test/test_helper.rb index b68d22b82..945016422 100644 --- a/instrumentation/action_mailer/test/test_helper.rb +++ b/instrumentation/action_mailer/test/test_helper.rb @@ -22,3 +22,23 @@ c.use 'OpenTelemetry::Instrumentation::ActionMailer' c.add_span_processor span_processor end + +OpenTelemetry::Instrumentation::ActiveSupport::Instrumentation.instance.install({}) +OpenTelemetry::Instrumentation::ActionMailer::Instrumentation.instance.install({}) + +ActionMailer::Base.delivery_method = :test + +class TestMailer < ActionMailer::Base + FROM = 'from@example.com' + TO = 'to@example.com' + CC = 'cc@example.com' + BCC = 'bcc@example.com' + + def hello_world(message = 'Hello world') + @message = message + mail from: FROM, to: TO, cc: CC, bcc: BCC do |format| + format.html { render inline: '

<%= @message %>

' } + format.text { render inline: '<%= @message %>' } + end + end +end diff --git a/instrumentation/action_pack/Appraisals b/instrumentation/action_pack/Appraisals index e6c48d017..2f466100e 100644 --- a/instrumentation/action_pack/Appraisals +++ b/instrumentation/action_pack/Appraisals @@ -4,20 +4,20 @@ # # SPDX-License-Identifier: Apache-2.0 -appraise 'rails-6.1' do - gem 'rails', '~> 6.1.0' -end - -appraise 'rails-7.0' do - gem 'rails', '~> 7.0.0' -end - -appraise 'rails-7.1' do - gem 'rails', '~> 7.1.0' +%w[6.1.0 7.0.0 7.1.0].each do |version| + appraise "rails-#{version}" do + gem 'rails', "~> #{version}" + end end if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.1.0') - appraise 'rails-7.2' do - gem 'rails', '~> 7.2.0' + %w[7.2.0].each do |version| + appraise "rails-#{version}" do + gem 'rails', "~> #{version}" + end + end + + appraise 'rails-latest' do + gem 'rails' end end diff --git a/instrumentation/action_pack/CHANGELOG.md b/instrumentation/action_pack/CHANGELOG.md index 015a170fd..2532b7580 100644 --- a/instrumentation/action_pack/CHANGELOG.md +++ b/instrumentation/action_pack/CHANGELOG.md @@ -1,5 +1,9 @@ # Release History: opentelemetry-instrumentation-action_pack +### v0.10.0 / 2024-11-19 + +* ADDED: Use Semconv Naming For ActionPack + ### v0.9.0 / 2024-01-09 * BREAKING CHANGE: Use ActiveSupport instead of patches #703 diff --git a/instrumentation/action_pack/README.md b/instrumentation/action_pack/README.md index 4eb0b6c97..c8b84f5ef 100644 --- a/instrumentation/action_pack/README.md +++ b/instrumentation/action_pack/README.md @@ -42,6 +42,25 @@ See the table below for details of what [Rails Framework Hook Events](https://gu | - | - | - | - | | `process_action.action_controller` | :white_check_mark: | :x: | It modifies the existing Rack span | +## Semantic Conventions + +This instrumentation generally uses [HTTP server semantic conventions](https://opentelemetry.io/docs/specs/semconv/http/http-spans/) to update the existing Rack span. + +For Rails 7.1+, the span name is updated to match the HTTP method and route that was matched for the request using [`ActionDispatch::Request#route_uri_pattern`](https://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-route_uri_pattern), e.g.: `GET /users/:id` + +For older versions of Rails the span name is updated to match the HTTP method, controller, and action name that was the target of the request, e.g.: `GET /example/index` + +> ![NOTE]: Users may override the `span_naming` option to default to Legacy Span Naming Behavior that uses the controller's class name and action in Ruby documentation syntax, e.g. `ExampleController#index`. + +This instrumentation does not emit any custom attributes. + +| Attribute Name | Type | Notes | +| - | - | - | +| `code.namespace` | String | `ActionController` class name | +| `code.function` | String | `ActionController` action name e.g. `index`, `show`, `edit`, etc... | +| `http.route` | String | (Rails 7.1+) the route that was matched for the request | +| `http.target` | String | The `request.filtered_path` | + ### Error Handling for Action Controller If an error is triggered by Action Controller (such as a 500 internal server error), Action Pack will typically employ the default `ActionDispatch::PublicExceptions.new(Rails.public_path)` as the `exceptions_app`, as detailed in the [documentation](https://guides.rubyonrails.org/configuring.html#config-exceptions-app). diff --git a/instrumentation/action_pack/lib/opentelemetry/instrumentation/action_pack/handlers/action_controller.rb b/instrumentation/action_pack/lib/opentelemetry/instrumentation/action_pack/handlers/action_controller.rb index d7b79b64d..843af4633 100644 --- a/instrumentation/action_pack/lib/opentelemetry/instrumentation/action_pack/handlers/action_controller.rb +++ b/instrumentation/action_pack/lib/opentelemetry/instrumentation/action_pack/handlers/action_controller.rb @@ -13,6 +13,7 @@ class ActionController # @param config [Hash] of instrumentation options def initialize(config) @config = config + @span_naming = config.fetch(:span_naming) end # Invoked by ActiveSupport::Notifications at the start of the instrumentation block @@ -22,20 +23,11 @@ def initialize(config) # @param payload [Hash] the payload passed as a method argument # @return [Hash] the payload passed as a method argument def start(_name, _id, payload) - rack_span = OpenTelemetry::Instrumentation::Rack.current_span + span_name, attributes = to_span_name_and_attributes(payload) - request = payload[:request] - - rack_span.name = "#{payload[:controller]}##{payload[:action]}" unless request.env['action_dispatch.exception'] - - attributes_to_append = { - OpenTelemetry::SemanticConventions::Trace::CODE_NAMESPACE => String(payload[:controller]), - OpenTelemetry::SemanticConventions::Trace::CODE_FUNCTION => String(payload[:action]) - } - - attributes_to_append[OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET] = request.filtered_path if request.filtered_path != request.fullpath - - rack_span.add_attributes(attributes_to_append) + span = OpenTelemetry::Instrumentation::Rack.current_span + span.name = span_name + span.add_attributes(attributes) rescue StandardError => e OpenTelemetry.handle_error(exception: e) end @@ -47,11 +39,37 @@ def start(_name, _id, payload) # @param payload [Hash] the payload passed as a method argument # @return [Hash] the payload passed as a method argument def finish(_name, _id, payload) - rack_span = OpenTelemetry::Instrumentation::Rack.current_span - rack_span.record_exception(payload[:exception_object]) if payload[:exception_object] + span = OpenTelemetry::Instrumentation::Rack.current_span + span.record_exception(payload[:exception_object]) if payload[:exception_object] rescue StandardError => e OpenTelemetry.handle_error(exception: e) end + + private + + # Extracts the span name and attributes from the payload + # + # @param payload [Hash] the payload passed from ActiveSupport::Notifications + # @return [Array] the span name and attributes + def to_span_name_and_attributes(payload) + request = payload[:request] + http_route = request.route_uri_pattern if request.respond_to?(:route_uri_pattern) + + attributes = { + OpenTelemetry::SemanticConventions::Trace::CODE_NAMESPACE => String(payload[:controller]), + OpenTelemetry::SemanticConventions::Trace::CODE_FUNCTION => String(payload[:action]) + } + attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_ROUTE] = http_route if http_route + attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET] = request.filtered_path if request.filtered_path != request.fullpath + + if @span_naming == :semconv + return ["#{request.method} #{http_route.gsub('(.:format)', '')}", attributes] if http_route + + return ["#{request.method} /#{payload.dig(:params, :controller)}/#{payload.dig(:params, :action)}", attributes] + end + + ["#{payload[:controller]}##{payload[:action]}", attributes] + end end end end diff --git a/instrumentation/action_pack/lib/opentelemetry/instrumentation/action_pack/instrumentation.rb b/instrumentation/action_pack/lib/opentelemetry/instrumentation/action_pack/instrumentation.rb index cad8a14a4..b81362f5a 100644 --- a/instrumentation/action_pack/lib/opentelemetry/instrumentation/action_pack/instrumentation.rb +++ b/instrumentation/action_pack/lib/opentelemetry/instrumentation/action_pack/instrumentation.rb @@ -7,7 +7,31 @@ module OpenTelemetry module Instrumentation module ActionPack - # The Instrumentation class contains logic to detect and install the ActionPack instrumentation + # The {OpenTelemetry::Instrumentation::ActionPack::Instrumentation} class contains logic to detect and install the ActionPack instrumentation + # + # Installation and configuration of this instrumentation is done within the + # {https://www.rubydoc.info/gems/opentelemetry-sdk/OpenTelemetry/SDK#configure-instance_method OpenTelemetry::SDK#configure} + # block, calling {https://www.rubydoc.info/gems/opentelemetry-sdk/OpenTelemetry%2FSDK%2FConfigurator:use use()} + # or {https://www.rubydoc.info/gems/opentelemetry-sdk/OpenTelemetry%2FSDK%2FConfigurator:use_all use_all()}. + # + # ## Configuration keys and options + # + # ### `:span_naming` + # + # Specifies how the span names are set. Can be one of: + # + # - `:semconv` **(default)** - The span name will use HTTP semantic conventions '{method http.route}', for example `GET /users/:id` + # - `:class` - The span name will appear as '#', + # for example `UsersController#show`. + # + # @example An explicit default configuration + # OpenTelemetry::SDK.configure do |c| + # c.use_all({ + # 'OpenTelemetry::Instrumentation::ActionPack' => { + # span_naming: :class + # }, + # }) + # end class Instrumentation < OpenTelemetry::Instrumentation::Base MINIMUM_VERSION = Gem::Version.new('6.1.0') @@ -17,6 +41,8 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base patch end + option :span_naming, default: :semconv, validate: %i[semconv class] + present do defined?(::ActionController) end diff --git a/instrumentation/action_pack/lib/opentelemetry/instrumentation/action_pack/version.rb b/instrumentation/action_pack/lib/opentelemetry/instrumentation/action_pack/version.rb index b746ac414..034f29d38 100644 --- a/instrumentation/action_pack/lib/opentelemetry/instrumentation/action_pack/version.rb +++ b/instrumentation/action_pack/lib/opentelemetry/instrumentation/action_pack/version.rb @@ -7,7 +7,7 @@ module OpenTelemetry module Instrumentation module ActionPack - VERSION = '0.9.0' + VERSION = '0.10.0' end end end diff --git a/instrumentation/action_pack/opentelemetry-instrumentation-action_pack.gemspec b/instrumentation/action_pack/opentelemetry-instrumentation-action_pack.gemspec index 27745ffac..f0028d35b 100644 --- a/instrumentation/action_pack/opentelemetry-instrumentation-action_pack.gemspec +++ b/instrumentation/action_pack/opentelemetry-instrumentation-action_pack.gemspec @@ -34,12 +34,11 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' - spec.add_development_dependency 'rails', '>= 6.1' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/action_pack/test/opentelemetry/instrumentation/action_pack/handlers/action_controller_test.rb b/instrumentation/action_pack/test/opentelemetry/instrumentation/action_pack/handlers/action_controller_test.rb index 0da17ab15..bec7648c5 100644 --- a/instrumentation/action_pack/test/opentelemetry/instrumentation/action_pack/handlers/action_controller_test.rb +++ b/instrumentation/action_pack/test/opentelemetry/instrumentation/action_pack/handlers/action_controller_test.rb @@ -16,7 +16,7 @@ let(:exporter) { EXPORTER } let(:spans) { exporter.finished_spans } let(:span) { exporter.finished_spans.last } - let(:rails_app) { DEFAULT_RAILS_APP } + let(:rails_app) { AppConfig.initialize_app } let(:config) { {} } # Clear captured spans @@ -36,7 +36,6 @@ _(last_response.body).must_equal 'actually ok' _(last_response.ok?).must_equal true - _(span.name).must_equal 'ExampleController#ok' _(span.kind).must_equal :server _(span.status.ok?).must_equal true @@ -65,7 +64,7 @@ _(last_response.body).must_equal 'created new item' _(last_response.ok?).must_equal true - _(span.name).must_equal 'ExampleController#new_item' + _(span.name).must_match(/^GET/) _(span.kind).must_equal :server _(span.status.ok?).must_equal true @@ -82,24 +81,25 @@ _(span.attributes['code.function']).must_equal 'new_item' end - it 'sets the span name when the controller raises an exception' do - get 'internal_server_error' + describe 'when encountering server side errors' do + it 'sets semconv attributes' do + get 'internal_server_error' - _(span.name).must_equal 'ExampleController#internal_server_error' - _(span.kind).must_equal :server - _(span.status.ok?).must_equal false + _(span.kind).must_equal :server + _(span.status.ok?).must_equal false - _(span.instrumentation_library.name).must_equal 'OpenTelemetry::Instrumentation::Rack' - _(span.instrumentation_library.version).must_equal OpenTelemetry::Instrumentation::Rack::VERSION + _(span.instrumentation_library.name).must_equal 'OpenTelemetry::Instrumentation::Rack' + _(span.instrumentation_library.version).must_equal OpenTelemetry::Instrumentation::Rack::VERSION - _(span.attributes['http.method']).must_equal 'GET' - _(span.attributes['http.host']).must_equal 'example.org' - _(span.attributes['http.scheme']).must_equal 'http' - _(span.attributes['http.target']).must_equal '/internal_server_error' - _(span.attributes['http.status_code']).must_equal 500 - _(span.attributes['http.user_agent']).must_be_nil - _(span.attributes['code.namespace']).must_equal 'ExampleController' - _(span.attributes['code.function']).must_equal 'internal_server_error' + _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.host']).must_equal 'example.org' + _(span.attributes['http.scheme']).must_equal 'http' + _(span.attributes['http.target']).must_equal '/internal_server_error' + _(span.attributes['http.status_code']).must_equal 500 + _(span.attributes['http.user_agent']).must_be_nil + _(span.attributes['code.namespace']).must_equal 'ExampleController' + _(span.attributes['code.function']).must_equal 'internal_server_error' + end end it 'does not set the span name when an exception is raised in middleware' do @@ -139,13 +139,79 @@ _(span.attributes['code.function']).must_be_nil end + describe 'span naming' do + describe 'when using the default span_naming configuration' do + describe 'successful requests' do + describe 'Rails Version < 7.1' do + it 'uses the http method controller and action name' do + skip "Rails #{Rails.gem_version} uses ActionDispatch::Request#route_uri_pattern" if Rails.gem_version >= Gem::Version.new('7.1') + get '/ok' + + _(span.name).must_equal 'GET /example/ok' + end + + it 'excludes route params' do + skip "Rails #{Rails.gem_version} uses ActionDispatch::Request#route_uri_pattern" if Rails.gem_version >= Gem::Version.new('7.1') + get '/items/1234' + + _(span.name).must_equal 'GET /example/item' + end + end + + describe 'Rails Version >= 7.1' do + it 'uses the Rails route' do + skip "Rails #{Rails.gem_version} does not define ActionDispatch::Request#route_uri_pattern" if Rails.gem_version < Gem::Version.new('7.1') + get '/ok' + + _(span.name).must_equal 'GET /ok' + end + + it 'includes route params' do + skip "Rails #{Rails.gem_version} does not define ActionDispatch::Request#route_uri_pattern" if Rails.gem_version < Gem::Version.new('7.1') + get '/items/1234' + + _(span.name).must_equal 'GET /items/:id' + end + end + end + + describe 'server errors' do + it 'uses the http method controller and action name for server side errors' do + skip "Rails #{Rails.gem_version} uses ActionDispatch::Request#route_uri_pattern" if Rails.gem_version >= Gem::Version.new('7.1') + + get 'internal_server_error' + + _(span.name).must_equal 'GET /example/internal_server_error' + end + + it 'uses the Rails route for server side errors' do + skip "Rails #{Rails.gem_version} uses ActionDispatch::Request#route_uri_pattern" if Rails.gem_version < Gem::Version.new('7.1') + + get 'internal_server_error' + + _(span.name).must_equal 'GET /internal_server_error' + end + end + end + + describe 'when using the class span_naming' do + let(:config) { { span_naming: :class } } + + it 'uses the http method and controller name' do + get '/ok' + + _(span.name).must_equal 'ExampleController#ok' + end + end + end + describe 'when the application has exceptions_app configured' do let(:rails_app) { AppConfig.initialize_app(use_exceptions_app: true) } it 'does not overwrite the span name from the controller that raised' do get 'internal_server_error' - _(span.name).must_equal 'ExampleController#internal_server_error' + _(span.name).must_match(/^GET/) _(span.kind).must_equal :server _(span.status.ok?).must_equal false diff --git a/instrumentation/action_pack/test/test_helper.rb b/instrumentation/action_pack/test/test_helper.rb index 4405450bc..c6ad0deee 100644 --- a/instrumentation/action_pack/test/test_helper.rb +++ b/instrumentation/action_pack/test/test_helper.rb @@ -22,8 +22,3 @@ c.use 'OpenTelemetry::Instrumentation::ActionPack' c.add_span_processor span_processor end - -# Create a globally available Rails app, this should be used in test unless -# specifically testing behaviour with different initialization configs. -DEFAULT_RAILS_APP = AppConfig.initialize_app -Rails.application = DEFAULT_RAILS_APP diff --git a/instrumentation/action_pack/test/test_helpers/app_config.rb b/instrumentation/action_pack/test/test_helpers/app_config.rb index f00733ad4..ce0f7ff6d 100644 --- a/instrumentation/action_pack/test/test_helpers/app_config.rb +++ b/instrumentation/action_pack/test/test_helpers/app_config.rb @@ -4,8 +4,8 @@ # # SPDX-License-Identifier: Apache-2.0 -class Application < Rails::Application; end require 'action_controller/railtie' +class Application < Rails::Application; end require_relative 'middlewares' require_relative 'controllers' require_relative 'routes' @@ -30,7 +30,7 @@ def initialize_app(use_exceptions_app: false, remove_rack_tracer_middleware: fal case Rails.version when /^6\.1/ apply_rails_6_1_configs(new_app) - when /^7\./ + when /^7|8\./ apply_rails_7_configs(new_app) end diff --git a/instrumentation/action_pack/test/test_helpers/controllers/example_controller.rb b/instrumentation/action_pack/test/test_helpers/controllers/example_controller.rb index 228c3c8c2..7c17d55c7 100644 --- a/instrumentation/action_pack/test/test_helpers/controllers/example_controller.rb +++ b/instrumentation/action_pack/test/test_helpers/controllers/example_controller.rb @@ -20,6 +20,6 @@ def new_item end def internal_server_error - raise :internal_server_error + raise 'internal_server_error' end end diff --git a/instrumentation/action_view/Appraisals b/instrumentation/action_view/Appraisals index e6c48d017..76b37a422 100644 --- a/instrumentation/action_view/Appraisals +++ b/instrumentation/action_view/Appraisals @@ -4,20 +4,20 @@ # # SPDX-License-Identifier: Apache-2.0 -appraise 'rails-6.1' do - gem 'rails', '~> 6.1.0' -end - -appraise 'rails-7.0' do - gem 'rails', '~> 7.0.0' -end - -appraise 'rails-7.1' do - gem 'rails', '~> 7.1.0' +%w[6.1.0 7.0.0 7.1.0].each do |version| + appraise "action_view-#{version}" do + gem 'rails', "~> #{version}" + end end if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.1.0') - appraise 'rails-7.2' do - gem 'rails', '~> 7.2.0' + %w[7.2.0].each do |version| + appraise "rails-#{version}" do + gem 'rails', "~> #{version}" + end + end + + appraise 'rails-latest' do + gem 'rails' end end diff --git a/instrumentation/action_view/opentelemetry-instrumentation-action_view.gemspec b/instrumentation/action_view/opentelemetry-instrumentation-action_view.gemspec index 79685ab32..a3dafc907 100644 --- a/instrumentation/action_view/opentelemetry-instrumentation-action_view.gemspec +++ b/instrumentation/action_view/opentelemetry-instrumentation-action_view.gemspec @@ -36,10 +36,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rails', '>= 6.1' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/active_job/Appraisals b/instrumentation/active_job/Appraisals index a25edd334..6d4d4dc42 100644 --- a/instrumentation/active_job/Appraisals +++ b/instrumentation/active_job/Appraisals @@ -10,6 +10,14 @@ end end -appraise 'activejob-latest' do - gem 'activejob' +if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.1.0') + %w[7.2.0].each do |version| + appraise "activejob-#{version}" do + gem 'activejob', "~> #{version}" + end + end + + appraise 'activejob-latest' do + gem 'activejob' + end end diff --git a/instrumentation/active_job/CHANGELOG.md b/instrumentation/active_job/CHANGELOG.md index 6bda338c4..7d9e6c941 100644 --- a/instrumentation/active_job/CHANGELOG.md +++ b/instrumentation/active_job/CHANGELOG.md @@ -1,5 +1,9 @@ # Release History: opentelemetry-instrumentation-active_job +### v0.7.8 / 2024-10-24 + +* FIXED: ActiveJob Propagate baggage information properly when performing + ### v0.7.7 / 2024-08-21 * FIXED: Propagate context between enqueue and perform diff --git a/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers/perform.rb b/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers/perform.rb index 88141f754..28981c945 100644 --- a/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers/perform.rb +++ b/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers/perform.rb @@ -34,7 +34,7 @@ def start_span(name, _id, payload) span = tracer.start_root_span(span_name, kind: :consumer, attributes: @mapper.call(payload), links: links) end - { span: span, ctx_token: attach_consumer_context(span) } + { span: span, ctx_token: attach_consumer_context(span, parent_context) } end # This method attaches a span to multiple contexts: @@ -42,9 +42,10 @@ def start_span(name, _id, payload) # This is used later to enrich the ingress span in children, e.g. setting span status to error when a child event like `discard` terminates due to an error # 2. Registers the ingress span as the "active" span, which is the default behavior of the SDK. # @param span [OpenTelemetry::Trace::Span] the currently active span used to record the exception and set the status + # @param parent_context [Context] The context to use as the parent for the consumer context # @return [Numeric] Context token that must be detached when finished - def attach_consumer_context(span) - consumer_context = OpenTelemetry::Trace.context_with_span(span) + def attach_consumer_context(span, parent_context) + consumer_context = OpenTelemetry::Trace.context_with_span(span, parent_context: parent_context) internal_context = OpenTelemetry::Instrumentation::ActiveJob.context_with_span(span, parent_context: consumer_context) OpenTelemetry::Context.attach(internal_context) diff --git a/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/version.rb b/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/version.rb index 587255970..5c55ce6dc 100644 --- a/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/version.rb +++ b/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/version.rb @@ -7,7 +7,7 @@ module OpenTelemetry module Instrumentation module ActiveJob - VERSION = '0.7.7' + VERSION = '0.7.8' end end end diff --git a/instrumentation/active_job/opentelemetry-instrumentation-active_job.gemspec b/instrumentation/active_job/opentelemetry-instrumentation-active_job.gemspec index 974244bd7..18da7cde0 100644 --- a/instrumentation/active_job/opentelemetry-instrumentation-active_job.gemspec +++ b/instrumentation/active_job/opentelemetry-instrumentation-active_job.gemspec @@ -35,10 +35,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/active_job/test/opentelemetry/instrumentation/active_job/handlers/perform_test.rb b/instrumentation/active_job/test/opentelemetry/instrumentation/active_job/handlers/perform_test.rb index de886c206..b2a19bf34 100644 --- a/instrumentation/active_job/test/opentelemetry/instrumentation/active_job/handlers/perform_test.rb +++ b/instrumentation/active_job/test/opentelemetry/instrumentation/active_job/handlers/perform_test.rb @@ -188,21 +188,6 @@ _(process_span.links[0].span_context.span_id).must_equal(publish_span.span_id) end - it 'propagates baggage' do - ctx = OpenTelemetry::Baggage.set_value('testing_baggage', 'it_worked') - OpenTelemetry::Context.with_current(ctx) do - BaggageJob.perform_later - end - - _(publish_span.trace_id).wont_equal(process_span.trace_id) - - _(process_span.total_recorded_links).must_equal(1) - _(process_span.links[0].span_context.trace_id).must_equal(publish_span.trace_id) - _(process_span.links[0].span_context.span_id).must_equal(publish_span.span_id) - - _(process_span.attributes['success']).must_equal(true) - end - describe 'with an async queue adapter' do before do begin @@ -225,6 +210,21 @@ _(process_span.links[0].span_context.trace_id).must_equal(publish_span.trace_id) _(process_span.links[0].span_context.span_id).must_equal(publish_span.span_id) end + + it 'propagates baggage' do + ctx = OpenTelemetry::Baggage.set_value('testing_baggage', 'it_worked') + OpenTelemetry::Context.with_current(ctx) do + BaggageJob.perform_later + end + perform_enqueued_jobs + + _(publish_span.trace_id).wont_equal(process_span.trace_id) + + _(process_span.total_recorded_links).must_equal(1) + _(process_span.links[0].span_context.trace_id).must_equal(publish_span.trace_id) + _(process_span.links[0].span_context.span_id).must_equal(publish_span.span_id) + _(process_span.attributes['success']).must_equal(true) + end end end @@ -251,18 +251,6 @@ _(process_span.parent_span_id).must_equal(publish_span.span_id) end - it 'propagates baggage' do - ctx = OpenTelemetry::Baggage.set_value('testing_baggage', 'it_worked') - OpenTelemetry::Context.with_current(ctx) do - BaggageJob.perform_later - end - _(process_span.total_recorded_links).must_equal(0) - - _(publish_span.trace_id).must_equal(process_span.trace_id) - _(process_span.parent_span_id).must_equal(publish_span.span_id) - _(process_span.attributes['success']).must_equal(true) - end - describe 'with an async queue adapter' do before do begin @@ -284,6 +272,20 @@ _(publish_span.trace_id).must_equal(process_span.trace_id) _(process_span.parent_span_id).must_equal(publish_span.span_id) end + + it 'propagates baggage' do + ctx = OpenTelemetry::Baggage.set_value('testing_baggage', 'it_worked') + OpenTelemetry::Context.with_current(ctx) do + BaggageJob.perform_later + end + perform_enqueued_jobs + + _(process_span.total_recorded_links).must_equal(0) + + _(publish_span.trace_id).must_equal(process_span.trace_id) + _(process_span.parent_span_id).must_equal(publish_span.span_id) + _(process_span.attributes['success']).must_equal(true) + end end end diff --git a/instrumentation/active_model_serializers/opentelemetry-instrumentation-active_model_serializers.gemspec b/instrumentation/active_model_serializers/opentelemetry-instrumentation-active_model_serializers.gemspec index 315ab5e41..0982b584c 100644 --- a/instrumentation/active_model_serializers/opentelemetry-instrumentation-active_model_serializers.gemspec +++ b/instrumentation/active_model_serializers/opentelemetry-instrumentation-active_model_serializers.gemspec @@ -35,10 +35,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rspec-mocks' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/active_record/Appraisals b/instrumentation/active_record/Appraisals index 36f641b64..faa0add16 100644 --- a/instrumentation/active_record/Appraisals +++ b/instrumentation/active_record/Appraisals @@ -4,20 +4,23 @@ # # SPDX-License-Identifier: Apache-2.0 -appraise 'activerecord-6.1' do - gem 'activerecord', '~> 6.1.0' -end - -appraise 'activerecord-7.0' do - gem 'activerecord', '~> 7.0.0' -end - -appraise 'activerecord-7.1' do - gem 'activerecord', '~> 7.1.0' +%w[6.1.0 7.0.0 7.1.0].each do |version| + appraise "activerecord-#{version}" do + gem 'sqlite3', '~> 1.4' + gem 'activerecord', "~> #{version}" + end end if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.1.0') - appraise 'activerecord-7.2' do - gem 'activerecord', '~> 7.2.0' + %w[7.2.0].each do |version| + appraise "activerecord-#{version}" do + gem 'sqlite3', '~> 1.4' + gem 'activerecord', "~> #{version}" + end + end + + appraise 'activerecord-latest' do + gem 'sqlite3', '>= 2.1' + gem 'activerecord' end end diff --git a/instrumentation/active_record/CHANGELOG.md b/instrumentation/active_record/CHANGELOG.md index e78491912..4f5f80d27 100644 --- a/instrumentation/active_record/CHANGELOG.md +++ b/instrumentation/active_record/CHANGELOG.md @@ -1,8 +1,17 @@ # Release History: opentelemetry-instrumentation-active_record +### v0.8.1 / 2024-11-21 + +* FIXED: Pass block argument in ActiveRecord `find_by_sql` patch. + +### v0.8.0 / 2024-10-22 + +* BREAKING CHANGE: Rename Active Record find_by_sql spans to query +* FIXED: Emit Active Record query spans for Rails 7.0+ + ### v0.7.4 / 2024-08-19 -* FIXED: Use ActiveSupport from top-level namespace (NoMethodError on_load) +* FIXED: Use ActiveSupport from top-level namespace (NoMethodError on_load) ### v0.7.3 / 2024-08-15 @@ -32,38 +41,38 @@ ### v0.6.1 / 2023-06-05 -* FIXED: Base config options +* FIXED: Base config options ### v0.6.0 / 2023-04-17 -* BREAKING CHANGE: Drop support for EoL Ruby 2.7 +* BREAKING CHANGE: Drop support for EoL Ruby 2.7 -* ADDED: Drop support for EoL Ruby 2.7 +* ADDED: Drop support for EoL Ruby 2.7 ### v0.5.0 / 2023-02-01 -* BREAKING CHANGE: Drop Rails 5 Support +* BREAKING CHANGE: Drop Rails 5 Support -* ADDED: Drop Rails 5 Support +* ADDED: Drop Rails 5 Support ### v0.4.1 / 2023-01-14 -* DOCS: Fix gem homepage -* DOCS: More gem documentation fixes +* DOCS: Fix gem homepage +* DOCS: More gem documentation fixes ### v0.4.0 / 2022-06-09 * Upgrading Base dependency version -* FIXED: Broken test file requirements +* FIXED: Broken test file requirements ### v0.3.0 / 2022-05-02 -* ADDED: Make ActiveRecord 7 compatible -* FIXED: RubyGems Fallback +* ADDED: Make ActiveRecord 7 compatible +* FIXED: RubyGems Fallback ### v0.2.2 / 2021-12-01 -* FIXED: Add max supported version for active record +* FIXED: Add max supported version for active record ### v0.2.1 / 2021-09-29 @@ -71,8 +80,8 @@ ### v0.2.0 / 2021-09-29 -* ADDED: Trace update_all and delete_all calls in ActiveRecord -* FIXED: Remove Active Record instantiation patch +* ADDED: Trace update_all and delete_all calls in ActiveRecord +* FIXED: Remove Active Record instantiation patch ### v0.1.1 / 2021-08-12 diff --git a/instrumentation/active_record/Gemfile b/instrumentation/active_record/Gemfile index 4475d27bf..02f64ca9a 100644 --- a/instrumentation/active_record/Gemfile +++ b/instrumentation/active_record/Gemfile @@ -12,5 +12,4 @@ group :test do gem 'byebug' gem 'opentelemetry-instrumentation-base', path: '../base' gem 'pry-byebug' - gem 'sqlite3', '~> 1.4' end diff --git a/instrumentation/active_record/lib/opentelemetry/instrumentation/active_record/patches/querying.rb b/instrumentation/active_record/lib/opentelemetry/instrumentation/active_record/patches/querying.rb index 41280b1f1..0b9f37904 100644 --- a/instrumentation/active_record/lib/opentelemetry/instrumentation/active_record/patches/querying.rb +++ b/instrumentation/active_record/lib/opentelemetry/instrumentation/active_record/patches/querying.rb @@ -18,9 +18,11 @@ class << base # Contains ActiveRecord::Querying to be patched module ClassMethods - def find_by_sql(...) - tracer.in_span("#{self}.find_by_sql") do - super + method_name = ::ActiveRecord.version >= Gem::Version.new('7.0.0') ? :_query_by_sql : :find_by_sql + + define_method(method_name) do |*args, **kwargs, &block| + tracer.in_span("#{self} query") do + super(*args, **kwargs, &block) end end diff --git a/instrumentation/active_record/lib/opentelemetry/instrumentation/active_record/version.rb b/instrumentation/active_record/lib/opentelemetry/instrumentation/active_record/version.rb index 8726c55e3..bf2bf31c3 100644 --- a/instrumentation/active_record/lib/opentelemetry/instrumentation/active_record/version.rb +++ b/instrumentation/active_record/lib/opentelemetry/instrumentation/active_record/version.rb @@ -7,7 +7,7 @@ module OpenTelemetry module Instrumentation module ActiveRecord - VERSION = '0.7.4' + VERSION = '0.8.1' end end end diff --git a/instrumentation/active_record/opentelemetry-instrumentation-active_record.gemspec b/instrumentation/active_record/opentelemetry-instrumentation-active_record.gemspec index 29eeab35d..1e6809b81 100644 --- a/instrumentation/active_record/opentelemetry-instrumentation-active_record.gemspec +++ b/instrumentation/active_record/opentelemetry-instrumentation-active_record.gemspec @@ -35,10 +35,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/active_record/test/instrumentation/active_record/patches/querying_test.rb b/instrumentation/active_record/test/instrumentation/active_record/patches/querying_test.rb index 6da620512..5a398a3c2 100644 --- a/instrumentation/active_record/test/instrumentation/active_record/patches/querying_test.rb +++ b/instrumentation/active_record/test/instrumentation/active_record/patches/querying_test.rb @@ -14,13 +14,98 @@ let(:spans) { exporter.finished_spans } before { exporter.reset } + after do + ActiveRecord::Base.subclasses.each do |model| + model.connection.truncate(model.table_name) + end + end - describe 'find_by_sql' do + describe 'query' do it 'traces' do + Account.create! + User.find_by_sql('SELECT * FROM users') + Account.first.users.to_a + + user_find_spans = spans.select { |s| s.name == 'User query' } + account_find_span = spans.find { |s| s.name == 'Account query' } + + _(user_find_spans.length).must_equal(2) + _(account_find_span).wont_be_nil + end + + describe 'find_by_sql' do + it 'creates a span' do + Account.create! + + Account.find_by_sql('SELECT * FROM accounts') + + account_find_span = spans.find { |s| s.name == 'Account query' } + _(account_find_span).wont_be_nil + _(account_find_span.attributes).must_be_empty + end + + describe 'given a block' do + it 'creates a span' do + account = Account.create! + + record_ids = [] + + Account.find_by_sql('SELECT * FROM accounts') do |record| + record_ids << record.id + end + + account_find_span = spans.find { |s| s.name == 'Account query' } + _(account_find_span).wont_be_nil + _(account_find_span.attributes).must_be_empty + + _(record_ids).must_equal([account.id]) + end + end + end + + describe 'find_by' do + it 'creates a span' do + account = Account.create! + User.create!(account: account) + + Account.find_by(id: account.id) + + account_find_span = spans.find { |s| s.name == 'Account query' } + _(account_find_span).wont_be_nil + _(account_find_span.attributes).must_be_empty + end + end + + describe 'find' do + it 'creates a span' do + account = Account.create! + User.create!(account: account) + + Account.find(account.id) + + account_find_span = spans.find { |s| s.name == 'Account query' } + _(account_find_span).wont_be_nil + _(account_find_span.attributes).must_be_empty + end + + describe 'given a block' do + it 'creates a span' do + account = Account.create! + User.create!(account: account) + + record_ids = [] + + Account.find(account.id) do |record| + record_ids << record.id + end - find_span = spans.find { |s| s.name == 'User.find_by_sql' } - _(find_span).wont_be_nil + account_find_span = spans.find { |s| s.name == 'Account query' } + _(account_find_span).wont_be_nil + _(account_find_span.attributes).must_be_empty + _(record_ids).must_equal([account.id]) + end + end end end end diff --git a/instrumentation/active_record/test/test_helper.rb b/instrumentation/active_record/test/test_helper.rb index 6cf6d2757..02751e7f6 100644 --- a/instrumentation/active_record/test/test_helper.rb +++ b/instrumentation/active_record/test/test_helper.rb @@ -34,8 +34,14 @@ database: 'db/development.sqlite3' ) -# Create User model +# Create ActiveRecord models +class Account < ActiveRecord::Base + has_many :users +end + class User < ActiveRecord::Base + belongs_to :account + validate :name_if_present scope :recently_created, -> { where('created_at > ?', Time.now - 3600) } @@ -54,9 +60,12 @@ class SuperUser < ActiveRecord::Base; end # Simple migration to create a table to test against class CreateUserTable < ActiveRecord::Migration[migration_version] def change + create_table :accounts, &:timestamps + create_table :users do |t| t.string 'name' t.integer 'counter' + t.references 'account' t.timestamps end diff --git a/instrumentation/active_support/Appraisals b/instrumentation/active_support/Appraisals index ef832823b..3a6dfc3fe 100644 --- a/instrumentation/active_support/Appraisals +++ b/instrumentation/active_support/Appraisals @@ -4,20 +4,20 @@ # # SPDX-License-Identifier: Apache-2.0 -appraise 'activesupport-6.1' do - gem 'activesupport', '~> 6.1.0' -end - -appraise 'activesupport-7.0' do - gem 'activesupport', '~> 7.0.0' -end - -appraise 'activesupport-7.1' do - gem 'activesupport', '~> 7.1.0' +%w[6.1.0 7.0.0 7.1.0].each do |version| + appraise "activesupport-#{version}" do + gem 'activesupport', "~> #{version}" + end end if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.1.0') - appraise 'activesupport-7.2' do - gem 'activesupport', '~> 7.2.0' + %w[7.2.0].each do |version| + appraise "activesupport-#{version}" do + gem 'activesupport', "~> #{version}" + end + end + + appraise 'activesupport-latest' do + gem 'activesupport' end end diff --git a/instrumentation/active_support/opentelemetry-instrumentation-active_support.gemspec b/instrumentation/active_support/opentelemetry-instrumentation-active_support.gemspec index e692985f1..8c5ad3aa0 100644 --- a/instrumentation/active_support/opentelemetry-instrumentation-active_support.gemspec +++ b/instrumentation/active_support/opentelemetry-instrumentation-active_support.gemspec @@ -39,10 +39,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'rails', '>= 6.1' spec.add_development_dependency 'rake', '~> 13.0' spec.add_development_dependency 'rspec-mocks' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/all/CHANGELOG.md b/instrumentation/all/CHANGELOG.md index 7d3116d2a..5fd7e693d 100644 --- a/instrumentation/all/CHANGELOG.md +++ b/instrumentation/all/CHANGELOG.md @@ -1,5 +1,27 @@ # Release History: opentelemetry-instrumentation-all +### v0.69.0 / 2024-11-19 + +* ADDED: Use Semconv Naming For ActionPack + +### v0.68.0 / 2024-10-23 + +* ADDED: Set span error only for 5xx response range + +### v0.67.0 / 2024-10-22 + +* BREAKING CHANGE: Rename Active Record find_by_sql spans to query +* FIXED: Emit Active Record query spans for Rails 7.0+ +* ADDED: Subscribe to process.action_mailer notifications + +### v0.66.0 / 2024-10-08 + +* ADDED: Integration with V3 telemetry provider for the aws-sdk + +### v0.65.0 / 2024-09-19 + +* ADDED: All AWS services emit traces + ### v0.64.0 / 2024-09-12 - BREAKING CHANGE: Return message when sql is over the obfuscation limit. Fixes a bug where sql statements with prepended comments that hit the obfuscation limit would be sent raw. diff --git a/instrumentation/all/lib/opentelemetry/instrumentation/all/version.rb b/instrumentation/all/lib/opentelemetry/instrumentation/all/version.rb index 93c736580..4ea9fa7d5 100644 --- a/instrumentation/all/lib/opentelemetry/instrumentation/all/version.rb +++ b/instrumentation/all/lib/opentelemetry/instrumentation/all/version.rb @@ -7,7 +7,7 @@ module OpenTelemetry module Instrumentation module All - VERSION = '0.64.0' + VERSION = '0.69.0' end end end diff --git a/instrumentation/all/opentelemetry-instrumentation-all.gemspec b/instrumentation/all/opentelemetry-instrumentation-all.gemspec index 05b81314c..dbcb84f6d 100644 --- a/instrumentation/all/opentelemetry-instrumentation-all.gemspec +++ b/instrumentation/all/opentelemetry-instrumentation-all.gemspec @@ -28,7 +28,7 @@ Gem::Specification.new do |spec| spec.add_dependency 'opentelemetry-instrumentation-active_model_serializers', '~> 0.20.1' spec.add_dependency 'opentelemetry-instrumentation-aws_lambda', '~> 0.1.0' - spec.add_dependency 'opentelemetry-instrumentation-aws_sdk', '~> 0.5.0' + spec.add_dependency 'opentelemetry-instrumentation-aws_sdk', '~> 0.7.0' spec.add_dependency 'opentelemetry-instrumentation-bunny', '~> 0.21.0' spec.add_dependency 'opentelemetry-instrumentation-concurrent_ruby', '~> 0.21.1' spec.add_dependency 'opentelemetry-instrumentation-dalli', '~> 0.25.0' @@ -50,8 +50,8 @@ Gem::Specification.new do |spec| spec.add_dependency 'opentelemetry-instrumentation-pg', '~> 0.29.0' spec.add_dependency 'opentelemetry-instrumentation-que', '~> 0.8.0' spec.add_dependency 'opentelemetry-instrumentation-racecar', '~> 0.3.0' - spec.add_dependency 'opentelemetry-instrumentation-rack', '~> 0.24.0' - spec.add_dependency 'opentelemetry-instrumentation-rails', '~> 0.31.0' + spec.add_dependency 'opentelemetry-instrumentation-rack', '~> 0.25.0' + spec.add_dependency 'opentelemetry-instrumentation-rails', '~> 0.33.0' spec.add_dependency 'opentelemetry-instrumentation-rake', '~> 0.2.1' spec.add_dependency 'opentelemetry-instrumentation-rdkafka', '~> 0.4.0' spec.add_dependency 'opentelemetry-instrumentation-redis', '~> 0.25.1' @@ -67,8 +67,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'bundler', '~> 2.4' spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' spec.add_development_dependency 'yard', '~> 0.9' diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index 69c050be5..fa0f55de2 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -30,7 +30,6 @@ def initialize def call_wrapped(event:, context:) parent_context = extract_parent_context(event) - span_kind = nil span_kind = if event['Records'] && AWS_TRIGGERS.include?(event['Records'].dig(0, 'eventSource')) :consumer else diff --git a/instrumentation/aws_lambda/opentelemetry-instrumentation-aws_lambda.gemspec b/instrumentation/aws_lambda/opentelemetry-instrumentation-aws_lambda.gemspec index 79937f592..049911d7c 100644 --- a/instrumentation/aws_lambda/opentelemetry-instrumentation-aws_lambda.gemspec +++ b/instrumentation/aws_lambda/opentelemetry-instrumentation-aws_lambda.gemspec @@ -36,10 +36,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'pry' spec.add_development_dependency 'pry-byebug' unless RUBY_ENGINE == 'jruby' spec.add_development_dependency 'rspec-mocks' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.19.1' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/aws_sdk/Appraisals b/instrumentation/aws_sdk/Appraisals index 5ecdbf591..c9c9b908b 100644 --- a/instrumentation/aws_sdk/Appraisals +++ b/instrumentation/aws_sdk/Appraisals @@ -4,58 +4,27 @@ # # SPDX-License-Identifier: Apache-2.0 -appraise 'aws-sdk-3.1' do - gem 'aws-sdk', '~> 3.1' +appraise 'aws-sdk-3' do + gem 'aws-sdk-core', '~> 3' + gem 'aws-sdk-lambda', '~> 1' + gem 'aws-sdk-dynamodb', '~> 1' + gem 'aws-sdk-sns', '~> 1' + gem 'aws-sdk-sqs', '~> 1' end -appraise 'aws-sdk-3.0' do - gem 'aws-sdk', '~> 3.0' +# pre-Observability support in V3 SDK +appraise 'aws-sdk-3.202' do + gem 'aws-sdk-core', '~> 3.202' + gem 'aws-sdk-lambda', '~> 1.127' + gem 'aws-sdk-dynamodb', '~> 1.118' + gem 'aws-sdk-sns', '~> 1.82' + gem 'aws-sdk-sqs', '~> 1.80' end appraise 'aws-sdk-2.11' do gem 'aws-sdk', '~> 2.11' end -appraise 'aws-sdk-2.10' do - gem 'aws-sdk', '~> 2.10' -end - -appraise 'aws-sdk-2.9' do - gem 'aws-sdk', '~> 2.9' -end - -appraise 'aws-sdk-2.8' do - gem 'aws-sdk', '~> 2.8' -end - -appraise 'aws-sdk-2.7' do - gem 'aws-sdk', '~> 2.7' -end - -appraise 'aws-sdk-2.6' do - gem 'aws-sdk', '~> 2.6' -end - -appraise 'aws-sdk-2.5' do - gem 'aws-sdk', '~> 2.5' -end - -appraise 'aws-sdk-2.4' do - gem 'aws-sdk', '~> 2.4' -end - -appraise 'aws-sdk-2.3' do - gem 'aws-sdk', '~> 2.3' -end - -appraise 'aws-sdk-2.2' do - gem 'aws-sdk', '~> 2.2' -end - -appraise 'aws-sdk-2.1' do - gem 'aws-sdk', '~> 2.1' -end - appraise 'aws-sdk-2.0' do gem 'aws-sdk', '~> 2.0' end diff --git a/instrumentation/aws_sdk/CHANGELOG.md b/instrumentation/aws_sdk/CHANGELOG.md index ae6f5e8a4..4c00cd561 100644 --- a/instrumentation/aws_sdk/CHANGELOG.md +++ b/instrumentation/aws_sdk/CHANGELOG.md @@ -1,5 +1,13 @@ # Release History: opentelemetry-instrumentation-aws_sdk +### v0.7.0 / 2024-10-08 + +* ADDED: Integration with V3 telemetry provider + +### v0.6.0 / 2024-09-19 + +* ADDED: All AWS services emit traces + ### v0.5.4 / 2024-07-23 * DOCS: Add cspell to CI diff --git a/instrumentation/aws_sdk/README.md b/instrumentation/aws_sdk/README.md index e1885d7a9..fcf4de368 100644 --- a/instrumentation/aws_sdk/README.md +++ b/instrumentation/aws_sdk/README.md @@ -32,6 +32,30 @@ OpenTelemetry::SDK.configure do |c| c.use_all end ``` +### Configuration options +This instrumentation offers the following configuration options: +* `:inject_messaging_context` (default: `false`): When set to `true`, adds context key/value + to Message Attributes for SQS/SNS messages. +* `suppress_internal_instrumentation` (default: `false`): When set to `true`, any spans with + span kind of `internal` are suppressed from traces. + +## Integration with SDK V3's Telemetry support +AWS SDK for Ruby V3 added support for Observability which includes a new configuration, +`telemetry_provider` and an OpenTelemetry-based telemetry provider. Only applies to +AWS service gems released after 2024-09-03. + +Using later versions of these gems will give more details on the internal spans. +See below for example usage: +```ruby +# configures the OpenTelemetry SDK with instrumentation defaults +OpenTelemetry::SDK.configure do |c| + c.use 'OpenTelemetry::Instrumentation::AwsSdk' +end + +# create open-telemetry provider and pass to client config +otel_provider = Aws::Telemetry::OTelProvider.new +client = Aws::S3::Client.new(telemetry_provider: otel_provider) +``` ## Example diff --git a/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/handler.rb b/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/handler.rb index a973adeb5..40ec604c7 100644 --- a/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/handler.rb +++ b/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/handler.rb @@ -7,38 +7,31 @@ module OpenTelemetry module Instrumentation module AwsSdk - # Generates Spans for all interactions with AwsSdk + # This handler supports specifically supports V2 and V3 + # prior to Observability support released on 2024-09-03. class Handler < Seahorse::Client::Handler - SQS_SEND_MESSAGE = 'SQS.SendMessage' - SQS_SEND_MESSAGE_BATCH = 'SQS.SendMessageBatch' - SQS_RECEIVE_MESSAGE = 'SQS.ReceiveMessage' - SNS_PUBLISH = 'SNS.Publish' - def call(context) return super unless context - service_name = service_name(context) - operation = context.operation&.name - client_method = "#{service_name}.#{operation}" - attributes = { - 'aws.region' => context.config.region, - OpenTelemetry::SemanticConventions::Trace::RPC_SYSTEM => 'aws-api', - OpenTelemetry::SemanticConventions::Trace::RPC_METHOD => operation, - OpenTelemetry::SemanticConventions::Trace::RPC_SERVICE => service_name - } - attributes[SemanticConventions::Trace::DB_SYSTEM] = 'dynamodb' if service_name == 'DynamoDB' - MessagingHelper.apply_sqs_attributes(attributes, context, client_method) if service_name == 'SQS' - MessagingHelper.apply_sns_attributes(attributes, context, client_method) if service_name == 'SNS' + service_id = HandlerHelper.service_id(context, legacy: true) + client_method = HandlerHelper.client_method(service_id, context) + + tracer.in_span( + HandlerHelper.span_name(context, client_method, service_id, legacy: true), + attributes: HandlerHelper.span_attributes(context, client_method, service_id, legacy: true), + kind: HandlerHelper.span_kind(client_method, service_id) + ) do |span| + MessagingHelper.inject_context_if_supported(context, client_method, service_id) - tracer.in_span(span_name(context, client_method), attributes: attributes, kind: span_kind(client_method)) do |span| - inject_context(context, client_method) - if instrumentation_config[:suppress_internal_instrumentation] + if HandlerHelper.instrumentation_config[:suppress_internal_instrumentation] OpenTelemetry::Common::Utilities.untraced { super } else super end.tap do |response| - span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, - context.http_response.status_code) + span.set_attribute( + OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, + context.http_response.status_code + ) if (err = response.error) span.record_exception(err) @@ -53,60 +46,11 @@ def call(context) def tracer AwsSdk::Instrumentation.instance.tracer end - - def instrumentation_config - AwsSdk::Instrumentation.instance.config - end - - def service_name(context) - # Support aws-sdk v2.0.x, which 'metadata' has a setter method only - return context.client.class.to_s.split('::')[1] if ::Seahorse::Model::Api.instance_method(:metadata).parameters.length.positive? - - context.client.class.api.metadata['serviceId'] || context.client.class.to_s.split('::')[1] - end - - SEND_MESSAGE_CLIENT_METHODS = [SQS_SEND_MESSAGE, SQS_SEND_MESSAGE_BATCH, SNS_PUBLISH].freeze - def inject_context(context, client_method) - return unless SEND_MESSAGE_CLIENT_METHODS.include? client_method - return unless instrumentation_config[:inject_messaging_context] - - if client_method == SQS_SEND_MESSAGE_BATCH - context.params[:entries].each do |entry| - entry[:message_attributes] ||= {} - OpenTelemetry.propagation.inject(entry[:message_attributes], setter: MessageAttributeSetter) - end - else - context.params[:message_attributes] ||= {} - OpenTelemetry.propagation.inject(context.params[:message_attributes], setter: MessageAttributeSetter) - end - end - - def span_kind(client_method) - case client_method - when SQS_SEND_MESSAGE, SQS_SEND_MESSAGE_BATCH, SNS_PUBLISH - OpenTelemetry::Trace::SpanKind::PRODUCER - when SQS_RECEIVE_MESSAGE - OpenTelemetry::Trace::SpanKind::CONSUMER - else - OpenTelemetry::Trace::SpanKind::CLIENT - end - end - - def span_name(context, client_method) - case client_method - when SQS_SEND_MESSAGE, SQS_SEND_MESSAGE_BATCH, SNS_PUBLISH - "#{MessagingHelper.queue_name(context)} publish" - when SQS_RECEIVE_MESSAGE - "#{MessagingHelper.queue_name(context)} receive" - else - client_method - end - end end # A Seahorse::Client::Plugin that enables instrumentation for all AWS services class Plugin < Seahorse::Client::Plugin - def add_handlers(handlers, config) + def add_handlers(handlers, _config) # run before Seahorse::Client::Plugin::ParamValidator (priority 50) handlers.add Handler, step: :validate, priority: 49 end diff --git a/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/handler_helper.rb b/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/handler_helper.rb new file mode 100644 index 000000000..9b5a01304 --- /dev/null +++ b/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/handler_helper.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module Instrumentation + module AwsSdk + # Utility module that contains shared methods between AwsSdk and Telemetry handlers + module HandlerHelper + class << self + def instrumentation_config + AwsSdk::Instrumentation.instance.config + end + + def client_method(service_id, context) + "#{service_id}.#{context.operation.name}".delete(' ') + end + + def span_attributes(context, client_method, service_id, legacy: false) + { + 'aws.region' => context.config.region, + OpenTelemetry::SemanticConventions::Trace::CODE_FUNCTION => context.operation_name.to_s, + OpenTelemetry::SemanticConventions::Trace::CODE_NAMESPACE => 'Aws::Plugins::Telemetry', + OpenTelemetry::SemanticConventions::Trace::RPC_METHOD => context.operation.name, + OpenTelemetry::SemanticConventions::Trace::RPC_SERVICE => service_id, + OpenTelemetry::SemanticConventions::Trace::RPC_SYSTEM => 'aws-api' + }.tap do |attrs| + attrs[OpenTelemetry::SemanticConventions::Trace::CODE_NAMESPACE] = 'Aws::Plugins::AwsSdk' if legacy + attrs[SemanticConventions::Trace::DB_SYSTEM] = 'dynamodb' if service_id == 'DynamoDB' + + MessagingHelper.apply_span_attributes(context, attrs, client_method, service_id) if MessagingHelper::SUPPORTED_SERVICES.include?(service_id) + end + end + + def span_kind(client_method, service_id) + case service_id + when *MessagingHelper::SUPPORTED_SERVICES + MessagingHelper.span_kind(client_method) + else + OpenTelemetry::Trace::SpanKind::CLIENT + end + end + + def span_name(context, client_method, service_id, legacy: false) + case service_id + when *MessagingHelper::SUPPORTED_SERVICES + if legacy + MessagingHelper.legacy_span_name(context, client_method) + else + MessagingHelper.span_name(context, client_method) + end + else + client_method + end + end + + def service_id(context, legacy: false) + if legacy + legacy_service_id(context) + else + context.config.api.metadata['serviceId'] || + context.config.api.metadata['serviceAbbreviation'] || + context.config.api.metadata['serviceFullName'] + end + end + + private + + def legacy_service_id(context) + # Support aws-sdk v2.0.x, which 'metadata' has a setter method only + return context.client.class.to_s.split('::')[1] if ::Seahorse::Model::Api.instance_method(:metadata).parameters.length.positive? + + context.client.class.api.metadata['serviceId'] || context.client.class.to_s.split('::')[1] + end + end + end + end + end +end diff --git a/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/instrumentation.rb b/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/instrumentation.rb index 07b4075f2..fe8651c25 100644 --- a/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/instrumentation.rb +++ b/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/instrumentation.rb @@ -7,13 +7,39 @@ module OpenTelemetry module Instrumentation module AwsSdk - # Instrumentation class that detects and installs the AwsSdk instrumentation + # The `OpenTelemetry::Instrumentation::AwsSdk::Instrumentation` class contains + # logic to detect and install the AwsSdk instrumentation. + # + # ## Configuration keys and options + # + # ### `:inject_messaging_context` + # + # Allows adding of context key/value to Message Attributes for SQS/SNS messages. + # + # - `false` **(default)** - Context key/value will not be added. + # - `true` - Context key/value will be added. + # + # ### `:suppress_internal_instrumentation` + # + # Disables tracing of spans of `internal` span kind. + # + # - `false` **(default)** - Internal spans are traced. + # - `true` - Internal spans are not traced. + # + # @example An explicit default configuration + # OpenTelemetry::SDK.configure do |c| + # c.use 'OpenTelemetry::Instrumentation::AwsSdk', { + # inject_messaging_context: false, + # suppress_internal_instrumentation: false + # } + # end class Instrumentation < OpenTelemetry::Instrumentation::Base MINIMUM_VERSION = Gem::Version.new('2.0.0') install do |_config| require_dependencies - add_plugin(Seahorse::Client::Base, *loaded_constants) + patch_telemetry_plugin if telemetry_plugin? + add_plugins(Seahorse::Client::Base, *loaded_service_clients) end present do @@ -41,31 +67,61 @@ def gem_version def require_dependencies require_relative 'handler' - require_relative 'services' + require_relative 'handler_helper' require_relative 'message_attributes' require_relative 'messaging_helper' + require_relative 'patches/telemetry' end - def add_plugin(*targets) - targets.each { |klass| klass.add_plugin(AwsSdk::Plugin) } + def add_plugins(*targets) + targets.each do |klass| + next if supports_telemetry_plugin?(klass) + + klass.add_plugin(AwsSdk::Plugin) + end + end + + def supports_telemetry_plugin?(klass) + telemetry_plugin? && + klass.plugins.include?(Aws::Plugins::Telemetry) + end + + def telemetry_plugin? + ::Aws::Plugins.const_defined?(:Telemetry) + end + + # Patches AWS SDK V3's telemetry plugin for integration + # This patch supports configuration set by this gem and + # additional span attributes that was not provided by the plugin + def patch_telemetry_plugin + ::Aws::Plugins::Telemetry::Handler.prepend(Patches::Handler) end - def loaded_constants - # Cross-check services against loaded AWS constants - # Module#const_get can return a constant from ancestors when there's a miss. - # If this conincidentally matches another constant, it will attempt to patch - # the wrong constant, resulting in patch failure. - available_services = ::Aws.constants & SERVICES.map(&:to_sym) - available_services.each_with_object([]) do |service, constants| - next if ::Aws.autoload?(service) + def loaded_service_clients + ::Aws.constants.each_with_object([]) do |c, constants| + m = ::Aws.const_get(c) + next unless loaded_service?(c, m) begin - constants << ::Aws.const_get(service, false).const_get(:Client, false) + constants << m.const_get(:Client) rescue StandardError => e OpenTelemetry.logger.warn("Constant could not be loaded: #{e}") end end end + + # This check does the following: + # 1 - Checks if the service client is autoload or not + # 2 - Validates whether if is a service client + # note that Seahorse::Client::Base is a superclass for V3 clients + # but for V2, it is Aws::Client + def loaded_service?(constant, service_module) + !::Aws.autoload?(constant) && + service_module.is_a?(Module) && + service_module.const_defined?(:Client) && + (service_module.const_get(:Client).superclass == Seahorse::Client::Base || + service_module.const_get(:Client).superclass == Aws::Client) + end end end end diff --git a/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/messaging_helper.rb b/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/messaging_helper.rb index e6fb8d0e4..b821aca56 100644 --- a/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/messaging_helper.rb +++ b/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/messaging_helper.rb @@ -7,9 +7,20 @@ module OpenTelemetry module Instrumentation module AwsSdk - # MessagingHelper class provides methods for calculating messaging span attributes + # An utility class to help SQS/SNS-related span attributes/context injection class MessagingHelper + SUPPORTED_SERVICES = %w[SQS SNS].freeze class << self + SQS_SEND_MESSAGE = 'SQS.SendMessage' + SQS_SEND_MESSAGE_BATCH = 'SQS.SendMessageBatch' + SQS_RECEIVE_MESSAGE = 'SQS.ReceiveMessage' + SNS_PUBLISH = 'SNS.Publish' + SEND_MESSAGE_CLIENT_METHODS = [SQS_SEND_MESSAGE, SQS_SEND_MESSAGE_BATCH, SNS_PUBLISH].freeze + + def supported_services + SUPPORTED_SERVICES + end + def queue_name(context) topic_arn = context.params[:topic_arn] target_arn = context.params[:target_arn] @@ -28,19 +39,82 @@ def queue_name(context) 'unknown' end + def span_name(context, client_method) + case client_method + when SQS_SEND_MESSAGE, SQS_SEND_MESSAGE_BATCH, SNS_PUBLISH + "#{client_method}.#{queue_name(context)}.Publish" + when SQS_RECEIVE_MESSAGE + "#{client_method}.#{queue_name(context)}.Receive" + else + client_method + end + end + + def legacy_span_name(context, client_method) + case client_method + when SQS_SEND_MESSAGE, SQS_SEND_MESSAGE_BATCH, SNS_PUBLISH + "#{MessagingHelper.queue_name(context)} publish" + when SQS_RECEIVE_MESSAGE + "#{MessagingHelper.queue_name(context)} receive" + else + client_method + end + end + + def apply_span_attributes(context, attrs, client_method, service_id) + case service_id + when 'SQS' + apply_sqs_attributes(attrs, context, client_method) + when 'SNS' + apply_sns_attributes(attrs, context, client_method) + end + end + + def span_kind(client_method) + case client_method + when SQS_SEND_MESSAGE, SQS_SEND_MESSAGE_BATCH, SNS_PUBLISH + OpenTelemetry::Trace::SpanKind::PRODUCER + when SQS_RECEIVE_MESSAGE + OpenTelemetry::Trace::SpanKind::CONSUMER + else + OpenTelemetry::Trace::SpanKind::CLIENT + end + end + + def inject_context_if_supported(context, client_method, service_id) + if HandlerHelper.instrumentation_config[:inject_messaging_context] && + SUPPORTED_SERVICES.include?(service_id) + inject_context(context, client_method) + end + end + + def inject_context(context, client_method) + return unless SEND_MESSAGE_CLIENT_METHODS.include?(client_method) + + if client_method == SQS_SEND_MESSAGE_BATCH + context.params[:entries].each do |entry| + entry[:message_attributes] ||= {} + OpenTelemetry.propagation.inject(entry[:message_attributes], setter: MessageAttributeSetter) + end + else + context.params[:message_attributes] ||= {} + OpenTelemetry.propagation.inject(context.params[:message_attributes], setter: MessageAttributeSetter) + end + end + + private + def apply_sqs_attributes(attributes, context, client_method) attributes[SemanticConventions::Trace::MESSAGING_SYSTEM] = 'aws.sqs' attributes[SemanticConventions::Trace::MESSAGING_DESTINATION_KIND] = 'queue' attributes[SemanticConventions::Trace::MESSAGING_DESTINATION] = queue_name(context) attributes[SemanticConventions::Trace::MESSAGING_URL] = context.params[:queue_url] if context.params[:queue_url] - - attributes[SemanticConventions::Trace::MESSAGING_OPERATION] = 'receive' if client_method == 'SQS.ReceiveMessage' + attributes[SemanticConventions::Trace::MESSAGING_OPERATION] = 'receive' if client_method == SQS_RECEIVE_MESSAGE end def apply_sns_attributes(attributes, context, client_method) attributes[SemanticConventions::Trace::MESSAGING_SYSTEM] = 'aws.sns' - - return unless client_method == 'SNS.Publish' + return unless client_method == SNS_PUBLISH attributes[SemanticConventions::Trace::MESSAGING_DESTINATION_KIND] = 'topic' attributes[SemanticConventions::Trace::MESSAGING_DESTINATION] = queue_name(context) diff --git a/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/patches/telemetry.rb b/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/patches/telemetry.rb new file mode 100644 index 000000000..31bb41c39 --- /dev/null +++ b/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/patches/telemetry.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module Instrumentation + module AwsSdk + module Patches + # Patch for Telemetry Plugin Handler in V3 SDK + module Handler + def call(context) + span_wrapper(context) { @handler.call(context) } + end + + private + + def span_wrapper(context, &block) + service_id = HandlerHelper.service_id(context) + client_method = HandlerHelper.client_method(service_id, context) + context.tracer.in_span( + HandlerHelper.span_name(context, client_method, service_id), + attributes: HandlerHelper.span_attributes(context, client_method, service_id), + kind: HandlerHelper.span_kind(client_method, service_id) + ) do |span| + MessagingHelper.inject_context_if_supported(context, client_method, service_id) + + if HandlerHelper.instrumentation_config[:suppress_internal_instrumentation] + OpenTelemetry::Common::Utilities.untraced { super } + else + yield span + end + end + end + end + end + end + end +end diff --git a/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/services.rb b/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/services.rb deleted file mode 100644 index d0bacb75f..000000000 --- a/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/services.rb +++ /dev/null @@ -1,121 +0,0 @@ -# frozen_string_literal: true - -module OpenTelemetry - module Instrumentation - # rubocop:disable Metrics/ModuleLength: - module AwsSdk - SERVICES = %w[ - ACM - APIGateway - AppStream - ApplicationAutoScaling - ApplicationDiscoveryService - Athena - AutoScaling - Batch - Budgets - CloudDirectory - CloudFormation - CloudFront - CloudHSM - CloudHSMV2 - CloudSearch - CloudSearchDomain - CloudTrail - CloudWatch - CloudWatchEvents - CloudWatchLogs - CodeBuild - CodeCommit - CodeDeploy - CodePipeline - CodeStar - CognitoIdentity - CognitoIdentityProvider - CognitoSync - ConfigService - CostandUsageReportService - DAX - DataPipeline - DatabaseMigrationService - DeviceFarm - DirectConnect - DirectoryService - DynamoDB - DynamoDBStreams - EC2 - ECR - ECS - EFS - EMR - ElastiCache - ElasticBeanstalk - ElasticLoadBalancing - ElasticLoadBalancingV2 - ElasticTranscoder - ElasticsearchService - EventBridge - Firehose - GameLift - Glacier - Glue - Greengrass - Health - IAM - ImportExport - Inspector - IoT - IoTDataPlane - KMS - Kinesis - KinesisAnalytics - Lambda - LambdaPreview - Lex - LexModelBuildingService - Lightsail - MTurk - MachineLearning - MarketplaceCommerceAnalytics - MarketplaceEntitlementService - MarketplaceMetering - MigrationHub - Mobile - OpsWorks - OpsWorksCM - Organizations - Pinpoint - Polly - RDS - Redshift - Rekognition - ResourceGroupsTaggingAPI - Route53 - Route53Domains - S3 - SES - SMS - SNS - SQS - SSM - STS - SWF - ServiceCatalog - Schemas - Shield - SimpleDB - Snowball - States - StorageGateway - Support - Textract - WAF - WAFRegional - WorkDocs - WorkSpaces - XRay - ].freeze - end - # rubocop:enable Metrics/ModuleLength: - end -end diff --git a/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/version.rb b/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/version.rb index b14b16581..6fe03e491 100644 --- a/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/version.rb +++ b/instrumentation/aws_sdk/lib/opentelemetry/instrumentation/aws_sdk/version.rb @@ -7,7 +7,7 @@ module OpenTelemetry module Instrumentation module AwsSdk - VERSION = '0.5.4' + VERSION = '0.7.0' end end end diff --git a/instrumentation/aws_sdk/opentelemetry-instrumentation-aws_sdk.gemspec b/instrumentation/aws_sdk/opentelemetry-instrumentation-aws_sdk.gemspec index 0c84297d7..3648bec85 100644 --- a/instrumentation/aws_sdk/opentelemetry-instrumentation-aws_sdk.gemspec +++ b/instrumentation/aws_sdk/opentelemetry-instrumentation-aws_sdk.gemspec @@ -19,9 +19,10 @@ Gem::Specification.new do |spec| spec.homepage = 'https://github.com/open-telemetry/opentelemetry-ruby-contrib' spec.license = 'Apache-2.0' - spec.files = Dir.glob('lib/**/*.rb') + - Dir.glob('*.md') + - ['LICENSE', '.yardopts'] + spec.files = + Dir.glob('lib/**/*.rb') + + Dir.glob('*.md') + + ['LICENSE', '.yardopts'] spec.require_paths = ['lib'] spec.required_ruby_version = '>= 3.0' @@ -36,10 +37,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'pry' spec.add_development_dependency 'pry-byebug' unless RUBY_ENGINE == 'jruby' spec.add_development_dependency 'rspec-mocks' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/aws_sdk/test/opentelemetry/handler_test.rb b/instrumentation/aws_sdk/test/opentelemetry/handler_test.rb new file mode 100644 index 000000000..8b178948c --- /dev/null +++ b/instrumentation/aws_sdk/test/opentelemetry/handler_test.rb @@ -0,0 +1,201 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'test_helper' + +describe OpenTelemetry::Instrumentation::AwsSdk do + describe 'AwsSdk Plugin' do + let(:instrumentation_gem_version) do + OpenTelemetry::Instrumentation::AwsSdk::Instrumentation.instance.gem_version + end + let(:otel_semantic) { OpenTelemetry::SemanticConventions::Trace } + let(:exporter) { EXPORTER } + let(:span) { exporter.finished_spans.last } + let(:span_attrs) do + { + 'aws.region' => 'us-stubbed-1', + otel_semantic::HTTP_STATUS_CODE => 200, + otel_semantic::RPC_SYSTEM => 'aws-api' + } + end + + before do + exporter.reset + end + + describe 'Lambda' do + let(:service_name) { 'Lambda' } + let(:client) { Aws::Lambda::Client.new(stub_responses: true) } + let(:expected_attrs) do + span_attrs.tap do |attrs| + attrs[otel_semantic::RPC_METHOD] = 'ListFunctions' + attrs[otel_semantic::RPC_SERVICE] = service_name + end + end + + it 'creates a span with all the supplied parameters' do + skip if TestHelper.telemetry_plugin?(service_name) + + client.list_functions + + _(span.name).must_equal('Lambda.ListFunctions') + _(span.kind).must_equal(:client) + TestHelper.match_span_attrs(expected_attrs, span, self) + end + + it 'should have correct span attributes when error' do + skip if TestHelper.telemetry_plugin?(service_name) + + client.stub_responses(:list_functions, 'NotFound') + + begin + client.list_functions + rescue Aws::Lambda::Errors::NotFound + _(span.status.code).must_equal(2) + _(span.events[0].name).must_equal('exception') + _(span.attributes[otel_semantic::HTTP_STATUS_CODE]).must_equal(400) + end + end + end + + describe 'SNS' do + let(:service_name) { 'SNS' } + let(:client) { Aws::SNS::Client.new(stub_responses: true) } + let(:expected_attrs) do + span_attrs.tap do |attrs| + attrs[otel_semantic::RPC_METHOD] = 'Publish' + attrs[otel_semantic::RPC_SERVICE] = service_name + attrs[otel_semantic::MESSAGING_DESTINATION_KIND] = 'topic' + attrs[otel_semantic::MESSAGING_DESTINATION] = 'TopicName' + attrs[otel_semantic::MESSAGING_SYSTEM] = 'aws.sns' + end + end + + it 'creates a span with appropriate messaging attributes' do + skip if TestHelper.telemetry_plugin?(service_name) + + client.publish( + message: 'msg', + topic_arn: 'arn:aws:sns:fake:123:TopicName' + ) + + _(span.name).must_equal('TopicName publish') + _(span.kind).must_equal(:producer) + TestHelper.match_span_attrs(expected_attrs, span, self) + end + + it 'creates a span that includes a phone number' do + # skip if using aws-sdk version before phone_number supported (v2.3.18) + skip if Gem::Version.new('2.3.18') > instrumentation_gem_version + skip if TestHelper.telemetry_plugin?(service_name) + + client.publish(message: 'msg', phone_number: '123456') + + _(span.name).must_equal('phone_number publish') + _(span.attributes[otel_semantic::MESSAGING_DESTINATION]) + .must_equal('phone_number') + end + end + + describe 'SQS' do + let(:service_name) { 'SQS' } + let(:client) { Aws::SQS::Client.new(stub_responses: true) } + let(:queue_url) { 'https://sqs.fake.amazonaws.com/1/QueueName' } + let(:expected_base_attrs) do + span_attrs.tap do |attrs| + attrs[otel_semantic::RPC_SERVICE] = service_name + attrs[otel_semantic::MESSAGING_DESTINATION_KIND] = 'queue' + attrs[otel_semantic::MESSAGING_DESTINATION] = 'QueueName' + attrs[otel_semantic::MESSAGING_SYSTEM] = 'aws.sqs' + attrs[otel_semantic::MESSAGING_URL] = queue_url + end + end + + describe '#SendMessage' do + let(:expected_attrs) do + span_attrs.tap do |attrs| + attrs[otel_semantic::RPC_METHOD] = 'SendMessage' + end + end + + it 'creates a span with appropriate messaging attributes' do + skip if TestHelper.telemetry_plugin?(service_name) + + client.send_message(message_body: 'msg', queue_url: queue_url) + + _(span.name).must_equal('QueueName publish') + _(span.kind).must_equal(:producer) + TestHelper.match_span_attrs(expected_attrs, span, self) + end + end + + describe '#SendMessageBatch' do + let(:expected_attrs) do + expected_base_attrs.tap do |attrs| + attrs[otel_semantic::RPC_METHOD] = 'SendMessageBatch' + end + end + + it 'creates a span with appropriate messaging attributes' do + skip if TestHelper.telemetry_plugin?(service_name) + + client.send_message_batch( + queue_url: queue_url, + entries: [{ id: 'Message1', message_body: 'Body1' }] + ) + + _(span.name).must_equal('QueueName publish') + _(span.kind).must_equal(:producer) + TestHelper.match_span_attrs(expected_attrs, span, self) + end + end + + describe '#ReceiveMessage' do + let(:expected_attrs) do + expected_base_attrs.tap do |attrs| + attrs[otel_semantic::RPC_METHOD] = 'ReceiveMessage' + attrs[otel_semantic::MESSAGING_OPERATION] = 'receive' + end + end + + it 'creates a span with appropriate messaging attributes' do + skip if TestHelper.telemetry_plugin?(service_name) + + client.receive_message(queue_url: queue_url) + + _(span.name).must_equal('QueueName receive') + _(span.kind).must_equal(:consumer) + TestHelper.match_span_attrs(expected_attrs, span, self) + end + end + + describe '#GetQueueUrl' do + it 'creates a span with appropriate messaging attributes' do + skip if TestHelper.telemetry_plugin?(service_name) + + client.get_queue_url(queue_name: 'queue-name') + + _(span.attributes['messaging.destination']) + .must_equal('unknown') + _(span.attributes).wont_include('messaging.url') + end + end + end + + describe 'DynamoDB' do + let(:client) { Aws::DynamoDB::Client.new(stub_responses: true) } + + it 'creates a span with dynamodb-specific attribute' do + skip if TestHelper.telemetry_plugin?('DynamoDB') + + client.list_tables + + _(span.attributes[otel_semantic::DB_SYSTEM]) + .must_equal('dynamodb') + end + end + end +end diff --git a/instrumentation/aws_sdk/test/opentelemetry/instrumentation_test.rb b/instrumentation/aws_sdk/test/opentelemetry/instrumentation_test.rb index f44e81bc5..7ffe3d33f 100644 --- a/instrumentation/aws_sdk/test/opentelemetry/instrumentation_test.rb +++ b/instrumentation/aws_sdk/test/opentelemetry/instrumentation_test.rb @@ -9,8 +9,6 @@ describe OpenTelemetry::Instrumentation::AwsSdk do let(:instrumentation) { OpenTelemetry::Instrumentation::AwsSdk::Instrumentation.instance } let(:minimum_version) { OpenTelemetry::Instrumentation::AwsSdk::Instrumentation::MINIMUM_VERSION } - let(:exporter) { EXPORTER } - let(:last_span) { exporter.finished_spans.last } it 'has #name' do _(instrumentation.name).must_equal 'OpenTelemetry::Instrumentation::AwsSdk' @@ -28,12 +26,24 @@ _(instrumentation.compatible?).must_equal false end - Gem.stub(:loaded_specs, { 'aws-sdk-core' => nil, 'aws-sdk' => Gem::Specification.new { |s| s.version = '1.0.0' } }) do + Gem.stub( + :loaded_specs, + { + 'aws-sdk-core' => nil, + 'aws-sdk' => Gem::Specification.new { |s| s.version = '1.0.0' } + } + ) do hide_const('::Aws::CORE_GEM_VERSION') _(instrumentation.compatible?).must_equal false end - Gem.stub(:loaded_specs, { 'aws-sdk-core' => Gem::Specification.new { |s| s.version = '1.0.0' }, 'aws-sdk' => nil }) do + Gem.stub( + :loaded_specs, + { + 'aws-sdk-core' => Gem::Specification.new { |s| s.version = '1.0.0' }, + 'aws-sdk' => nil + } + ) do hide_const('::Aws::CORE_GEM_VERSION') _(instrumentation.compatible?).must_equal false end @@ -55,216 +65,4 @@ instrumentation.instance_variable_set(:@installed, false) end end - - describe 'validate_spans' do - describe 'SNS' do - it 'should have correct attributes' do - sns = Aws::SNS::Client.new(stub_responses: true) - sns.stub_responses(:publish) - - sns.publish message: 'msg' - - _(last_span.attributes['rpc.system']).must_equal 'aws-api' - _(last_span.attributes['rpc.service']).must_equal 'SNS' - _(last_span.attributes['rpc.method']).must_equal 'Publish' - _(last_span.attributes['aws.region']).must_include 'stubbed' - _(last_span.attributes['db.system']).must_be_nil - - _(last_span.attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE]).must_equal 200 - - _(last_span.status.code).must_equal OpenTelemetry::Trace::Status::UNSET - end - end - - describe 'S3' do - it 'should have correct attributes when success' do - s3 = Aws::S3::Client.new(stub_responses: { list_buckets: { buckets: [{ name: 'bucket1' }] } }) - - s3.list_buckets - - _(last_span.attributes['rpc.system']).must_equal 'aws-api' - _(last_span.attributes['rpc.service']).must_equal 'S3' - _(last_span.attributes['rpc.method']).must_equal 'ListBuckets' - _(last_span.attributes['aws.region']).must_include 'stubbed' - _(last_span.attributes['db.system']).must_be_nil - - _(last_span.attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE]).must_equal 200 - - _(last_span.status.code).must_equal OpenTelemetry::Trace::Status::UNSET - end - - it 'should have correct attributes when error' do - s3 = Aws::S3::Client.new(stub_responses: true) - s3.stub_responses(:list_buckets, 'NotFound') - - begin - s3.list_buckets - rescue StandardError - _(last_span.attributes['rpc.system']).must_equal 'aws-api' - _(last_span.attributes['rpc.service']).must_equal 'S3' - _(last_span.attributes['rpc.method']).must_equal 'ListBuckets' - _(last_span.attributes['aws.region']).must_include 'stubbed' - _(last_span.attributes['db.system']).must_be_nil - end - - _(last_span.attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE]).must_equal 400 - - _(last_span.status.code).must_equal OpenTelemetry::Trace::Status::ERROR - end - end - - describe 'dynamodb' do - it 'should have db.system attribute' do - dynamodb_client = Aws::DynamoDB::Client.new(stub_responses: true) - - dynamodb_client.list_tables - - _(last_span.attributes['rpc.system']).must_equal 'aws-api' - _(last_span.attributes['db.system']).must_equal 'dynamodb' - - _(last_span.attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE]).must_equal 200 - end - end - - describe 'sqs' do - it 'should have messaging attributes for send_message' do - sqs_client = Aws::SQS::Client.new(stub_responses: true) - - sqs_client.send_message message_body: 'msg', queue_url: 'https://sqs.fake.amazonaws.com/1/queue-name' - - _(last_span.attributes['rpc.system']).must_equal 'aws-api' - _(last_span.attributes['messaging.system']).must_equal 'aws.sqs' - _(last_span.attributes['messaging.destination_kind']).must_equal 'queue' - _(last_span.attributes['messaging.destination']).must_equal 'queue-name' - _(last_span.attributes['messaging.url']).must_equal 'https://sqs.fake.amazonaws.com/1/queue-name' - end - - it 'should have messaging attributes for send_message_batch' do - sqs_client = Aws::SQS::Client.new(stub_responses: true) - - entries = [ - { - id: 'Message1', - message_body: 'This is the first message.' - }, - { - id: 'Message2', - message_body: 'This is the second message.', - message_attributes: { - attr1: { - data_type: 'String', - string_value: 'value1' - } - } - } - ] - - sqs_client.send_message_batch( - queue_url: 'https://sqs.fake.amazonaws.com/1/queue-name', - entries: entries - ) - - _(last_span.attributes['rpc.system']).must_equal 'aws-api' - _(last_span.attributes['messaging.system']).must_equal 'aws.sqs' - _(last_span.attributes['messaging.destination_kind']).must_equal 'queue' - _(last_span.attributes['messaging.destination']).must_equal 'queue-name' - _(last_span.attributes['messaging.url']).must_equal 'https://sqs.fake.amazonaws.com/1/queue-name' - end - - it 'should have messaging attributes for get_queue_url' do - sqs_client = Aws::SQS::Client.new(stub_responses: true) - - sqs_client.get_queue_url queue_name: 'queue-name' - - _(last_span.attributes['rpc.system']).must_equal 'aws-api' - _(last_span.attributes['messaging.system']).must_equal 'aws.sqs' - _(last_span.attributes['messaging.destination_kind']).must_equal 'queue' - _(last_span.attributes['messaging.destination']).must_equal 'unknown' - _(last_span.attributes).wont_include('messaging.url') - end - end - - describe 'sns' do - it 'should have messaging attributes for publish' do - sns_client = Aws::SNS::Client.new(stub_responses: true) - - sns_client.publish message: 'msg', topic_arn: 'arn:aws:sns:fake:123:topic-name' - - _(last_span.attributes['rpc.system']).must_equal 'aws-api' - _(last_span.attributes['messaging.system']).must_equal 'aws.sns' - _(last_span.attributes['messaging.destination_kind']).must_equal 'topic' - _(last_span.attributes['messaging.destination']).must_equal 'topic-name' - end - - it 'should handle phone numbers' do - # skip if using aws-sdk version before phone_number supported (v2.3.18) - return if Gem::Version.new('2.3.18') > instrumentation.gem_version - - sns_client = Aws::SNS::Client.new(stub_responses: true) - - sns_client.publish message: 'msg', phone_number: '123456' - - _(last_span.attributes['messaging.destination']).must_equal 'phone_number' - _(last_span.name).must_equal 'phone_number publish' - end - end - end - - describe 'MessageAttributeSetter' do - it 'set when hash length is lower than 10' do - key = 'foo' - value = 'bar' - metadata_attributes = {} - OpenTelemetry::Instrumentation::AwsSdk::MessageAttributeSetter.set(metadata_attributes, key, value) - _(metadata_attributes[key]).must_equal(string_value: value, data_type: 'String') - end - - it 'should keep existing attributes' do - key = 'foo' - value = 'bar' - metadata_attributes = { - 'existingKey' => { string_value: 'existingValue', data_type: 'String' } - } - OpenTelemetry::Instrumentation::AwsSdk::MessageAttributeSetter.set(metadata_attributes, key, value) - _(metadata_attributes[key]).must_equal(string_value: value, data_type: 'String') - _(metadata_attributes['existingKey']).must_equal(string_value: 'existingValue', data_type: 'String') - end - - it 'should not add if there are 10 or more existing attributes' do - metadata_attributes = { - 'existingKey0' => { string_value: 'existingValue', data_type: 'String' }, - 'existingKey1' => { string_value: 'existingValue', data_type: 'String' }, - 'existingKey2' => { string_value: 'existingValue', data_type: 'String' }, - 'existingKey3' => { string_value: 'existingValue', data_type: 'String' }, - 'existingKey4' => { string_value: 'existingValue', data_type: 'String' }, - 'existingKey5' => { string_value: 'existingValue', data_type: 'String' }, - 'existingKey6' => { string_value: 'existingValue', data_type: 'String' }, - 'existingKey7' => { string_value: 'existingValue', data_type: 'String' }, - 'existingKey8' => { string_value: 'existingValue', data_type: 'String' }, - 'existingKey9' => { string_value: 'existingValue', data_type: 'String' } - } - OpenTelemetry::Instrumentation::AwsSdk::MessageAttributeSetter.set(metadata_attributes, 'new10', 'value') - _(metadata_attributes.keys).must_equal(%w[existingKey0 existingKey1 existingKey2 existingKey3 existingKey4 existingKey5 existingKey6 existingKey7 existingKey8 existingKey9]) - end - - describe 'MessageAttributeGetter' do - let(:getter) { OpenTelemetry::Instrumentation::AwsSdk::MessageAttributeGetter } - let(:carrier) do - { - 'traceparent' => { data_type: 'String', string_value: 'tp' }, - 'tracestate' => { data_type: 'String', string_value: 'ts' }, - 'x-source-id' => { data_type: 'String', string_value: '123' } - } - end - - it 'reads key from carrier' do - _(getter.get(carrier, 'traceparent')).must_equal('tp') - _(getter.get(carrier, 'x-source-id')).must_equal('123') - end - - it 'returns nil for non-existant key' do - _(getter.get(carrier, 'not-here')).must_be_nil - end - end - end end diff --git a/instrumentation/aws_sdk/test/opentelemetry/message_attributes_test.rb b/instrumentation/aws_sdk/test/opentelemetry/message_attributes_test.rb new file mode 100644 index 000000000..1d3486399 --- /dev/null +++ b/instrumentation/aws_sdk/test/opentelemetry/message_attributes_test.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'test_helper' + +describe OpenTelemetry::Instrumentation::AwsSdk do + let(:instrumentation) { OpenTelemetry::Instrumentation::AwsSdk } + + describe 'MessageAttributeSetter' do + it 'set when hash length is lower than 10' do + key = 'foo' + value = 'bar' + metadata_attributes = {} + instrumentation::MessageAttributeSetter.set(metadata_attributes, key, value) + _(metadata_attributes[key]).must_equal(string_value: value, data_type: 'String') + end + + it 'should keep existing attributes' do + key = 'foo' + value = 'bar' + metadata_attributes = { + 'existingKey' => { string_value: 'existingValue', data_type: 'String' } + } + instrumentation::MessageAttributeSetter.set(metadata_attributes, key, value) + _(metadata_attributes[key]).must_equal(string_value: value, data_type: 'String') + _(metadata_attributes['existingKey']) + .must_equal(string_value: 'existingValue', data_type: 'String') + end + + it 'should not add if there are 10 or more existing attributes' do + metadata_attributes = { + 'existingKey0' => { string_value: 'existingValue', data_type: 'String' }, + 'existingKey1' => { string_value: 'existingValue', data_type: 'String' }, + 'existingKey2' => { string_value: 'existingValue', data_type: 'String' }, + 'existingKey3' => { string_value: 'existingValue', data_type: 'String' }, + 'existingKey4' => { string_value: 'existingValue', data_type: 'String' }, + 'existingKey5' => { string_value: 'existingValue', data_type: 'String' }, + 'existingKey6' => { string_value: 'existingValue', data_type: 'String' }, + 'existingKey7' => { string_value: 'existingValue', data_type: 'String' }, + 'existingKey8' => { string_value: 'existingValue', data_type: 'String' }, + 'existingKey9' => { string_value: 'existingValue', data_type: 'String' } + } + instrumentation::MessageAttributeSetter.set(metadata_attributes, 'new10', 'value') + _(metadata_attributes.keys) + .must_equal( + %w[ + existingKey0 + existingKey1 + existingKey2 + existingKey3 + existingKey4 + existingKey5 + existingKey6 + existingKey7 + existingKey8 + existingKey9 + ] + ) + end + end + + describe 'MessageAttributeGetter' do + let(:getter) { instrumentation::MessageAttributeGetter } + let(:carrier) do + { + 'traceparent' => { data_type: 'String', string_value: 'tp' }, + 'tracestate' => { data_type: 'String', string_value: 'ts' }, + 'x-source-id' => { data_type: 'String', string_value: '123' } + } + end + + it 'reads key from carrier' do + _(getter.get(carrier, 'traceparent')).must_equal('tp') + _(getter.get(carrier, 'x-source-id')).must_equal('123') + end + + it 'returns nil for non-existant key' do + _(getter.get(carrier, 'not-here')).must_be_nil + end + end +end diff --git a/instrumentation/aws_sdk/test/opentelemetry/patches/telemetry_test.rb b/instrumentation/aws_sdk/test/opentelemetry/patches/telemetry_test.rb new file mode 100644 index 000000000..55fd83886 --- /dev/null +++ b/instrumentation/aws_sdk/test/opentelemetry/patches/telemetry_test.rb @@ -0,0 +1,297 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require_relative '../../test_helper' + +describe OpenTelemetry::Instrumentation::AwsSdk do + describe 'Telemetry plugin' do + let(:instrumentation_gem_version) do + OpenTelemetry::Instrumentation::AwsSdk::Instrumentation.instance.gem_version + end + let(:otel_semantic) { OpenTelemetry::SemanticConventions::Trace } + let(:exporter) { EXPORTER } + let(:spans) { exporter.finished_spans } + let(:otel_provider) { Aws::Telemetry::OTelProvider.new } + let(:stub_span) { spans.find { |s| s.name == 'Handler.StubResponses' } } + let(:client_attrs) do + { + 'aws.region' => 'us-stubbed-1', + otel_semantic::CODE_NAMESPACE => 'Aws::Plugins::Telemetry', + otel_semantic::RPC_SYSTEM => 'aws-api' + } + end + + let(:stub_attrs) do + { + 'http.status_code' => '200', + 'net.protocol.name' => 'http', + 'net.protocol.version' => '1.1' + } + end + + before do + exporter.reset + end + + describe 'Lambda' do + let(:service_name) { 'Lambda' } + let(:service_uri) do + 'https://lambda.us-east-1.amazonaws.com/2015-03-31/functions/' + end + let(:client) do + Aws::Lambda::Client.new( + telemetry_provider: otel_provider, + stub_responses: true + ) + end + let(:client_span) { spans.find { |s| s.name == 'Lambda.ListFunctions' } } + let(:internal_span) { spans.find { |s| s.name == 'Handler.NetHttp' } } + + let(:expected_client_attrs) do + client_attrs.tap do |attrs| + attrs[otel_semantic::CODE_FUNCTION] = 'list_functions' + attrs[otel_semantic::RPC_METHOD] = 'ListFunctions' + attrs[otel_semantic::RPC_SERVICE] = service_name + end + end + + let(:expected_stub_attrs) { stub_attrs.tap { |a| a['http.method'] = 'GET' } } + + let(:expected_internal_attrs) do + stub_attrs.tap do |attrs| + attrs['net.peer.name'] = 'lambda.us-east-1.amazonaws.com' + attrs['net.peer.port'] = '443' + end + end + + it 'creates spans with all the supplied parameters' do + skip unless TestHelper.telemetry_plugin?(service_name) + client.list_functions + + _(client_span.name).must_equal('Lambda.ListFunctions') + _(stub_span.name).must_equal('Handler.StubResponses') + _(client_span.kind).must_equal(:client) + _(stub_span.kind).must_equal(:internal) + TestHelper.match_span_attrs(expected_client_attrs, client_span, self) + TestHelper.match_span_attrs(expected_stub_attrs, stub_span, self) + _(stub_span.parent_span_id).must_equal(client_span.span_id) + end + + it 'creates spans with all the non-stubbed parameters' do + skip unless TestHelper.telemetry_plugin?(service_name) + stub_request(:get, 'https://lambda.us-east-1.amazonaws.com/2015-03-31/functions/') + + client = Aws::Lambda::Client.new( + telemetry_provider: otel_provider, + credentials: Aws::Credentials.new('akid', 'secret'), + region: 'us-east-1' + ) + client.list_functions + + _(client_span.name).must_equal('Lambda.ListFunctions') + _(internal_span.name).must_equal('Handler.NetHttp') + _(client_span.kind).must_equal(:client) + _(internal_span.kind).must_equal(:internal) + _(client_span.attributes['aws.region']).must_equal('us-east-1') + TestHelper.match_span_attrs(expected_internal_attrs, internal_span, self) + end + + it 'should have correct span attributes when error' do + skip unless TestHelper.telemetry_plugin?(service_name) + stub_request(:get, 'foo').to_return(status: 400) + + begin + client.list_functions + rescue Aws::Lambda::Errors::BadRequest + _(client_span.status.code).must_equal(2) + _(client_span.events[0].name).must_equal('exception') + _(internal_span.attributes['http.status_code']).must_equal('400') + end + end + end + + describe 'SNS' do + let(:service_name) { 'SNS' } + let(:client) do + Aws::SNS::Client.new( + telemetry_provider: otel_provider, + stub_responses: true + ) + end + let(:client_span) { spans.find { |s| s.name.include?('SNS.Publish') } } + + let(:expected_client_attrs) do + client_attrs.tap do |attrs| + attrs[otel_semantic::CODE_FUNCTION] = 'publish' + attrs[otel_semantic::RPC_METHOD] = 'Publish' + attrs[otel_semantic::RPC_SERVICE] = service_name + attrs[otel_semantic::MESSAGING_DESTINATION_KIND] = 'topic' + attrs[otel_semantic::MESSAGING_DESTINATION] = 'TopicName' + attrs[otel_semantic::MESSAGING_SYSTEM] = 'aws.sns' + end + end + + let(:expected_stub_attrs) { stub_attrs.tap { |a| a['http.method'] = 'POST' } } + + it 'creates spans with appropriate messaging attributes' do + skip unless TestHelper.telemetry_plugin?(service_name) + + client.publish( + message: 'msg', + topic_arn: 'arn:aws:sns:fake:123:TopicName' + ) + + _(client_span.name).must_equal('SNS.Publish.TopicName.Publish') + _(client_span.kind).must_equal(:producer) + _(stub_span.name).must_equal('Handler.StubResponses') + _(stub_span.kind).must_equal(:internal) + TestHelper.match_span_attrs(expected_client_attrs, client_span, self) + TestHelper.match_span_attrs(expected_stub_attrs, stub_span, self) + _(stub_span.parent_span_id).must_equal(client_span.span_id) + end + + it 'creates a span that includes a phone number' do + # skip if using aws-sdk version before phone_number supported (v2.3.18) + skip if Gem::Version.new('2.3.18') > instrumentation_gem_version + skip unless TestHelper.telemetry_plugin?(service_name) + + client.publish(message: 'msg', phone_number: '123456') + + _(client_span.name).must_equal('SNS.Publish.phone_number.Publish') + _(client_span.attributes[otel_semantic::MESSAGING_DESTINATION]) + .must_equal('phone_number') + end + end + + describe 'SQS' do + let(:service_name) { 'SQS' } + let(:client) do + Aws::SQS::Client.new( + telemetry_provider: otel_provider, + stub_responses: true + ) + end + let(:queue_url) { 'https://sqs.us-east-1.amazonaws.com/1/QueueName' } + let(:expected_client_base_attrs) do + client_attrs.tap do |attrs| + attrs[otel_semantic::RPC_SERVICE] = service_name + attrs[otel_semantic::MESSAGING_DESTINATION_KIND] = 'queue' + attrs[otel_semantic::MESSAGING_DESTINATION] = 'QueueName' + attrs[otel_semantic::MESSAGING_SYSTEM] = 'aws.sqs' + attrs[otel_semantic::MESSAGING_URL] = queue_url + end + end + + let(:expected_stub_attrs) { stub_attrs.tap { |a| a['http.method'] = 'POST' } } + + describe '#SendMessage' do + let(:client_span) { spans.find { |s| s.name.include?('SQS.SendMessage') } } + let(:expected_client_attrs) do + expected_client_base_attrs.tap do |attrs| + attrs[otel_semantic::RPC_METHOD] = 'SendMessage' + end + end + + it 'creates spans with appropriate messaging attributes' do + skip unless TestHelper.telemetry_plugin?(service_name) + + client.send_message(message_body: 'msg', queue_url: queue_url) + + _(client_span.name).must_equal('SQS.SendMessage.QueueName.Publish') + _(client_span.kind).must_equal(:producer) + _(stub_span.name).must_equal('Handler.StubResponses') + _(stub_span.kind).must_equal(:internal) + TestHelper.match_span_attrs(expected_client_attrs, client_span, self) + TestHelper.match_span_attrs(expected_stub_attrs, stub_span, self) + _(stub_span.parent_span_id).must_equal(client_span.span_id) + end + end + + describe '#SendMessageBatch' do + let(:client_span) { spans.find { |s| s.name.include?('SQS.SendMessageBatch') } } + let(:expected_client_attrs) do + expected_client_base_attrs.tap do |attrs| + attrs[otel_semantic::RPC_METHOD] = 'SendMessageBatch' + end + end + + it 'creates spans with appropriate messaging attributes' do + skip unless TestHelper.telemetry_plugin?(service_name) + + client.send_message_batch( + queue_url: queue_url, + entries: [{ id: 'Message1', message_body: 'Body1' }] + ) + + _(client_span.name).must_equal('SQS.SendMessageBatch.QueueName.Publish') + _(client_span.kind).must_equal(:producer) + _(stub_span.name).must_equal('Handler.StubResponses') + _(stub_span.kind).must_equal(:internal) + TestHelper.match_span_attrs(expected_client_attrs, client_span, self) + TestHelper.match_span_attrs(expected_stub_attrs, stub_span, self) + _(stub_span.parent_span_id).must_equal(client_span.span_id) + end + end + + describe '#ReceiveMessage' do + let(:client_span) { spans.find { |s| s.name.include?('SQS.ReceiveMessage') } } + let(:expected_client_attrs) do + expected_client_base_attrs.tap do |attrs| + attrs[otel_semantic::RPC_METHOD] = 'ReceiveMessage' + attrs[otel_semantic::MESSAGING_OPERATION] = 'receive' + end + end + + it 'creates spans with appropriate messaging attributes' do + skip unless TestHelper.telemetry_plugin?(service_name) + + client.receive_message(queue_url: queue_url) + + _(client_span.name).must_equal('SQS.ReceiveMessage.QueueName.Receive') + _(client_span.kind).must_equal(:consumer) + _(stub_span.name).must_equal('Handler.StubResponses') + _(stub_span.kind).must_equal(:internal) + TestHelper.match_span_attrs(expected_client_attrs, client_span, self) + TestHelper.match_span_attrs(expected_stub_attrs, stub_span, self) + _(stub_span.parent_span_id).must_equal(client_span.span_id) + end + end + + describe '#GetQueueUrl' do + let(:client_span) { spans.find { |s| s.name.include?('SQS.GetQueueUrl') } } + + it 'creates a span with appropriate messaging attributes' do + skip unless TestHelper.telemetry_plugin?(service_name) + + client.get_queue_url(queue_name: 'queue-name') + + _(client_span.attributes[otel_semantic::MESSAGING_DESTINATION]).must_equal('unknown') + _(client_span.attributes).wont_include(otel_semantic::MESSAGING_URL) + end + end + end + + describe 'DynamoDB' do + let(:client) do + Aws::DynamoDB::Client.new( + telemetry_provider: otel_provider, + stub_responses: true + ) + end + let(:client_span) { TestHelper.find_span(spans, 'DynamoDB.ListTables') } + let(:client_span) { spans.find { |s| s.name == 'DynamoDB.ListTables' } } + + it 'creates a span with dynamodb-specific attribute' do + skip unless TestHelper.telemetry_plugin?('DynamoDB') + + client.list_tables + + _(client_span.attributes[otel_semantic::DB_SYSTEM]) + .must_equal('dynamodb') + end + end + end +end diff --git a/instrumentation/aws_sdk/test/test_helper.rb b/instrumentation/aws_sdk/test/test_helper.rb index 7153e99b2..b588f8c75 100644 --- a/instrumentation/aws_sdk/test/test_helper.rb +++ b/instrumentation/aws_sdk/test/test_helper.rb @@ -10,6 +10,7 @@ require 'opentelemetry-instrumentation-aws_sdk' require 'minitest/autorun' +require 'webmock/minitest' require 'rspec/mocks/minitest_integration' # global opentelemetry-sdk setup: @@ -22,3 +23,19 @@ c.use 'OpenTelemetry::Instrumentation::AwsSdk' c.add_span_processor span_processor end + +class TestHelper + class << self + def telemetry_plugin?(service) + m = ::Aws.const_get(service).const_get(:Client) + Aws.const_defined?('Plugins::Telemetry') && + m.plugins.include?(Aws::Plugins::Telemetry) + end + + def match_span_attrs(expected_attrs, span, expect) + expected_attrs.each do |key, value| + expect._(span.attributes[key]).must_equal(value) + end + end + end +end diff --git a/instrumentation/base/opentelemetry-instrumentation-base.gemspec b/instrumentation/base/opentelemetry-instrumentation-base.gemspec index 97da5f64f..4debdb6fb 100644 --- a/instrumentation/base/opentelemetry-instrumentation-base.gemspec +++ b/instrumentation/base/opentelemetry-instrumentation-base.gemspec @@ -33,8 +33,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.22.0' spec.add_development_dependency 'yard', '~> 0.9' diff --git a/instrumentation/bunny/opentelemetry-instrumentation-bunny.gemspec b/instrumentation/bunny/opentelemetry-instrumentation-bunny.gemspec index 9f94081f0..e7dab3aff 100644 --- a/instrumentation/bunny/opentelemetry-instrumentation-bunny.gemspec +++ b/instrumentation/bunny/opentelemetry-instrumentation-bunny.gemspec @@ -33,8 +33,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' spec.add_development_dependency 'yard', '~> 0.9' diff --git a/instrumentation/concurrent_ruby/opentelemetry-instrumentation-concurrent_ruby.gemspec b/instrumentation/concurrent_ruby/opentelemetry-instrumentation-concurrent_ruby.gemspec index 539887b96..1f71f3fde 100644 --- a/instrumentation/concurrent_ruby/opentelemetry-instrumentation-concurrent_ruby.gemspec +++ b/instrumentation/concurrent_ruby/opentelemetry-instrumentation-concurrent_ruby.gemspec @@ -33,8 +33,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' spec.add_development_dependency 'yard', '~> 0.9' diff --git a/instrumentation/dalli/opentelemetry-instrumentation-dalli.gemspec b/instrumentation/dalli/opentelemetry-instrumentation-dalli.gemspec index 08405e804..6803d287c 100644 --- a/instrumentation/dalli/opentelemetry-instrumentation-dalli.gemspec +++ b/instrumentation/dalli/opentelemetry-instrumentation-dalli.gemspec @@ -33,8 +33,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' spec.add_development_dependency 'yard', '~> 0.9' diff --git a/instrumentation/delayed_job/Appraisals b/instrumentation/delayed_job/Appraisals index e4d86e84f..9099f1369 100644 --- a/instrumentation/delayed_job/Appraisals +++ b/instrumentation/delayed_job/Appraisals @@ -4,18 +4,23 @@ # # SPDX-License-Identifier: Apache-2.0 -appraise 'delayed_job_4.1-rails-latest' do - gem 'activejob' +%w[6.1.0 7.0.0 7.1.0].each do |version| + appraise "delayed_job_4.1-activejob-#{version}" do + gem 'delayed_job', '~> 4.1' + gem 'activejob', "~> #{version}" + end end -appraise 'delayed_job_4.1-rails-7.1' do - gem 'activejob', '~> 7.1.0' -end - -appraise 'delayed_job_4.1-rails-7.0' do - gem 'activejob', '~> 7.0.0' -end +if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.1.0') + %w[7.2.0].each do |version| + appraise "delayed_job-4.1-activejob-#{version}" do + gem 'delayed_job', '~> 4.1' + gem 'activejob', "~> #{version}" + end + end -appraise 'delayed_job-4.1-rails-6.1' do - gem 'activejob', '~> 6.1.0' + appraise 'delayed_job-latest' do + gem 'delayed_job' + gem 'activejob' + end end diff --git a/instrumentation/delayed_job/Gemfile b/instrumentation/delayed_job/Gemfile index 3c182227f..2baf57ac4 100644 --- a/instrumentation/delayed_job/Gemfile +++ b/instrumentation/delayed_job/Gemfile @@ -9,6 +9,5 @@ source 'https://rubygems.org' gemspec group :test do - gem 'delayed_job', '~> 4.1' gem 'opentelemetry-instrumentation-base', path: '../base' end diff --git a/instrumentation/delayed_job/opentelemetry-instrumentation-delayed_job.gemspec b/instrumentation/delayed_job/opentelemetry-instrumentation-delayed_job.gemspec index 8007aec82..c92d19f0b 100644 --- a/instrumentation/delayed_job/opentelemetry-instrumentation-delayed_job.gemspec +++ b/instrumentation/delayed_job/opentelemetry-instrumentation-delayed_job.gemspec @@ -34,11 +34,11 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rspec-mocks' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' spec.add_development_dependency 'sqlite3' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/ethon/lib/opentelemetry/instrumentation/ethon/patches/easy.rb b/instrumentation/ethon/lib/opentelemetry/instrumentation/ethon/patches/easy.rb index 74791818e..7850ac565 100644 --- a/instrumentation/ethon/lib/opentelemetry/instrumentation/ethon/patches/easy.rb +++ b/instrumentation/ethon/lib/opentelemetry/instrumentation/ethon/patches/easy.rb @@ -16,6 +16,9 @@ module Easy end HTTP_METHODS_TO_SPAN_NAMES = Hash.new { |h, k| h[k] = "HTTP #{k}" } + # Constant for the HTTP status range + HTTP_STATUS_SUCCESS_RANGE = (100..399) + def http_request(url, action_name, options = {}) @otel_method = ACTION_NAMES_TO_HTTP_METHODS[action_name] super @@ -42,7 +45,7 @@ def complete @otel_span.status = OpenTelemetry::Trace::Status.error("Request has failed: #{message}") else @otel_span.set_attribute('http.status_code', response_code) - @otel_span.status = OpenTelemetry::Trace::Status.error unless (100..399).cover?(response_code.to_i) + @otel_span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(response_code.to_i) end ensure @otel_span&.finish diff --git a/instrumentation/ethon/opentelemetry-instrumentation-ethon.gemspec b/instrumentation/ethon/opentelemetry-instrumentation-ethon.gemspec index b5b90f5d4..5dfa222ae 100644 --- a/instrumentation/ethon/opentelemetry-instrumentation-ethon.gemspec +++ b/instrumentation/ethon/opentelemetry-instrumentation-ethon.gemspec @@ -33,8 +33,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' spec.add_development_dependency 'yard', '~> 0.9' diff --git a/instrumentation/excon/lib/opentelemetry/instrumentation/excon/middlewares/tracer_middleware.rb b/instrumentation/excon/lib/opentelemetry/instrumentation/excon/middlewares/tracer_middleware.rb index 592fdb793..b17bfc662 100644 --- a/instrumentation/excon/lib/opentelemetry/instrumentation/excon/middlewares/tracer_middleware.rb +++ b/instrumentation/excon/lib/opentelemetry/instrumentation/excon/middlewares/tracer_middleware.rb @@ -21,11 +21,13 @@ class TracerMiddleware < ::Excon::Middleware::Base hash[uppercase_method] ||= "HTTP #{uppercase_method}" end.freeze + # Constant for the HTTP status range + HTTP_STATUS_SUCCESS_RANGE = (100..399) + def request_call(datum) return @stack.request_call(datum) if untraced?(datum) http_method = HTTP_METHODS_TO_UPPERCASE[datum[:method]] - attributes = { OpenTelemetry::SemanticConventions::Trace::HTTP_HOST => datum[:host], OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => http_method, @@ -35,19 +37,14 @@ def request_call(datum) OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => datum[:hostname], OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => datum[:port] } - peer_service = Excon::Instrumentation.instance.config[:peer_service] attributes[OpenTelemetry::SemanticConventions::Trace::PEER_SERVICE] = peer_service if peer_service attributes.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) - span = tracer.start_span(HTTP_METHODS_TO_SPAN_NAMES[http_method], attributes: attributes, kind: :client) ctx = OpenTelemetry::Trace.context_with_span(span) - datum[:otel_span] = span datum[:otel_token] = OpenTelemetry::Context.attach(ctx) - OpenTelemetry.propagation.inject(datum[:headers]) - @stack.request_call(datum) end @@ -68,7 +65,6 @@ def self.around_default_stack # If the default stack contains a version of the trace middleware already... existing_trace_middleware = default_stack.find { |m| m <= TracerMiddleware } default_stack.delete(existing_trace_middleware) if existing_trace_middleware - # Inject after the ResponseParser middleware response_middleware_index = default_stack.index(::Excon::Middleware::ResponseParser).to_i default_stack.insert(response_middleware_index + 1, self) @@ -84,7 +80,7 @@ def handle_response(datum) if datum.key?(:response) response = datum[:response] span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, response[:status]) - span.status = OpenTelemetry::Trace::Status.error unless (100..399).cover?(response[:status].to_i) + span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(response[:status].to_i) end if datum.key?(:error) @@ -93,7 +89,6 @@ def handle_response(datum) end span.finish - OpenTelemetry::Context.detach(datum.delete(:otel_token)) if datum.include?(:otel_token) end rescue StandardError => e diff --git a/instrumentation/excon/opentelemetry-instrumentation-excon.gemspec b/instrumentation/excon/opentelemetry-instrumentation-excon.gemspec index 18c3f82ba..3373aa8a2 100644 --- a/instrumentation/excon/opentelemetry-instrumentation-excon.gemspec +++ b/instrumentation/excon/opentelemetry-instrumentation-excon.gemspec @@ -33,10 +33,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/faraday/lib/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware.rb b/instrumentation/faraday/lib/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware.rb index 1b4452ac3..981e44e26 100644 --- a/instrumentation/faraday/lib/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware.rb +++ b/instrumentation/faraday/lib/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware.rb @@ -9,7 +9,7 @@ module Instrumentation module Faraday module Middlewares # TracerMiddleware propagates context and instruments Faraday requests - # by way of its middlware system + # by way of its middleware system class TracerMiddleware < ::Faraday::Middleware HTTP_METHODS_SYMBOL_TO_STRING = { connect: 'CONNECT', @@ -23,6 +23,9 @@ class TracerMiddleware < ::Faraday::Middleware trace: 'TRACE' }.freeze + # Constant for the HTTP status range + HTTP_STATUS_SUCCESS_RANGE = (100..399) + def call(env) http_method = HTTP_METHODS_SYMBOL_TO_STRING[env.method] config = Faraday::Instrumentation.instance.config @@ -68,7 +71,7 @@ def tracer def trace_response(span, status) span.set_attribute('http.status_code', status) - span.status = OpenTelemetry::Trace::Status.error unless (100..399).cover?(status.to_i) + span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(status.to_i) end end end diff --git a/instrumentation/faraday/opentelemetry-instrumentation-faraday.gemspec b/instrumentation/faraday/opentelemetry-instrumentation-faraday.gemspec index f08ff6576..c74bfc26b 100644 --- a/instrumentation/faraday/opentelemetry-instrumentation-faraday.gemspec +++ b/instrumentation/faraday/opentelemetry-instrumentation-faraday.gemspec @@ -33,10 +33,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/grape/opentelemetry-instrumentation-grape.gemspec b/instrumentation/grape/opentelemetry-instrumentation-grape.gemspec index 86306cddb..3ee053af9 100644 --- a/instrumentation/grape/opentelemetry-instrumentation-grape.gemspec +++ b/instrumentation/grape/opentelemetry-instrumentation-grape.gemspec @@ -38,10 +38,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'rack-test' spec.add_development_dependency 'rake', '~> 13.0' spec.add_development_dependency 'rspec-mocks' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/graphql/opentelemetry-instrumentation-graphql.gemspec b/instrumentation/graphql/opentelemetry-instrumentation-graphql.gemspec index 36aec82c3..cbce4c52a 100644 --- a/instrumentation/graphql/opentelemetry-instrumentation-graphql.gemspec +++ b/instrumentation/graphql/opentelemetry-instrumentation-graphql.gemspec @@ -34,10 +34,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/gruf/opentelemetry-instrumentation-gruf.gemspec b/instrumentation/gruf/opentelemetry-instrumentation-gruf.gemspec index bff04dd3e..a7b95ea1e 100644 --- a/instrumentation/gruf/opentelemetry-instrumentation-gruf.gemspec +++ b/instrumentation/gruf/opentelemetry-instrumentation-gruf.gemspec @@ -35,10 +35,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-sdk', '~> 1.0' spec.add_development_dependency 'opentelemetry-test-helpers' spec.add_development_dependency 'rake', '~> 12.3.3' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/client.rb b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/client.rb index f814e1a65..1d98cb5c1 100644 --- a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/client.rb +++ b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/client.rb @@ -10,6 +10,9 @@ module HTTP module Patches # Module to prepend to HTTP::Client for instrumentation module Client + # Constant for the HTTP status range + HTTP_STATUS_SUCCESS_RANGE = (100..399) + def perform(req, options) uri = req.uri request_method = req.verb.to_s.upcase @@ -43,7 +46,7 @@ def annotate_span_with_response!(span, response) status_code = response.status.to_i span.set_attribute('http.status_code', status_code) - span.status = OpenTelemetry::Trace::Status.error unless (100..399).cover?(status_code.to_i) + span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(status_code) end def create_request_span_name(request_method, request_path) diff --git a/instrumentation/http/opentelemetry-instrumentation-http.gemspec b/instrumentation/http/opentelemetry-instrumentation-http.gemspec index 54069ff29..cee534cc9 100644 --- a/instrumentation/http/opentelemetry-instrumentation-http.gemspec +++ b/instrumentation/http/opentelemetry-instrumentation-http.gemspec @@ -35,10 +35,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rake', '~> 13.0' spec.add_development_dependency 'rspec-mocks' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/http_client/lib/opentelemetry/instrumentation/http_client/patches/client.rb b/instrumentation/http_client/lib/opentelemetry/instrumentation/http_client/patches/client.rb index a71c8ad7b..46ad72142 100644 --- a/instrumentation/http_client/lib/opentelemetry/instrumentation/http_client/patches/client.rb +++ b/instrumentation/http_client/lib/opentelemetry/instrumentation/http_client/patches/client.rb @@ -10,6 +10,9 @@ module HttpClient module Patches # Module to prepend to HTTPClient for instrumentation module Client + # Constant for the HTTP status range + HTTP_STATUS_SUCCESS_RANGE = (100..399) + private def do_get_block(req, proxy, conn, &block) @@ -42,7 +45,7 @@ def annotate_span_with_response!(span, response) status_code = response.status_code.to_i span.set_attribute('http.status_code', status_code) - span.status = OpenTelemetry::Trace::Status.error unless (100..399).cover?(status_code.to_i) + span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(status_code) end def tracer diff --git a/instrumentation/http_client/opentelemetry-instrumentation-http_client.gemspec b/instrumentation/http_client/opentelemetry-instrumentation-http_client.gemspec index 98a0a1170..99c056b80 100644 --- a/instrumentation/http_client/opentelemetry-instrumentation-http_client.gemspec +++ b/instrumentation/http_client/opentelemetry-instrumentation-http_client.gemspec @@ -34,10 +34,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/httpx/lib/opentelemetry/instrumentation/httpx/plugin.rb b/instrumentation/httpx/lib/opentelemetry/instrumentation/httpx/plugin.rb index 137fca976..2635a39e6 100644 --- a/instrumentation/httpx/lib/opentelemetry/instrumentation/httpx/plugin.rb +++ b/instrumentation/httpx/lib/opentelemetry/instrumentation/httpx/plugin.rb @@ -11,6 +11,9 @@ module Plugin # Instruments around HTTPX's request/response lifecycle in order to generate # an OTEL trace. class RequestTracer + # Constant for the HTTP status range + HTTP_STATUS_SUCCESS_RANGE = (100..399) + def initialize(request) @request = request end @@ -54,7 +57,7 @@ def finish(response) @span.status = Trace::Status.error("Unhandled exception of type: #{response.error.class}") else @span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, response.status) - @span.status = Trace::Status.error unless (100..399).cover?(response.status) + @span.status = Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(response.status) end OpenTelemetry::Context.detach(@trace_token) if @trace_token diff --git a/instrumentation/httpx/opentelemetry-instrumentation-httpx.gemspec b/instrumentation/httpx/opentelemetry-instrumentation-httpx.gemspec index b2f48305a..d285bad81 100644 --- a/instrumentation/httpx/opentelemetry-instrumentation-httpx.gemspec +++ b/instrumentation/httpx/opentelemetry-instrumentation-httpx.gemspec @@ -35,10 +35,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rake', '~> 13.0' spec.add_development_dependency 'rspec-mocks' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/koala/opentelemetry-instrumentation-koala.gemspec b/instrumentation/koala/opentelemetry-instrumentation-koala.gemspec index 75d1d574e..7e95f6392 100644 --- a/instrumentation/koala/opentelemetry-instrumentation-koala.gemspec +++ b/instrumentation/koala/opentelemetry-instrumentation-koala.gemspec @@ -35,10 +35,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rake', '~> 13.0' spec.add_development_dependency 'rspec-mocks' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/lmdb/opentelemetry-instrumentation-lmdb.gemspec b/instrumentation/lmdb/opentelemetry-instrumentation-lmdb.gemspec index 7a59efcaa..535a9994e 100644 --- a/instrumentation/lmdb/opentelemetry-instrumentation-lmdb.gemspec +++ b/instrumentation/lmdb/opentelemetry-instrumentation-lmdb.gemspec @@ -34,10 +34,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/mongo/opentelemetry-instrumentation-mongo.gemspec b/instrumentation/mongo/opentelemetry-instrumentation-mongo.gemspec index f981355e7..b1831edd6 100644 --- a/instrumentation/mongo/opentelemetry-instrumentation-mongo.gemspec +++ b/instrumentation/mongo/opentelemetry-instrumentation-mongo.gemspec @@ -36,10 +36,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'pry' spec.add_development_dependency 'pry-byebug' unless RUBY_ENGINE == 'jruby' spec.add_development_dependency 'rspec-mocks' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/mysql2/opentelemetry-instrumentation-mysql2.gemspec b/instrumentation/mysql2/opentelemetry-instrumentation-mysql2.gemspec index 8a3124f0f..31d521db1 100644 --- a/instrumentation/mysql2/opentelemetry-instrumentation-mysql2.gemspec +++ b/instrumentation/mysql2/opentelemetry-instrumentation-mysql2.gemspec @@ -37,8 +37,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'pry' spec.add_development_dependency 'pry-byebug' unless RUBY_ENGINE == 'jruby' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' spec.add_development_dependency 'yard', '~> 0.9' diff --git a/instrumentation/net_http/lib/opentelemetry/instrumentation/net/http/patches/instrumentation.rb b/instrumentation/net_http/lib/opentelemetry/instrumentation/net/http/patches/instrumentation.rb index 725d4c546..6cdbfdb2b 100644 --- a/instrumentation/net_http/lib/opentelemetry/instrumentation/net/http/patches/instrumentation.rb +++ b/instrumentation/net_http/lib/opentelemetry/instrumentation/net/http/patches/instrumentation.rb @@ -14,6 +14,9 @@ module Instrumentation HTTP_METHODS_TO_SPAN_NAMES = Hash.new { |h, k| h[k] = "HTTP #{k}" } USE_SSL_TO_SCHEME = { false => 'http', true => 'https' }.freeze + # Constant for the HTTP status range + HTTP_STATUS_SUCCESS_RANGE = (100..399) + def request(req, body = nil, &block) # Do not trace recursive call for starting the connection return super unless started? @@ -78,7 +81,7 @@ def annotate_span_with_response!(span, response) status_code = response.code.to_i span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, status_code) - span.status = OpenTelemetry::Trace::Status.error unless (100..399).cover?(status_code.to_i) + span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(status_code) end def tracer diff --git a/instrumentation/net_http/opentelemetry-instrumentation-net_http.gemspec b/instrumentation/net_http/opentelemetry-instrumentation-net_http.gemspec index c0d4f4857..e557f72a4 100644 --- a/instrumentation/net_http/opentelemetry-instrumentation-net_http.gemspec +++ b/instrumentation/net_http/opentelemetry-instrumentation-net_http.gemspec @@ -34,10 +34,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rake', '~> 13.0.1' spec.add_development_dependency 'rspec-mocks' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/pg/lib/opentelemetry/instrumentation/pg/patches/connection.rb b/instrumentation/pg/lib/opentelemetry/instrumentation/pg/patches/connection.rb index 98814950b..a40da7cd7 100644 --- a/instrumentation/pg/lib/opentelemetry/instrumentation/pg/patches/connection.rb +++ b/instrumentation/pg/lib/opentelemetry/instrumentation/pg/patches/connection.rb @@ -15,7 +15,7 @@ module Patches # Module to prepend to PG::Connection for instrumentation module Connection # rubocop:disable Metrics/ModuleLength # Capture the first word (including letters, digits, underscores, & '.', ) that follows common table commands - TABLE_NAME = /\b(?:FROM|INTO|UPDATE|CREATE\s+TABLE(?:\s+IF\s+NOT\s+EXISTS)?|DROP\s+TABLE(?:\s+IF\s+EXISTS)?|ALTER\s+TABLE(?:\s+IF\s+EXISTS)?)\s+([\w\.]+)/i + TABLE_NAME = /\b(?:FROM|INTO|UPDATE|CREATE\s+TABLE(?:\s+IF\s+NOT\s+EXISTS)?|DROP\s+TABLE(?:\s+IF\s+EXISTS)?|ALTER\s+TABLE(?:\s+IF\s+EXISTS)?)\s+["]?([\w\.]+)["]?/i PG::Constants::EXEC_ISH_METHODS.each do |method| define_method method do |*args, &block| diff --git a/instrumentation/pg/opentelemetry-instrumentation-pg.gemspec b/instrumentation/pg/opentelemetry-instrumentation-pg.gemspec index 29feea416..dd985d2e0 100644 --- a/instrumentation/pg/opentelemetry-instrumentation-pg.gemspec +++ b/instrumentation/pg/opentelemetry-instrumentation-pg.gemspec @@ -37,8 +37,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'pry' spec.add_development_dependency 'pry-byebug' unless RUBY_ENGINE == 'jruby' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' spec.add_development_dependency 'yard', '~> 0.9' diff --git a/instrumentation/pg/test/fixtures/sql_table_name.json b/instrumentation/pg/test/fixtures/sql_table_name.json index eacd9571f..7cf96681f 100644 --- a/instrumentation/pg/test/fixtures/sql_table_name.json +++ b/instrumentation/pg/test/fixtures/sql_table_name.json @@ -50,5 +50,9 @@ { "name": "from_with_join", "sql": "SELECT columns FROM test_table JOIN table2 ON test_table.column = table2.column" + }, + { + "name": "table_name_with_double_quotes", + "sql": "SELECT columns FROM \"test_table\"" } - ] \ No newline at end of file +] diff --git a/instrumentation/que/CHANGELOG.md b/instrumentation/que/CHANGELOG.md index d77e66d0f..e9cff0dfd 100644 --- a/instrumentation/que/CHANGELOG.md +++ b/instrumentation/que/CHANGELOG.md @@ -1,5 +1,9 @@ # Release History: opentelemetry-instrumentation-que +### v0.8.4 / 2024-10-08 + +* FIXED: Fix bulk_enqueue when enqueuing more than 5 jobs + ### v0.8.3 / 2024-07-23 * DOCS: Add cspell to CI diff --git a/instrumentation/que/lib/opentelemetry/instrumentation/que/patches/que_job.rb b/instrumentation/que/lib/opentelemetry/instrumentation/que/patches/que_job.rb index 5be898984..a189f5aee 100644 --- a/instrumentation/que/lib/opentelemetry/instrumentation/que/patches/que_job.rb +++ b/instrumentation/que/lib/opentelemetry/instrumentation/que/patches/que_job.rb @@ -19,6 +19,10 @@ class << base # Module to prepend to Que singleton class module ClassMethods def enqueue(*args, job_options: {}, **arg_opts) + # In Que version 2.1.0 `bulk_enqueue` was introduced. + # In that case, the span is created inside the `bulk_enqueue` method. + return super(*args, **arg_opts) if gem_version >= Gem::Version.new('2.1.0') && Thread.current[:que_jobs_to_bulk_insert] + tracer = Que::Instrumentation.instance.tracer otel_config = Que::Instrumentation.instance.config @@ -43,19 +47,8 @@ def enqueue(*args, job_options: {}, **arg_opts) OpenTelemetry.propagation.inject(tags, setter: TagSetter) end - # In Que version 2.1.0 `bulk_enqueue` was introduced and in order - # for it to work, we must pass `job_options` to `bulk_enqueue` instead of enqueue. - if gem_version >= Gem::Version.new('2.1.0') && Thread.current[:que_jobs_to_bulk_insert] - Thread.current[:que_jobs_to_bulk_insert][:job_options] = Thread.current[:que_jobs_to_bulk_insert][:job_options]&.merge(tags: tags) do |_, a, b| - a.is_a?(Array) && b.is_a?(Array) ? a.concat(b) : b - end - - job = super(*args, **arg_opts) - job_attrs = Thread.current[:que_jobs_to_bulk_insert][:jobs_attrs].last - else - job = super(*args, job_options: job_options.merge(tags: tags), **arg_opts) - job_attrs = job.que_attrs - end + job = super(*args, job_options: job_options.merge(tags: tags), **arg_opts) + job_attrs = job.que_attrs span.name = "#{job_attrs[:job_class]} publish" span.add_attributes(QueJob.job_attributes(job_attrs)) @@ -67,6 +60,32 @@ def enqueue(*args, job_options: {}, **arg_opts) def gem_version @gem_version ||= Gem.loaded_specs['que'].version end + + if Gem.loaded_specs['que'].version >= Gem::Version.new('2.1.0') + def bulk_enqueue(**_kwargs, &block) + tracer = Que::Instrumentation.instance.tracer + otel_config = Que::Instrumentation.instance.config + + tracer.in_span('publish', kind: :producer) do |span| + super do + yield + + job_attrs = Thread.current[:que_jobs_to_bulk_insert][:jobs_attrs] + + unless job_attrs.empty? + span.name = "#{job_attrs.first[:job_class]} publish" + span.add_attributes(QueJob.job_attributes(job_attrs.first)) + end + + if otel_config[:propagation_style] != :none + job_options = Thread.current[:que_jobs_to_bulk_insert][:job_options] + job_options[:tags] ||= [] + OpenTelemetry.propagation.inject(job_options[:tags], setter: TagSetter) + end + end + end + end + end end def self.job_attributes(job_attrs) diff --git a/instrumentation/que/lib/opentelemetry/instrumentation/que/version.rb b/instrumentation/que/lib/opentelemetry/instrumentation/que/version.rb index eaa4552b6..964554f5d 100644 --- a/instrumentation/que/lib/opentelemetry/instrumentation/que/version.rb +++ b/instrumentation/que/lib/opentelemetry/instrumentation/que/version.rb @@ -7,7 +7,7 @@ module OpenTelemetry module Instrumentation module Que - VERSION = '0.8.3' + VERSION = '0.8.4' end end end diff --git a/instrumentation/que/opentelemetry-instrumentation-que.gemspec b/instrumentation/que/opentelemetry-instrumentation-que.gemspec index 5fa8dfcfb..d9599515d 100644 --- a/instrumentation/que/opentelemetry-instrumentation-que.gemspec +++ b/instrumentation/que/opentelemetry-instrumentation-que.gemspec @@ -34,8 +34,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' spec.add_development_dependency 'yard', '~> 0.9' diff --git a/instrumentation/que/test/opentelemetry/instrumentation/que_test.rb b/instrumentation/que/test/opentelemetry/instrumentation/que_test.rb index 9ec9847c1..7222e82cd 100644 --- a/instrumentation/que/test/opentelemetry/instrumentation/que_test.rb +++ b/instrumentation/que/test/opentelemetry/instrumentation/que_test.rb @@ -304,6 +304,74 @@ def self.run(first, second); end end end + describe 'enqueueing multiple jobs' do + it 'creates a span' do + Que.bulk_enqueue do + 10.times { TestJobAsync.enqueue } + end + + _(finished_spans.size).must_equal(1) + + span = finished_spans.last + _(span.kind).must_equal(:producer) + end + + it 'names the created span' do + Que.bulk_enqueue do + 10.times { TestJobAsync.enqueue } + end + + span = finished_spans.last + _(span.name).must_equal('TestJobAsync publish') + end + + it 'links spans together' do + bulk_jobs = Que.bulk_enqueue do + 10.times { TestJobAsync.enqueue } + end + + bulk_jobs.each { |job| Que.run_job_middleware(job) { job.tap(&:_run) } } + + _(finished_spans.size).must_equal(11) + + publish_span = finished_spans.first + + process_spans = finished_spans.drop(1) + + process_spans.each do |process_span| + _(publish_span.trace_id).wont_equal(process_span.trace_id) + + _(process_span.total_recorded_links).must_equal(1) + _(process_span.links[0].span_context.trace_id).must_equal(publish_span.trace_id) + _(process_span.links[0].span_context.span_id).must_equal(publish_span.span_id) + end + end + + it 'records attributes' do + Que.bulk_enqueue do + 10.times { TestJobAsync.enqueue } + end + + attributes = finished_spans.last.attributes + _(attributes['messaging.system']).must_equal('que') + _(attributes['messaging.destination']).must_equal('default') + _(attributes['messaging.destination_kind']).must_equal('queue') + _(attributes['messaging.operation']).must_equal('publish') + _(attributes['messaging.que.job_class']).must_equal('TestJobAsync') + _(attributes['messaging.que.priority']).must_equal(100) + _(attributes.key?('messaging.message_id')).must_equal(false) + end + end + + describe 'enqueueing zero jobs' do + it 'creates a span' do + Que.bulk_enqueue do + end + + _(finished_spans.size).must_equal(1) + end + end + describe 'processing a job' do before do bulk_job = Que.bulk_enqueue do @@ -363,10 +431,10 @@ def self.run(first, second); end _(finished_spans.size).must_equal(2) - span1 = finished_spans.first + span1 = finished_spans.last _(span1.kind).must_equal(:producer) - span2 = finished_spans.last + span2 = finished_spans.first _(span2.kind).must_equal(:consumer) end @@ -375,10 +443,10 @@ def self.run(first, second); end TestJobSync.enqueue end - span1 = finished_spans.first + span1 = finished_spans.last _(span1.name).must_equal('TestJobSync publish') - span2 = finished_spans.last + span2 = finished_spans.first _(span2.name).must_equal('TestJobSync process') end @@ -387,7 +455,7 @@ def self.run(first, second); end TestJobSync.enqueue end - attributes = finished_spans.last.attributes + attributes = finished_spans.first.attributes _(attributes['messaging.system']).must_equal('que') _(attributes['messaging.destination']).must_equal('default') _(attributes['messaging.destination_kind']).must_equal('queue') diff --git a/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec b/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec index ce4aceae2..842597e02 100644 --- a/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec +++ b/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec @@ -35,10 +35,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rake', '~> 13.0' spec.add_development_dependency 'rspec-mocks' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/rack/CHANGELOG.md b/instrumentation/rack/CHANGELOG.md index 2f82b82fa..7fa9fe445 100644 --- a/instrumentation/rack/CHANGELOG.md +++ b/instrumentation/rack/CHANGELOG.md @@ -1,5 +1,9 @@ # Release History: opentelemetry-instrumentation-rack +### v0.25.0 / 2024-10-23 + +* ADDED: Set span error only for 5xx response range + ### v0.24.6 / 2024-07-23 * DOCS: Add cspell to CI diff --git a/instrumentation/rack/lib/opentelemetry/instrumentation/rack/middlewares/event_handler.rb b/instrumentation/rack/lib/opentelemetry/instrumentation/rack/middlewares/event_handler.rb index 5475a4fc5..a77448cb7 100644 --- a/instrumentation/rack/lib/opentelemetry/instrumentation/rack/middlewares/event_handler.rb +++ b/instrumentation/rack/lib/opentelemetry/instrumentation/rack/middlewares/event_handler.rb @@ -43,7 +43,6 @@ class EventHandler include ::Rack::Events::Abstract OTEL_TOKEN_AND_SPAN = 'otel.rack.token_and_span' - GOOD_HTTP_STATUSES = (100..499) # Creates a server span for this current request using the incoming parent context # and registers them as the {current_span} @@ -208,7 +207,7 @@ def detach_context(request) end def add_response_attributes(span, response) - span.status = OpenTelemetry::Trace::Status.error unless GOOD_HTTP_STATUSES.include?(response.status.to_i) + span.status = OpenTelemetry::Trace::Status.error if response.server_error? attributes = extract_response_attributes(response) span.add_attributes(attributes) rescue StandardError => e diff --git a/instrumentation/rack/lib/opentelemetry/instrumentation/rack/middlewares/tracer_middleware.rb b/instrumentation/rack/lib/opentelemetry/instrumentation/rack/middlewares/tracer_middleware.rb index 608728ac6..e6aceba7d 100644 --- a/instrumentation/rack/lib/opentelemetry/instrumentation/rack/middlewares/tracer_middleware.rb +++ b/instrumentation/rack/lib/opentelemetry/instrumentation/rack/middlewares/tracer_middleware.rb @@ -152,7 +152,7 @@ def create_request_span_name(request_uri_or_path_info, env) end def set_attributes_after_request(span, status, headers, _response) - span.status = OpenTelemetry::Trace::Status.error unless (100..499).cover?(status.to_i) + span.status = OpenTelemetry::Trace::Status.error if (500..599).cover?(status.to_i) span.set_attribute('http.status_code', status) # NOTE: if data is available, it would be good to do this: diff --git a/instrumentation/rack/lib/opentelemetry/instrumentation/rack/version.rb b/instrumentation/rack/lib/opentelemetry/instrumentation/rack/version.rb index f958c372f..50e682692 100644 --- a/instrumentation/rack/lib/opentelemetry/instrumentation/rack/version.rb +++ b/instrumentation/rack/lib/opentelemetry/instrumentation/rack/version.rb @@ -7,7 +7,7 @@ module OpenTelemetry module Instrumentation module Rack - VERSION = '0.24.6' + VERSION = '0.25.0' end end end diff --git a/instrumentation/rack/opentelemetry-instrumentation-rack.gemspec b/instrumentation/rack/opentelemetry-instrumentation-rack.gemspec index 7ecebeb6b..5f04dbca3 100644 --- a/instrumentation/rack/opentelemetry-instrumentation-rack.gemspec +++ b/instrumentation/rack/opentelemetry-instrumentation-rack.gemspec @@ -36,10 +36,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rake', '~> 13.0' spec.add_development_dependency 'rspec-mocks' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/rack/test/opentelemetry/instrumentation/rack/middlewares/event_handler_test.rb b/instrumentation/rack/test/opentelemetry/instrumentation/rack/middlewares/event_handler_test.rb index b106a5d0d..afb254bca 100644 --- a/instrumentation/rack/test/opentelemetry/instrumentation/rack/middlewares/event_handler_test.rb +++ b/instrumentation/rack/test/opentelemetry/instrumentation/rack/middlewares/event_handler_test.rb @@ -105,6 +105,19 @@ _(proxy_event).must_be_nil end + describe 'with a hijacked response' do + let(:service) do + lambda do |env| + env['rack.hijack?'] = true + [-1, {}, []] + end + end + + it 'sets the span status to "unset"' do + _(rack_span.status.code).must_equal OpenTelemetry::Trace::Status::UNSET + end + end + describe 'when baggage is set' do let(:headers) do Hash( diff --git a/instrumentation/rack/test/opentelemetry/instrumentation/rack/middlewares/tracer_middleware_test.rb b/instrumentation/rack/test/opentelemetry/instrumentation/rack/middlewares/tracer_middleware_test.rb index 89c68c328..b17f60ed9 100644 --- a/instrumentation/rack/test/opentelemetry/instrumentation/rack/middlewares/tracer_middleware_test.rb +++ b/instrumentation/rack/test/opentelemetry/instrumentation/rack/middlewares/tracer_middleware_test.rb @@ -72,6 +72,19 @@ _(first_span.status.code).must_equal OpenTelemetry::Trace::Status::UNSET end + describe 'with a hijacked response' do + let(:app) do + lambda do |env| + env['rack.hijack?'] = true + [-1, {}, []] + end + end + + it 'sets the span status to "unset"' do + _(first_span.status.code).must_equal OpenTelemetry::Trace::Status::UNSET + end + end + it 'has no parent' do _(first_span.parent_span_id).must_equal OpenTelemetry::Trace::INVALID_SPAN_ID end diff --git a/instrumentation/rails/Appraisals b/instrumentation/rails/Appraisals index e6c48d017..2f466100e 100644 --- a/instrumentation/rails/Appraisals +++ b/instrumentation/rails/Appraisals @@ -4,20 +4,20 @@ # # SPDX-License-Identifier: Apache-2.0 -appraise 'rails-6.1' do - gem 'rails', '~> 6.1.0' -end - -appraise 'rails-7.0' do - gem 'rails', '~> 7.0.0' -end - -appraise 'rails-7.1' do - gem 'rails', '~> 7.1.0' +%w[6.1.0 7.0.0 7.1.0].each do |version| + appraise "rails-#{version}" do + gem 'rails', "~> #{version}" + end end if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.1.0') - appraise 'rails-7.2' do - gem 'rails', '~> 7.2.0' + %w[7.2.0].each do |version| + appraise "rails-#{version}" do + gem 'rails', "~> #{version}" + end + end + + appraise 'rails-latest' do + gem 'rails' end end diff --git a/instrumentation/rails/CHANGELOG.md b/instrumentation/rails/CHANGELOG.md index f3a462ef8..bffd8095d 100644 --- a/instrumentation/rails/CHANGELOG.md +++ b/instrumentation/rails/CHANGELOG.md @@ -1,5 +1,15 @@ # Release History: opentelemetry-instrumentation-rails +### v0.33.0 / 2024-11-19 + +* ADDED: Use Semconv Naming For ActionPack + +### v0.32.0 / 2024-10-22 + +* BREAKING CHANGE: Rename Active Record find_by_sql spans to query +* FIXED: Emit Active Record query spans for Rails 7.0+ +* ADDED: Subscribe to process.action_mailer notifications + ### v0.31.2 / 2024-08-15 * FIXED: Rails instrumentation should load ActiveJob instrumentation diff --git a/instrumentation/rails/Gemfile b/instrumentation/rails/Gemfile index 198c4eff8..2c08ce501 100644 --- a/instrumentation/rails/Gemfile +++ b/instrumentation/rails/Gemfile @@ -11,10 +11,11 @@ gemspec group :test, :development do gem 'pry-byebug' gem 'opentelemetry-instrumentation-base', path: '../base' - gem 'opentelemetry-instrumentation-action_pack', path: '../action_pack' - gem 'opentelemetry-instrumentation-action_view', path: '../action_view' gem 'opentelemetry-instrumentation-active_job', path: '../active_job' + gem 'opentelemetry-instrumentation-action_mailer', path: '../action_mailer' + gem 'opentelemetry-instrumentation-action_pack', path: '../action_pack' gem 'opentelemetry-instrumentation-active_record', path: '../active_record' gem 'opentelemetry-instrumentation-active_support', path: '../active_support' + gem 'opentelemetry-instrumentation-action_view', path: '../action_view' gem 'opentelemetry-instrumentation-rack', path: '../rack' end diff --git a/instrumentation/rails/lib/opentelemetry/instrumentation/rails/version.rb b/instrumentation/rails/lib/opentelemetry/instrumentation/rails/version.rb index 490c785c4..aa88ce3c9 100644 --- a/instrumentation/rails/lib/opentelemetry/instrumentation/rails/version.rb +++ b/instrumentation/rails/lib/opentelemetry/instrumentation/rails/version.rb @@ -7,7 +7,7 @@ module OpenTelemetry module Instrumentation module Rails - VERSION = '0.31.2' + VERSION = '0.33.0' end end end diff --git a/instrumentation/rails/opentelemetry-instrumentation-rails.gemspec b/instrumentation/rails/opentelemetry-instrumentation-rails.gemspec index e8db79ecf..0328a44ae 100644 --- a/instrumentation/rails/opentelemetry-instrumentation-rails.gemspec +++ b/instrumentation/rails/opentelemetry-instrumentation-rails.gemspec @@ -26,11 +26,11 @@ Gem::Specification.new do |spec| spec.required_ruby_version = '>= 3.0' spec.add_dependency 'opentelemetry-api', '~> 1.0' - spec.add_dependency 'opentelemetry-instrumentation-action_mailer', '~> 0.1.0' - spec.add_dependency 'opentelemetry-instrumentation-action_pack', '~> 0.9.0' + spec.add_dependency 'opentelemetry-instrumentation-action_mailer', '~> 0.2.0' + spec.add_dependency 'opentelemetry-instrumentation-action_pack', '~> 0.10.0' spec.add_dependency 'opentelemetry-instrumentation-action_view', '~> 0.7.0' spec.add_dependency 'opentelemetry-instrumentation-active_job', '~> 0.7.0' - spec.add_dependency 'opentelemetry-instrumentation-active_record', '~> 0.7.0' + spec.add_dependency 'opentelemetry-instrumentation-active_record', '~> 0.8.0' spec.add_dependency 'opentelemetry-instrumentation-active_support', '~> 0.6.0' spec.add_dependency 'opentelemetry-instrumentation-base', '~> 0.22.1' @@ -41,10 +41,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rack-test', '~> 2.1.0' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.22.0' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' spec.metadata['source_code_uri'] = 'https://github.com/open-telemetry/opentelemetry-ruby-contrib/tree/main/instrumentation/rails' if spec.respond_to?(:metadata) diff --git a/instrumentation/rails/test/instrumentation/opentelemetry/instrumentation/rails/patches/action_controller/metal_test.rb b/instrumentation/rails/test/instrumentation/opentelemetry/instrumentation/rails/patches/action_controller/metal_test.rb index aa34213d2..731d4fead 100644 --- a/instrumentation/rails/test/instrumentation/opentelemetry/instrumentation/rails/patches/action_controller/metal_test.rb +++ b/instrumentation/rails/test/instrumentation/opentelemetry/instrumentation/rails/patches/action_controller/metal_test.rb @@ -12,17 +12,17 @@ let(:exporter) { EXPORTER } let(:spans) { exporter.finished_spans } let(:span) { exporter.finished_spans.last } - let(:rails_app) { DEFAULT_RAILS_APP } + let(:rails_app) { AppConfig.initialize_app } # Clear captured spans before { exporter.reset } - it 'sets the span name to the format: HTTP_METHOD /rails/route(.:format)' do + it 'sets the span name to the format: HTTP_METHOD /rails/route' do get '/ok' _(last_response.body).must_equal 'actually ok' _(last_response.ok?).must_equal true - _(span.name).must_equal 'ExampleController#ok' + _(span.name).must_match %r{GET.*/ok} _(span.kind).must_equal :server _(span.status.ok?).must_equal true diff --git a/instrumentation/rails/test/instrumentation/test_helper.rb b/instrumentation/rails/test/instrumentation/test_helper.rb index 2690c04d0..b95b64235 100644 --- a/instrumentation/rails/test/instrumentation/test_helper.rb +++ b/instrumentation/rails/test/instrumentation/test_helper.rb @@ -23,8 +23,3 @@ c.use_all c.add_span_processor span_processor end - -# Create a globally available Rails app, this should be used in test unless -# specifically testing behaviour with different initialization configs. -DEFAULT_RAILS_APP = AppConfig.initialize_app -Rails.application = DEFAULT_RAILS_APP diff --git a/instrumentation/rails/test/instrumentation/test_helpers/app_config.rb b/instrumentation/rails/test/instrumentation/test_helpers/app_config.rb index 3e8c23ee1..ad4898551 100644 --- a/instrumentation/rails/test/instrumentation/test_helpers/app_config.rb +++ b/instrumentation/rails/test/instrumentation/test_helpers/app_config.rb @@ -4,8 +4,9 @@ # # SPDX-License-Identifier: Apache-2.0 -class Application < Rails::Application; end require 'action_controller/railtie' +class Application < Rails::Application; end + require_relative 'middlewares' require_relative 'controllers' require_relative 'routes' @@ -28,7 +29,7 @@ def initialize_app(use_exceptions_app: false, remove_rack_tracer_middleware: fal case Rails.version when /^6\.1/ apply_rails_6_1_configs(new_app) - when /^7\./ + when /^7|8\./ apply_rails_7_configs(new_app) end @@ -46,9 +47,7 @@ def initialize_app(use_exceptions_app: false, remove_rack_tracer_middleware: fal private def remove_rack_middleware(application) - application.middleware.delete( - OpenTelemetry::Instrumentation::Rack::Middlewares::TracerMiddleware - ) + application.middleware.delete(Rack::Events) end def add_exceptions_app(application) diff --git a/instrumentation/rails/test/instrumentation/test_helpers/controllers/example_controller.rb b/instrumentation/rails/test/instrumentation/test_helpers/controllers/example_controller.rb index 9bb554655..abe86b587 100644 --- a/instrumentation/rails/test/instrumentation/test_helpers/controllers/example_controller.rb +++ b/instrumentation/rails/test/instrumentation/test_helpers/controllers/example_controller.rb @@ -12,6 +12,6 @@ def ok end def internal_server_error - raise :internal_server_error + raise 'internal_server_error' end end diff --git a/instrumentation/rails/test/instrumentation/test_helpers/routes.rb b/instrumentation/rails/test/instrumentation/test_helpers/routes.rb index 88f0565f2..bef13feb6 100644 --- a/instrumentation/rails/test/instrumentation/test_helpers/routes.rb +++ b/instrumentation/rails/test/instrumentation/test_helpers/routes.rb @@ -6,7 +6,7 @@ def draw_routes(rails_app) rails_app.routes.draw do - get '/ok', to: 'example#ok' + get 'ok', to: 'example#ok' get '/internal_server_error', to: 'example#internal_server_error' end end diff --git a/instrumentation/rails/test/railtie/dummy/tmp/.gitkeep b/instrumentation/rails/test/railtie/dummy/tmp/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/instrumentation/rake/opentelemetry-instrumentation-rake.gemspec b/instrumentation/rake/opentelemetry-instrumentation-rake.gemspec index f6f8b709b..3c6825d72 100644 --- a/instrumentation/rake/opentelemetry-instrumentation-rake.gemspec +++ b/instrumentation/rake/opentelemetry-instrumentation-rake.gemspec @@ -33,10 +33,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'opentelemetry-sdk', '~> 1.0' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/rdkafka/opentelemetry-instrumentation-rdkafka.gemspec b/instrumentation/rdkafka/opentelemetry-instrumentation-rdkafka.gemspec index e7b14e48a..72bf2056c 100644 --- a/instrumentation/rdkafka/opentelemetry-instrumentation-rdkafka.gemspec +++ b/instrumentation/rdkafka/opentelemetry-instrumentation-rdkafka.gemspec @@ -35,10 +35,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'pry-byebug' unless RUBY_ENGINE == 'jruby' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/redis/opentelemetry-instrumentation-redis.gemspec b/instrumentation/redis/opentelemetry-instrumentation-redis.gemspec index 183a9d8e0..7e00c7a55 100644 --- a/instrumentation/redis/opentelemetry-instrumentation-redis.gemspec +++ b/instrumentation/redis/opentelemetry-instrumentation-redis.gemspec @@ -33,8 +33,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' spec.add_development_dependency 'yard', '~> 0.9' diff --git a/instrumentation/resque/opentelemetry-instrumentation-resque.gemspec b/instrumentation/resque/opentelemetry-instrumentation-resque.gemspec index 1c6e8e5ab..89cc03eaf 100644 --- a/instrumentation/resque/opentelemetry-instrumentation-resque.gemspec +++ b/instrumentation/resque/opentelemetry-instrumentation-resque.gemspec @@ -34,10 +34,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/restclient/lib/opentelemetry/instrumentation/restclient/patches/request.rb b/instrumentation/restclient/lib/opentelemetry/instrumentation/restclient/patches/request.rb index afb2fdf11..1507948f7 100644 --- a/instrumentation/restclient/lib/opentelemetry/instrumentation/restclient/patches/request.rb +++ b/instrumentation/restclient/lib/opentelemetry/instrumentation/restclient/patches/request.rb @@ -10,6 +10,9 @@ module RestClient module Patches # Module to prepend to RestClient::Request for instrumentation module Request + # Constant for the HTTP status range + HTTP_STATUS_SUCCESS_RANGE = (100..399) + def execute(&block) trace_request do |_span| super @@ -49,13 +52,12 @@ def trace_request # If so, add additional attributes. if response.is_a?(::RestClient::Response) span.set_attribute('http.status_code', response.code) - span.status = OpenTelemetry::Trace::Status.error unless (100..399).cover?(response.code.to_i) + span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(response.code.to_i) end end rescue ::RestClient::ExceptionWithResponse => e span.set_attribute('http.status_code', e.http_code) - span.status = OpenTelemetry::Trace::Status.error unless (100..399).cover?(e.http_code.to_i) - + span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(e.http_code.to_i) raise e ensure span.finish diff --git a/instrumentation/restclient/opentelemetry-instrumentation-restclient.gemspec b/instrumentation/restclient/opentelemetry-instrumentation-restclient.gemspec index 2b4823aac..dadfa6d14 100644 --- a/instrumentation/restclient/opentelemetry-instrumentation-restclient.gemspec +++ b/instrumentation/restclient/opentelemetry-instrumentation-restclient.gemspec @@ -33,10 +33,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/rspec/opentelemetry-instrumentation-rspec.gemspec b/instrumentation/rspec/opentelemetry-instrumentation-rspec.gemspec index 6c4760d0c..f7129e984 100644 --- a/instrumentation/rspec/opentelemetry-instrumentation-rspec.gemspec +++ b/instrumentation/rspec/opentelemetry-instrumentation-rspec.gemspec @@ -34,10 +34,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-sdk' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/ruby_kafka/opentelemetry-instrumentation-ruby_kafka.gemspec b/instrumentation/ruby_kafka/opentelemetry-instrumentation-ruby_kafka.gemspec index a6572baa6..2e8bbfba5 100644 --- a/instrumentation/ruby_kafka/opentelemetry-instrumentation-ruby_kafka.gemspec +++ b/instrumentation/ruby_kafka/opentelemetry-instrumentation-ruby_kafka.gemspec @@ -34,8 +34,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rspec-mocks' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' spec.add_development_dependency 'yard', '~> 0.9' diff --git a/instrumentation/sidekiq/opentelemetry-instrumentation-sidekiq.gemspec b/instrumentation/sidekiq/opentelemetry-instrumentation-sidekiq.gemspec index dc1939455..0e63e3800 100644 --- a/instrumentation/sidekiq/opentelemetry-instrumentation-sidekiq.gemspec +++ b/instrumentation/sidekiq/opentelemetry-instrumentation-sidekiq.gemspec @@ -35,8 +35,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rspec-mocks' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' spec.add_development_dependency 'yard', '~> 0.9' diff --git a/instrumentation/sinatra/Appraisals b/instrumentation/sinatra/Appraisals index f04c6775b..73cb3a9d4 100644 --- a/instrumentation/sinatra/Appraisals +++ b/instrumentation/sinatra/Appraisals @@ -4,16 +4,10 @@ # # SPDX-License-Identifier: Apache-2.0 -appraise 'sinatra-4.x' do - gem 'sinatra', '~> 4.0' -end - -appraise 'sinatra-3.x' do - gem 'sinatra', '~> 3.0' -end - -appraise 'sinatra-2.x' do - gem 'sinatra', '~> 2.1' +%w[4.1 3.0 2.1].each do |version| + appraise "sinatra-#{version}" do + gem 'sinatra', "~> #{version}" + end end appraise 'sinatra-latest' do diff --git a/instrumentation/sinatra/opentelemetry-instrumentation-sinatra.gemspec b/instrumentation/sinatra/opentelemetry-instrumentation-sinatra.gemspec index 4a1543785..0f77e5b23 100644 --- a/instrumentation/sinatra/opentelemetry-instrumentation-sinatra.gemspec +++ b/instrumentation/sinatra/opentelemetry-instrumentation-sinatra.gemspec @@ -35,10 +35,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' spec.add_development_dependency 'rack-test', '~> 2.1' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' - spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/instrumentation/sinatra/test/opentelemetry/instrumentation/sinatra_test.rb b/instrumentation/sinatra/test/opentelemetry/instrumentation/sinatra_test.rb index 0425595b8..4c9d5814a 100644 --- a/instrumentation/sinatra/test/opentelemetry/instrumentation/sinatra_test.rb +++ b/instrumentation/sinatra/test/opentelemetry/instrumentation/sinatra_test.rb @@ -17,6 +17,7 @@ class CustomError < StandardError; end let(:app_one) do Class.new(Sinatra::Application) do + set :raise_errors, false get '/endpoint' do '1' end @@ -41,6 +42,7 @@ class CustomError < StandardError; end let(:app_two) do Class.new(Sinatra::Application) do + set :raise_errors, false get '/endpoint' do '2' end @@ -165,7 +167,8 @@ class CustomError < StandardError; end 'http.method' => 'GET', 'http.route' => '/error', 'http.scheme' => 'http', - 'http.target' => '/error' + 'http.target' => '/error', + 'http.status_code' => 500 ) _(exporter.finished_spans.flat_map(&:events).map(&:name)).must_equal(['exception']) end diff --git a/instrumentation/sinatra/test/test_helper.rb b/instrumentation/sinatra/test/test_helper.rb index 6caf4af52..48ae2a681 100644 --- a/instrumentation/sinatra/test/test_helper.rb +++ b/instrumentation/sinatra/test/test_helper.rb @@ -3,6 +3,7 @@ # Copyright The OpenTelemetry Authors # # SPDX-License-Identifier: Apache-2.0 +ENV['APP_ENV'] = 'test' require 'bundler/setup' Bundler.require(:default, :development, :test) diff --git a/instrumentation/trilogy/opentelemetry-instrumentation-trilogy.gemspec b/instrumentation/trilogy/opentelemetry-instrumentation-trilogy.gemspec index 788ab8469..dca960cb2 100644 --- a/instrumentation/trilogy/opentelemetry-instrumentation-trilogy.gemspec +++ b/instrumentation/trilogy/opentelemetry-instrumentation-trilogy.gemspec @@ -41,8 +41,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'pry-byebug' unless RUBY_ENGINE == 'jruby' spec.add_development_dependency 'rake', '~> 13.0' spec.add_development_dependency 'rspec-mocks' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' spec.add_development_dependency 'yard', '~> 0.9' diff --git a/otelcol-config.yml b/otelcol-config.yml index e653551b5..c406f0517 100644 --- a/otelcol-config.yml +++ b/otelcol-config.yml @@ -2,13 +2,15 @@ receivers: otlp: protocols: grpc: + endpoint: 0.0.0.0:4317 http: + endpoint: 0.0.0.0:4318 exporters: - jaeger: - endpoint: "jaeger:14250" + otlp: + endpoint: "jaeger:4317" tls: insecure: true - logging: + debug: processors: batch: @@ -18,4 +20,4 @@ service: traces: receivers: [otlp] processors: [batch] - exporters: [logging, jaeger] + exporters: [debug, otlp] diff --git a/processor/baggage/opentelemetry-processor-baggage.gemspec b/processor/baggage/opentelemetry-processor-baggage.gemspec index 18ef334bb..8d429b12e 100644 --- a/processor/baggage/opentelemetry-processor-baggage.gemspec +++ b/processor/baggage/opentelemetry-processor-baggage.gemspec @@ -30,8 +30,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.22.0' spec.add_development_dependency 'yard', '~> 0.9' diff --git a/propagator/ottrace/opentelemetry-propagator-ottrace.gemspec b/propagator/ottrace/opentelemetry-propagator-ottrace.gemspec index d00f57231..9e4aa0bcc 100644 --- a/propagator/ottrace/opentelemetry-propagator-ottrace.gemspec +++ b/propagator/ottrace/opentelemetry-propagator-ottrace.gemspec @@ -28,8 +28,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'bundler', '~> 2.4' spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.22.0' spec.add_development_dependency 'yard', '~> 0.9' diff --git a/propagator/vitess/README.md b/propagator/vitess/README.md index 47b88eda3..cb5c96ef9 100644 --- a/propagator/vitess/README.md +++ b/propagator/vitess/README.md @@ -40,7 +40,7 @@ Or, if you use [bundler][bundler-home], include `opentelemetry-propagator-vitess Configure your application to use this propagator with the Trilogy client instrumentation by setting the following [environment variable][envars]: ```console -OTEL_RUBY_INSTRUMENTATION_TRILOGY_PROPAGATOR=vitess +OTEL_RUBY_INSTRUMENTATION_TRILOGY_CONFIG_OPTS=propagator=vitess ``` ## How can I get involved? diff --git a/propagator/vitess/opentelemetry-propagator-vitess.gemspec b/propagator/vitess/opentelemetry-propagator-vitess.gemspec index 74d87c68f..474f06f7c 100644 --- a/propagator/vitess/opentelemetry-propagator-vitess.gemspec +++ b/propagator/vitess/opentelemetry-propagator-vitess.gemspec @@ -29,8 +29,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'bundler', '~> 2.4' spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.22.0' spec.add_development_dependency 'yard', '~> 0.9' diff --git a/propagator/xray/opentelemetry-propagator-xray.gemspec b/propagator/xray/opentelemetry-propagator-xray.gemspec index c4c056fc8..8efcfc243 100644 --- a/propagator/xray/opentelemetry-propagator-xray.gemspec +++ b/propagator/xray/opentelemetry-propagator-xray.gemspec @@ -31,8 +31,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'bundler', '~> 2.4' spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.22.0' spec.add_development_dependency 'yard', '~> 0.9' diff --git a/release-please-config.json b/release-please-config.json index 056677671..35d6c7b5b 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -1,5 +1,5 @@ { - "bootstrap-sha": "c7686e532a7348b504ad43024735b12d795756cd", + "bootstrap-sha": "ad8988bc4a11bafa0925c3137f2ae32bc57f40a0", "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": true, "draft": true, diff --git a/resources/azure/opentelemetry-resource-detector-azure.gemspec b/resources/azure/opentelemetry-resource-detector-azure.gemspec index 8c92fea3c..aaa321054 100644 --- a/resources/azure/opentelemetry-resource-detector-azure.gemspec +++ b/resources/azure/opentelemetry-resource-detector-azure.gemspec @@ -30,10 +30,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'bundler', '~> 2.4' spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17' - spec.add_development_dependency 'webmock', '~> 3.23.0' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata) diff --git a/resources/container/opentelemetry-resource-detector-container.gemspec b/resources/container/opentelemetry-resource-detector-container.gemspec index caf0fc56c..1589db320 100644 --- a/resources/container/opentelemetry-resource-detector-container.gemspec +++ b/resources/container/opentelemetry-resource-detector-container.gemspec @@ -30,8 +30,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'bundler', '~> 2.4' spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17' spec.add_development_dependency 'yard', '~> 0.9' diff --git a/resources/google_cloud_platform/opentelemetry-resource-detector-google_cloud_platform.gemspec b/resources/google_cloud_platform/opentelemetry-resource-detector-google_cloud_platform.gemspec index 1603b54fe..564b9d620 100644 --- a/resources/google_cloud_platform/opentelemetry-resource-detector-google_cloud_platform.gemspec +++ b/resources/google_cloud_platform/opentelemetry-resource-detector-google_cloud_platform.gemspec @@ -31,10 +31,10 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'bundler', '~> 2.4' spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rubocop', '~> 1.66.0' - spec.add_development_dependency 'rubocop-performance', '~> 1.20' + spec.add_development_dependency 'rubocop', '~> 1.68.0' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' spec.add_development_dependency 'simplecov', '~> 0.17' - spec.add_development_dependency 'webmock', '~> 3.23.0' + spec.add_development_dependency 'webmock', '~> 3.24.0' spec.add_development_dependency 'yard', '~> 0.9' if spec.respond_to?(:metadata)