From 9d13c5ade08cc3fd7906e671900c66132e9b5564 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Wed, 29 Jan 2025 14:59:33 -0500 Subject: [PATCH 01/44] feat: init commit for zero-code instrumentation --- .github/workflows/ci-contrib.yml | 37 ++++ zero-code-instrumentation/CHANGELOG.md | 5 + zero-code-instrumentation/Gemfile | 23 ++ zero-code-instrumentation/LICENSE | 201 ++++++++++++++++++ zero-code-instrumentation/README.md | 151 +++++++++++++ zero-code-instrumentation/Rakefile | 28 +++ zero-code-instrumentation/example/Gemfile | 3 + zero-code-instrumentation/example/app.rb | 14 ++ zero-code-instrumentation/lib/version.rb | 7 + .../lib/zero-code-instrumentation.rb | 144 +++++++++++++ zero-code-instrumentation/test/test_helper.rb | 14 ++ .../test/zero-code-instrumentation_test.rb | 88 ++++++++ .../zero-code-instrumentation.gemspec | 54 +++++ 13 files changed, 769 insertions(+) create mode 100644 zero-code-instrumentation/CHANGELOG.md create mode 100644 zero-code-instrumentation/Gemfile create mode 100644 zero-code-instrumentation/LICENSE create mode 100644 zero-code-instrumentation/README.md create mode 100644 zero-code-instrumentation/Rakefile create mode 100644 zero-code-instrumentation/example/Gemfile create mode 100644 zero-code-instrumentation/example/app.rb create mode 100644 zero-code-instrumentation/lib/version.rb create mode 100644 zero-code-instrumentation/lib/zero-code-instrumentation.rb create mode 100644 zero-code-instrumentation/test/test_helper.rb create mode 100644 zero-code-instrumentation/test/zero-code-instrumentation_test.rb create mode 100644 zero-code-instrumentation/zero-code-instrumentation.gemspec diff --git a/.github/workflows/ci-contrib.yml b/.github/workflows/ci-contrib.yml index 39ee9e9e21..7cafbfcbce 100644 --- a/.github/workflows/ci-contrib.yml +++ b/.github/workflows/ci-contrib.yml @@ -168,3 +168,40 @@ jobs: with: gem: "opentelemetry-processor-${{ matrix.gem }}" ruby: "jruby-9.4.9.0" + + zero-code-instrumentation: + strategy: + fail-fast: false + matrix: + gem: + - zero-code-instrumentation + os: + - ubuntu-latest + name: "${{ matrix.gem }} / ${{ matrix.os }}" + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - name: "Test Ruby 3.3" + uses: ./.github/actions/test_gem + with: + gem: "${{ matrix.gem }}" + ruby: "3.3" + - name: "Test Ruby 3.2" + uses: ./.github/actions/test_gem + with: + gem: "${{ matrix.gem }}" + ruby: "3.2" + - name: "Test Ruby 3.1" + uses: ./.github/actions/test_gem + with: + gem: "${{ matrix.gem }}" + ruby: "3.1" + yard: true + rubocop: true + build: true + - name: "Test JRuby" + if: "${{ matrix.os == 'ubuntu-latest'" + uses: ./.github/actions/test_gem + with: + gem: "${{ matrix.gem }}" + ruby: "jruby-9.4.9.0" diff --git a/zero-code-instrumentation/CHANGELOG.md b/zero-code-instrumentation/CHANGELOG.md new file mode 100644 index 0000000000..de43fbf3d1 --- /dev/null +++ b/zero-code-instrumentation/CHANGELOG.md @@ -0,0 +1,5 @@ +# Release History: zero-code-instrumentation + +### v0.1.0 / 2025-01-21 + +* Initial release diff --git a/zero-code-instrumentation/Gemfile b/zero-code-instrumentation/Gemfile new file mode 100644 index 0000000000..2b7a43e677 --- /dev/null +++ b/zero-code-instrumentation/Gemfile @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +source 'https://rubygems.org' + +# avoid use gemspec to avoid circular load + +gem 'opentelemetry-sdk' +gem 'opentelemetry-instrumentation-all' +gem 'opentelemetry-exporter-otlp' +gem 'opentelemetry-test-helpers' +gem 'opentelemetry-resource-detector-container', path: '../resources/container' + +gem 'bundler' +gem 'minitest' +gem 'rake' +gem 'rubocop' +gem 'rubocop-performance' +gem 'simplecov' +gem 'yard' diff --git a/zero-code-instrumentation/LICENSE b/zero-code-instrumentation/LICENSE new file mode 100644 index 0000000000..1ef7dad2c5 --- /dev/null +++ b/zero-code-instrumentation/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright The OpenTelemetry Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/zero-code-instrumentation/README.md b/zero-code-instrumentation/README.md new file mode 100644 index 0000000000..1263908ef5 --- /dev/null +++ b/zero-code-instrumentation/README.md @@ -0,0 +1,151 @@ +# Zero-code Instrumentation + +The `zero-code-instrumentation` gem provides an easy way to load and initialize opentelemetry-ruby for zero-code instrumentation. + +## What is OpenTelemetry? + +OpenTelemetry is an open source observability framework, providing a general-purpose API, SDK, and related tools required for the instrumentation of cloud-native software, frameworks, and libraries. + +OpenTelemetry provides a single set of APIs, libraries, agents, and collector services to capture distributed traces and metrics from your application. You can analyze them using Prometheus, Jaeger, and other observability tools. + +## How does this gem fit in? + +The `zero-code-instrumentation` gem provides an easy way to load and initialize the OpenTelemetry Ruby SDK. This gem is particularly used for the [OpenTelemetry Operator][opentelemetry-operator]. + +## How do I get started? + +It's recommended to install this gem through gem install rather than Bundler since it doesn't require modifying any user's codebase (including the Gemfile). + +Install the gem using: + +```console +gem install zero-code-instrumentation +``` + +Install zero-code-instrumentation will automatically install following gems: + + opentelemetry-sdk + opentelemetry-api + opentelemetry-instrumentation-all + opentelemetry-exporter-otlp + opentelemetry-helpers-mysql + opentelemetry-helpers-sql-obfuscation + opentelemetry-resource-detector-google_cloud_platform + opentelemetry-resource-detector-azure + opentelemetry-resource-detector-container + +Instrument your application: + +```console +RUBYOPT="-r zero-code-instrumentation" ruby application.rb +``` + +Instrument your application with additional environment variables: + +```console +export OTEL_TRACES_EXPORTER="otlp" +export OTEL_EXPORTER_OTLP_ENDPOINT="your-endpoint" +export OTEL_RUBY_RESOURCE_DETECTORS="container" +export OTEL_SERVICE_NAME="your-service-name" + +RUBYOPT="-r zero-code-instrumentation" ruby application.rb +``` + +Instrument your application with disabling certain instrumentation (e.g. sinatra): + +```console +export OTEL_RUBY_INSTRUMENTATION_SINATRA_ENABLED='false' +RUBYOPT="-r zero-code-instrumentation" ruby application.rb +``` + +Instrument your application with only certain instrumentation installed (e.g. mysql, redis): + +```console +export OTEL_RUBY_ENABLED_INSTRUMENTATIONS='mysql2,redis' +RUBYOPT="-r zero-code-instrumentation" ruby application.rb +``` + +Instrument your application with only redis and configure its options: + +```console +export OTEL_RUBY_ENABLED_INSTRUMENTATIONS='redis' +export OTEL_RUBY_INSTRUMENTATION_REDIS_CONFIG_OPTS='peer_service=new_service;db_statement=omit' +RUBYOPT="-r zero-code-instrumentation" ruby application.rb +``` + +Instrument Rails application: + +```console +RUBYOPT="-r zero-code-instrumentation" rails server +``` + +Instrument Rails application with `bundle exec` + +Since installing the `zero-code-instrumentation` gem through `gem install`, anything related to the OpenTelemetry gem won't be stored in Bundler's gem path. Therefore, users need to add an additional gem path that contains these gems prior to initialization. + +```console +export GEM_PATH= +RUBYOPT="-r {PUT YOUR GEM PATH}/gems/zero-code-instrumentation-0.1.0/lib/zero-code-instrumentation" bundle exec rails server +``` + +Instrument Sinatra application with rackup: + +If you are using a Gemfile to install the required gems but without `Bundler.require`, set `REQUIRE_BUNDLER` to true. This way, `zero-code-instrumentation` will call `Bundler.require` to initialize the required gems prior to SDK initialization. + +```console +export REQUIRE_BUNDLER=true +RUBYOPT="-r zero-code-instrumentation" rackup config.ru +``` + +If wish to load some gem outside the Gemfile, then it needs to be placed in front of zero-code-instrumentation: + +```console +export BUNDLE_WITHOUT=development,test +gem install mysql2 +RUBYOPT="-r mysql2 -r zero-code-instrumentation" ruby application.rb +``` + +## Example + +In example folder, execute the following commands should see the trace output. + +```console +# if user don't want to install zero-code-instrumentation from rubygems.org +# user can build the gem and install it with gem install *.gem + +gem install zero-code-instrumentation +bundle install +export REQUIRE_BUNDLER=true +export OTEL_TRACES_EXPORTER=console +RUBYOPT="-r zero-code-instrumentation" ruby app.rb +``` + +## Configuration + +These environment variables are not standard OpenTelemetry environment variables; they are only feature flags for this gem. + +| Environment Variable | Description | Default | Example | +|----------------------|-------------|---------|---------| +| `REQUIRE_BUNDLER` | Set to `true` if you are using Bundler to install gems but without `Bundler.require` in your script during initialization. | nil | N/A | +| `USE_BUNDLE_EXEC` | Set to `true` if initializing through `bundle exec`. | nil | N/A | +| `ADDITIONAL_GEM_PATH` | Intended to be used for the OpenTelemetry Operator environment if you install `zero-code-instrumentation` to a customized path. | nil | N/A | +| `OTEL_OPERATOR` | Set to `true` to set the binding path for the OpenTelemetry Operator. | `/otel-auto-instrumentation-ruby` | N/A | +| `OTEL_RUBY_RESOURCE_DETECTORS` | Determine what kind of resource detector is needed. Currently supports `container`, `azure`, and `google_cloud_platform`. Use commas to separate multiple detectors. | nil | `container,azure` | +| `OTEL_RUBY_ENABLED_INSTRUMENTATIONS` | Shortcut used when you only want to instrument one or a couple of particular libraries. | nil | `redis,active_record` | + +## How can I get involved? + +The `zero-code-instrumentation` gem source is on GitHub, along with related gems. + +The OpenTelemetry Ruby gems are maintained by the OpenTelemetry Ruby special interest group (SIG). You can get involved by joining us on our [GitHub Discussions][discussions-url], [Slack Channel][slack-channel] or attending our weekly meeting. See the [meeting calendar][community-meetings] for dates and times. For more information on this and other language SIGs, see the OpenTelemetry [community page][ruby-sig]. + +## License + +The `zero-code-instrumentation` gem is distributed under the Apache 2.0 license. See LICENSE for more information. + +[ruby-sig]: https://github.com/open-telemetry/community#ruby-sig +[community-meetings]: https://github.com/open-telemetry/community#community-meetings +[slack-channel]: https://cloud-native.slack.com/archives/C01NWKKMKMY +[discussions-url]: https://github.com/open-telemetry/opentelemetry-ruby/discussions +[k8sattributesprocessor-url]: https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/processor/k8sattributesprocessor/README.md +[opentelemetry-operator]: https://github.com/open-telemetry/opentelemetry-operator diff --git a/zero-code-instrumentation/Rakefile b/zero-code-instrumentation/Rakefile new file mode 100644 index 0000000000..1a64ba842e --- /dev/null +++ b/zero-code-instrumentation/Rakefile @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'bundler/gem_tasks' +require 'rake/testtask' +require 'yard' +require 'rubocop/rake_task' + +RuboCop::RakeTask.new + +Rake::TestTask.new :test do |t| + t.libs << 'test' + t.libs << 'lib' + t.test_files = FileList['test/**/*_test.rb'] +end + +YARD::Rake::YardocTask.new do |t| + t.stats_options = ['--list-undoc'] +end + +if RUBY_ENGINE == 'truffleruby' + task default: %i[test] +else + task default: %i[test rubocop yard] +end diff --git a/zero-code-instrumentation/example/Gemfile b/zero-code-instrumentation/example/Gemfile new file mode 100644 index 0000000000..a8b0038780 --- /dev/null +++ b/zero-code-instrumentation/example/Gemfile @@ -0,0 +1,3 @@ +source 'https://rubygems.org' + +gem 'net-http' diff --git a/zero-code-instrumentation/example/app.rb b/zero-code-instrumentation/example/app.rb new file mode 100644 index 0000000000..f895369eda --- /dev/null +++ b/zero-code-instrumentation/example/app.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'uri' +require 'net/http' + +url = URI.parse("http://catfact.ninja/fact") +req = Net::HTTP::Get.new(url.to_s) +res = Net::HTTP.start(url.host, url.port) {|http| + http.request(req) +} diff --git a/zero-code-instrumentation/lib/version.rb b/zero-code-instrumentation/lib/version.rb new file mode 100644 index 0000000000..001acd6202 --- /dev/null +++ b/zero-code-instrumentation/lib/version.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +VERSION = '0.1.0' diff --git a/zero-code-instrumentation/lib/zero-code-instrumentation.rb b/zero-code-instrumentation/lib/zero-code-instrumentation.rb new file mode 100644 index 0000000000..b897c4b26c --- /dev/null +++ b/zero-code-instrumentation/lib/zero-code-instrumentation.rb @@ -0,0 +1,144 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OTelBundlerPatch + + # ref: https://github.com/newrelic/newrelic-ruby-agent/blob/dev/lib/boot/strap.rb + def require(*_groups) + super + require_otel + end + + # this is used for case when user particularly want to enable single instrumentation + OTEL_INSTRUMENTATION_MAP = { + "gruf" => "OpenTelemetry::Instrumentation::Gruf", + "trilogy" => "OpenTelemetry::Instrumentation::Trilogy", + "active_support" => "OpenTelemetry::Instrumentation::ActiveSupport", + "action_pack" => "OpenTelemetry::Instrumentation::ActionPack", + "active_job" => "OpenTelemetry::Instrumentation::ActiveJob", + "active_record" => "OpenTelemetry::Instrumentation::ActiveRecord", + "action_view" => "OpenTelemetry::Instrumentation::ActionView", + "action_mailer" => "OpenTelemetry::Instrumentation::ActionMailer", + "aws_sdk" => "OpenTelemetry::Instrumentation::AwsSdk", + "aws_lambda" => "OpenTelemetry::Instrumentation::AwsLambda", + "bunny" => "OpenTelemetry::Instrumentation::Bunny", + "lmdb" => "OpenTelemetry::Instrumentation::LMDB", + "http" => "OpenTelemetry::Instrumentation::HTTP", + "koala" => "OpenTelemetry::Instrumentation::Koala", + "active_model_serializers" => "OpenTelemetry::Instrumentation::ActiveModelSerializers", + "concurrent_ruby" => "OpenTelemetry::Instrumentation::ConcurrentRuby", + "dalli" => "OpenTelemetry::Instrumentation::Dalli", + "delayed_job" => "OpenTelemetry::Instrumentation::DelayedJob", + "ethon" => "OpenTelemetry::Instrumentation::Ethon", + "excon" => "OpenTelemetry::Instrumentation::Excon", + "faraday" => "OpenTelemetry::Instrumentation::Faraday", + "grape" => "OpenTelemetry::Instrumentation::Grape", + "graphql" => "OpenTelemetry::Instrumentation::GraphQL", + "http_client" => "OpenTelemetry::Instrumentation::HttpClient", + "mongo" => "OpenTelemetry::Instrumentation::Mongo", + "mysql2" => "OpenTelemetry::Instrumentation::Mysql2", + "net_http" => "OpenTelemetry::Instrumentation::Net::HTTP", + "pg" => "OpenTelemetry::Instrumentation::PG", + "que" => "OpenTelemetry::Instrumentation::Que", + "racecar" => "OpenTelemetry::Instrumentation::Racecar", + "rack" => "OpenTelemetry::Instrumentation::Rack", + "rails" => "OpenTelemetry::Instrumentation::Rails", + "rake" => "OpenTelemetry::Instrumentation::Rake", + "rdkafka" => "OpenTelemetry::Instrumentation::Rdkafka", + "redis" => "OpenTelemetry::Instrumentation::Redis", + "restclient" => "OpenTelemetry::Instrumentation::RestClient", + "resque" => "OpenTelemetry::Instrumentation::Resque", + "ruby_kafka" => "OpenTelemetry::Instrumentation::RubyKafka", + "sidekiq" => "OpenTelemetry::Instrumentation::Sidekiq", + "sinatra" => "OpenTelemetry::Instrumentation::Sinatra" + } + + def detect_resource_from_env + env = ENV['OTEL_RUBY_RESOURCE_DETECTORS'].to_s + additional_resource = ::OpenTelemetry::SDK::Resources::Resource.create({}) + + env.split(',').each do |detector| + case detector + when 'container' + additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::Container.detect) if defined? (::OpenTelemetry::Resource::Detector::Container) + when 'google_cloud_platform' + additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::GoogleCloudPlatform.detect) if defined? (::OpenTelemetry::Resource::Detector::GoogleCloudPlatform) + when 'azure' + additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::Azure.detect) if defined? (::OpenTelemetry::Resource::Detector::Azure) + end + end + + additional_resource + end + + def determine_enabled_instrumentation + env = ENV['OTEL_RUBY_ENABLED_INSTRUMENTATIONS'].to_s + + enabled_instrumentation = [] + env.split(',').each { |instrumentation| enabled_instrumentation.push(OTEL_INSTRUMENTATION_MAP[instrumentation]) } + enabled_instrumentation + end + + def require_otel + lib = File.expand_path('../..', __FILE__) + $LOAD_PATH.reject! { |path| path.include?('zero-code-instrumentation') } + $LOAD_PATH.unshift(lib) + + begin + required_instrumentation = determine_enabled_instrumentation + + OpenTelemetry::SDK.configure do |c| + c.resource = detect_resource_from_env + if required_instrumentation.size == 0 + c.use_all # enables all instrumentation! + else + required_instrumentation.each do |instrumentation| + c.use instrumentation + end + end + end + OpenTelemetry.logger.info {"Auto-instrumentation initialized"} + rescue StandardError => e + OpenTelemetry.logger.info {"Auto-instrumentation failed to initialize. Error: #{e.message}"} + end + end +end + +require 'bundler' + +container = ENV['OTEL_RUBY_RESOURCE_DETECTORS'].to_s.include?('container') +google_cloud_platform = ENV['OTEL_RUBY_RESOURCE_DETECTORS'].to_s.include?('google_cloud_platform') +azure = ENV['OTEL_RUBY_RESOURCE_DETECTORS'].to_s.include?('azure') + +if ENV['USE_BUNDLE_EXEC'].to_s == 'true' + + # assume the operator ruby image will amount the additional otel gem to this folder + operator_gem_path = ENV['OTEL_OPERATOR'].to_s == 'true' ? '/otel-auto-instrumentation-ruby' : nil + additional_gem_path = operator_gem_path || ENV['ADDITIONAL_GEM_PATH'] || Gem.dir + OpenTelemetry.logger.info { "Loading the additional gem path from #{additional_gem_path}"} + + # google-protobuf is used for otel trace exporter + Dir.glob("#{additional_gem_path}/gems/*").each do |file| + if file.include?('opentelemetry') || file.include?('google') + puts file.inspect + $LOAD_PATH.unshift("#{file}/lib") + end + end +end + +require 'opentelemetry-sdk' +require 'opentelemetry-instrumentation-all' +require 'opentelemetry-helpers-mysql' +require 'opentelemetry-helpers-sql-obfuscation' +require 'opentelemetry-exporter-otlp' + +require 'opentelemetry-resource-detector-container' if container +require 'opentelemetry-resource-detector-google_cloud_platform' if google_cloud_platform +require 'opentelemetry-resource-detector-azure' if azure + +Bundler::Runtime.prepend(OTelBundlerPatch) + +Bundler.require if ENV['REQUIRE_BUNDLER'].to_s == 'true' diff --git a/zero-code-instrumentation/test/test_helper.rb b/zero-code-instrumentation/test/test_helper.rb new file mode 100644 index 0000000000..9798aead57 --- /dev/null +++ b/zero-code-instrumentation/test/test_helper.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'rake' +require 'minitest' +require 'minitest/autorun' +require 'opentelemetry-test-helpers' +require 'opentelemetry/resource/detector' +require 'net/http' +require 'opentelemetry-sdk' +require 'opentelemetry-instrumentation-all' diff --git a/zero-code-instrumentation/test/zero-code-instrumentation_test.rb b/zero-code-instrumentation/test/zero-code-instrumentation_test.rb new file mode 100644 index 0000000000..f32f92c7fc --- /dev/null +++ b/zero-code-instrumentation/test/zero-code-instrumentation_test.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'test_helper' + +describe 'ZeroCodeInstrumentation' do + + before do + OpenTelemetry::TestHelpers.reset_opentelemetry + end + + after do + OTelBundlerPatch.send(:remove_const, :OTEL_INSTRUMENTATION_MAP) + OTelBundlerPatch.send(:undef_method, :detect_resource_from_env) + OTelBundlerPatch.send(:undef_method, :determine_enabled_instrumentation) + OTelBundlerPatch.send(:undef_method, :require_otel) + OTelBundlerPatch.send(:undef_method, :require) + OpenTelemetry::Instrumentation::Net::HTTP::Instrumentation.instance_variable_get(:@instance).instance_variable_set(:@installed, false) + OpenTelemetry::Instrumentation::Rake::Instrumentation.instance_variable_get(:@instance).instance_variable_set(:@installed, false) + end + + it 'simple_load_test' do + + load './lib/zero-code-instrumentation.rb' + Bundler.require + + _(OpenTelemetry.tracer_provider.class).must_equal OpenTelemetry::SDK::Trace::TracerProvider + + resource_attributes = OpenTelemetry.tracer_provider.instance_variable_get(:@resource).instance_variable_get(:@attributes) + + _(resource_attributes['service.name']).must_equal 'unknown_service' + _(resource_attributes['telemetry.sdk.name']).must_equal 'opentelemetry' + _(resource_attributes['telemetry.sdk.language']).must_equal 'ruby' + _(resource_attributes.key?('container.id')).must_equal false + + registry = OpenTelemetry.tracer_provider.instance_variable_get(:@registry) + + _(registry.size).must_equal 2 + end + + it 'simple_load_with_net_http_disabled' do + + ENV['OTEL_RUBY_INSTRUMENTATION_NET_HTTP_ENABLED'] = 'false' + + load './lib/zero-code-instrumentation.rb' + Bundler.require + + registry = OpenTelemetry.tracer_provider.instance_variable_get(:@registry) + + _(registry.size).must_equal 1 + _(registry.first.first.name).must_equal 'OpenTelemetry::Instrumentation::Rake' + + ENV['OTEL_RUBY_INSTRUMENTATION_NET_HTTP_ENABLED'] = nil + end + + it 'simple_load_with_desired_instrument_only' do + + ENV['OTEL_RUBY_ENABLED_INSTRUMENTATIONS'] = 'net_http' + + load './lib/zero-code-instrumentation.rb' + Bundler.require + + registry = OpenTelemetry.tracer_provider.instance_variable_get(:@registry) + + _(registry.size).must_equal 1 + _(registry.first.first.name).must_equal 'OpenTelemetry::Instrumentation::Net::HTTP' + + ENV['OTEL_RUBY_ENABLED_INSTRUMENTATIONS'] = nil + end + + it 'simple_load_with_additional_resource' do + + ENV['OTEL_RUBY_RESOURCE_DETECTORS'] = 'container' + + load './lib/zero-code-instrumentation.rb' + Bundler.require + + resource_attributes = OpenTelemetry.tracer_provider.instance_variable_get(:@resource).instance_variable_get(:@attributes) + _(resource_attributes.key?('container.id')).must_equal true + _(resource_attributes['telemetry.sdk.name']).must_equal 'opentelemetry' + _(resource_attributes['telemetry.sdk.language']).must_equal 'ruby' + + ENV['OTEL_RUBY_RESOURCE_DETECTORS'] = nil + end +end diff --git a/zero-code-instrumentation/zero-code-instrumentation.gemspec b/zero-code-instrumentation/zero-code-instrumentation.gemspec new file mode 100644 index 0000000000..5808aae632 --- /dev/null +++ b/zero-code-instrumentation/zero-code-instrumentation.gemspec @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +lib = File.expand_path('lib', __dir__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require 'version' + +Gem::Specification.new do |spec| + spec.name = 'zero-code-instrumentation' + spec.version = VERSION + spec.authors = ['OpenTelemetry Authors'] + spec.email = ['cncf-opentelemetry-contributors@lists.cncf.io'] + + spec.summary = 'Zero-code instrumentation for opentelemetry ruby' + spec.description = 'Zero-code instrumentation for opentelemetry ruby' + 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'] + + spec.require_paths = ['lib'] + spec.required_ruby_version = '>= 3.1' + + spec.add_dependency 'opentelemetry-sdk', '~> 1.0' + spec.add_dependency 'opentelemetry-instrumentation-all', '~> 0.72.0' + spec.add_dependency 'opentelemetry-exporter-otlp', '~> 0.29.1' + spec.add_dependency 'opentelemetry-helpers-mysql', '~> 0.2.0' + spec.add_dependency 'opentelemetry-helpers-sql-obfuscation', '~> 0.3.0' + spec.add_dependency 'opentelemetry-resource-detector-google_cloud_platform', '~> 0.2.0' + spec.add_dependency 'opentelemetry-resource-detector-azure', '~> 0.2.0' + spec.add_dependency 'opentelemetry-resource-detector-container', '~> 0.2.0' + + 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.69.1' + spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' + spec.add_development_dependency 'simplecov', '~> 0.17' + spec.add_development_dependency 'yard', '~> 0.9' + + if spec.respond_to?(:metadata) + spec.metadata['changelog_uri'] = "https://rubydoc.info/gems/#{spec.name}/#{spec.version}/file/CHANGELOG.md" + spec.metadata['source_code_uri'] = 'https://github.com/open-telemetry/opentelemetry-ruby-contrib/zero-code-instrumentation' + spec.metadata['bug_tracker_uri'] = 'https://github.com/open-telemetry/opentelemetry-ruby-contrib/issues' + spec.metadata['documentation_uri'] = "https://rubydoc.info/gems/#{spec.name}/#{spec.version}" + end + + spec.post_install_message = File.read(File.expand_path('../POST_INSTALL_MESSAGE', __dir__)) +end From 444959aad3e85ac7343b5a6cb81eb236f9d822a1 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Wed, 29 Jan 2025 15:01:28 -0500 Subject: [PATCH 02/44] lint --- zero-code-instrumentation/Gemfile | 4 +- .../lib/zero-code-instrumentation.rb | 104 +++++++++--------- .../test/zero-code-instrumentation_test.rb | 5 - .../zero-code-instrumentation.gemspec | 6 +- 4 files changed, 56 insertions(+), 63 deletions(-) diff --git a/zero-code-instrumentation/Gemfile b/zero-code-instrumentation/Gemfile index 2b7a43e677..793db3cb15 100644 --- a/zero-code-instrumentation/Gemfile +++ b/zero-code-instrumentation/Gemfile @@ -16,8 +16,8 @@ gem 'opentelemetry-resource-detector-container', path: '../resources/container' gem 'bundler' gem 'minitest' -gem 'rake' +gem 'rake' gem 'rubocop' gem 'rubocop-performance' -gem 'simplecov' +gem 'simplecov' gem 'yard' diff --git a/zero-code-instrumentation/lib/zero-code-instrumentation.rb b/zero-code-instrumentation/lib/zero-code-instrumentation.rb index b897c4b26c..1ff6156cd9 100644 --- a/zero-code-instrumentation/lib/zero-code-instrumentation.rb +++ b/zero-code-instrumentation/lib/zero-code-instrumentation.rb @@ -4,8 +4,8 @@ # # SPDX-License-Identifier: Apache-2.0 +# OTelBundlerPatch module OTelBundlerPatch - # ref: https://github.com/newrelic/newrelic-ruby-agent/blob/dev/lib/boot/strap.rb def require(*_groups) super @@ -14,47 +14,47 @@ def require(*_groups) # this is used for case when user particularly want to enable single instrumentation OTEL_INSTRUMENTATION_MAP = { - "gruf" => "OpenTelemetry::Instrumentation::Gruf", - "trilogy" => "OpenTelemetry::Instrumentation::Trilogy", - "active_support" => "OpenTelemetry::Instrumentation::ActiveSupport", - "action_pack" => "OpenTelemetry::Instrumentation::ActionPack", - "active_job" => "OpenTelemetry::Instrumentation::ActiveJob", - "active_record" => "OpenTelemetry::Instrumentation::ActiveRecord", - "action_view" => "OpenTelemetry::Instrumentation::ActionView", - "action_mailer" => "OpenTelemetry::Instrumentation::ActionMailer", - "aws_sdk" => "OpenTelemetry::Instrumentation::AwsSdk", - "aws_lambda" => "OpenTelemetry::Instrumentation::AwsLambda", - "bunny" => "OpenTelemetry::Instrumentation::Bunny", - "lmdb" => "OpenTelemetry::Instrumentation::LMDB", - "http" => "OpenTelemetry::Instrumentation::HTTP", - "koala" => "OpenTelemetry::Instrumentation::Koala", - "active_model_serializers" => "OpenTelemetry::Instrumentation::ActiveModelSerializers", - "concurrent_ruby" => "OpenTelemetry::Instrumentation::ConcurrentRuby", - "dalli" => "OpenTelemetry::Instrumentation::Dalli", - "delayed_job" => "OpenTelemetry::Instrumentation::DelayedJob", - "ethon" => "OpenTelemetry::Instrumentation::Ethon", - "excon" => "OpenTelemetry::Instrumentation::Excon", - "faraday" => "OpenTelemetry::Instrumentation::Faraday", - "grape" => "OpenTelemetry::Instrumentation::Grape", - "graphql" => "OpenTelemetry::Instrumentation::GraphQL", - "http_client" => "OpenTelemetry::Instrumentation::HttpClient", - "mongo" => "OpenTelemetry::Instrumentation::Mongo", - "mysql2" => "OpenTelemetry::Instrumentation::Mysql2", - "net_http" => "OpenTelemetry::Instrumentation::Net::HTTP", - "pg" => "OpenTelemetry::Instrumentation::PG", - "que" => "OpenTelemetry::Instrumentation::Que", - "racecar" => "OpenTelemetry::Instrumentation::Racecar", - "rack" => "OpenTelemetry::Instrumentation::Rack", - "rails" => "OpenTelemetry::Instrumentation::Rails", - "rake" => "OpenTelemetry::Instrumentation::Rake", - "rdkafka" => "OpenTelemetry::Instrumentation::Rdkafka", - "redis" => "OpenTelemetry::Instrumentation::Redis", - "restclient" => "OpenTelemetry::Instrumentation::RestClient", - "resque" => "OpenTelemetry::Instrumentation::Resque", - "ruby_kafka" => "OpenTelemetry::Instrumentation::RubyKafka", - "sidekiq" => "OpenTelemetry::Instrumentation::Sidekiq", - "sinatra" => "OpenTelemetry::Instrumentation::Sinatra" - } + 'gruf' => 'OpenTelemetry::Instrumentation::Gruf', + 'trilogy' => 'OpenTelemetry::Instrumentation::Trilogy', + 'active_support' => 'OpenTelemetry::Instrumentation::ActiveSupport', + 'action_pack' => 'OpenTelemetry::Instrumentation::ActionPack', + 'active_job' => 'OpenTelemetry::Instrumentation::ActiveJob', + 'active_record' => 'OpenTelemetry::Instrumentation::ActiveRecord', + 'action_view' => 'OpenTelemetry::Instrumentation::ActionView', + 'action_mailer' => 'OpenTelemetry::Instrumentation::ActionMailer', + 'aws_sdk' => 'OpenTelemetry::Instrumentation::AwsSdk', + 'aws_lambda' => 'OpenTelemetry::Instrumentation::AwsLambda', + 'bunny' => 'OpenTelemetry::Instrumentation::Bunny', + 'lmdb' => 'OpenTelemetry::Instrumentation::LMDB', + 'http' => 'OpenTelemetry::Instrumentation::HTTP', + 'koala' => 'OpenTelemetry::Instrumentation::Koala', + 'active_model_serializers' => 'OpenTelemetry::Instrumentation::ActiveModelSerializers', + 'concurrent_ruby' => 'OpenTelemetry::Instrumentation::ConcurrentRuby', + 'dalli' => 'OpenTelemetry::Instrumentation::Dalli', + 'delayed_job' => 'OpenTelemetry::Instrumentation::DelayedJob', + 'ethon' => 'OpenTelemetry::Instrumentation::Ethon', + 'excon' => 'OpenTelemetry::Instrumentation::Excon', + 'faraday' => 'OpenTelemetry::Instrumentation::Faraday', + 'grape' => 'OpenTelemetry::Instrumentation::Grape', + 'graphql' => 'OpenTelemetry::Instrumentation::GraphQL', + 'http_client' => 'OpenTelemetry::Instrumentation::HttpClient', + 'mongo' => 'OpenTelemetry::Instrumentation::Mongo', + 'mysql2' => 'OpenTelemetry::Instrumentation::Mysql2', + 'net_http' => 'OpenTelemetry::Instrumentation::Net::HTTP', + 'pg' => 'OpenTelemetry::Instrumentation::PG', + 'que' => 'OpenTelemetry::Instrumentation::Que', + 'racecar' => 'OpenTelemetry::Instrumentation::Racecar', + 'rack' => 'OpenTelemetry::Instrumentation::Rack', + 'rails' => 'OpenTelemetry::Instrumentation::Rails', + 'rake' => 'OpenTelemetry::Instrumentation::Rake', + 'rdkafka' => 'OpenTelemetry::Instrumentation::Rdkafka', + 'redis' => 'OpenTelemetry::Instrumentation::Redis', + 'restclient' => 'OpenTelemetry::Instrumentation::RestClient', + 'resque' => 'OpenTelemetry::Instrumentation::Resque', + 'ruby_kafka' => 'OpenTelemetry::Instrumentation::RubyKafka', + 'sidekiq' => 'OpenTelemetry::Instrumentation::Sidekiq', + 'sinatra' => 'OpenTelemetry::Instrumentation::Sinatra' + }.freeze def detect_resource_from_env env = ENV['OTEL_RUBY_RESOURCE_DETECTORS'].to_s @@ -63,11 +63,11 @@ def detect_resource_from_env env.split(',').each do |detector| case detector when 'container' - additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::Container.detect) if defined? (::OpenTelemetry::Resource::Detector::Container) + additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::Container.detect) if defined? ::OpenTelemetry::Resource::Detector::Container when 'google_cloud_platform' - additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::GoogleCloudPlatform.detect) if defined? (::OpenTelemetry::Resource::Detector::GoogleCloudPlatform) + additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::GoogleCloudPlatform.detect) if defined? ::OpenTelemetry::Resource::Detector::GoogleCloudPlatform when 'azure' - additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::Azure.detect) if defined? (::OpenTelemetry::Resource::Detector::Azure) + additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::Azure.detect) if defined? ::OpenTelemetry::Resource::Detector::Azure end end @@ -77,13 +77,11 @@ def detect_resource_from_env def determine_enabled_instrumentation env = ENV['OTEL_RUBY_ENABLED_INSTRUMENTATIONS'].to_s - enabled_instrumentation = [] - env.split(',').each { |instrumentation| enabled_instrumentation.push(OTEL_INSTRUMENTATION_MAP[instrumentation]) } - enabled_instrumentation + env.split(',').map { |instrumentation| OTEL_INSTRUMENTATION_MAP[instrumentation] } end def require_otel - lib = File.expand_path('../..', __FILE__) + lib = File.expand_path('..', __dir__) $LOAD_PATH.reject! { |path| path.include?('zero-code-instrumentation') } $LOAD_PATH.unshift(lib) @@ -92,7 +90,7 @@ def require_otel OpenTelemetry::SDK.configure do |c| c.resource = detect_resource_from_env - if required_instrumentation.size == 0 + if required_instrumentation.empty? c.use_all # enables all instrumentation! else required_instrumentation.each do |instrumentation| @@ -100,9 +98,9 @@ def require_otel end end end - OpenTelemetry.logger.info {"Auto-instrumentation initialized"} + OpenTelemetry.logger.info { 'Auto-instrumentation initialized' } rescue StandardError => e - OpenTelemetry.logger.info {"Auto-instrumentation failed to initialize. Error: #{e.message}"} + OpenTelemetry.logger.info { "Auto-instrumentation failed to initialize. Error: #{e.message}" } end end end @@ -118,7 +116,7 @@ def require_otel # assume the operator ruby image will amount the additional otel gem to this folder operator_gem_path = ENV['OTEL_OPERATOR'].to_s == 'true' ? '/otel-auto-instrumentation-ruby' : nil additional_gem_path = operator_gem_path || ENV['ADDITIONAL_GEM_PATH'] || Gem.dir - OpenTelemetry.logger.info { "Loading the additional gem path from #{additional_gem_path}"} + OpenTelemetry.logger.info { "Loading the additional gem path from #{additional_gem_path}" } # google-protobuf is used for otel trace exporter Dir.glob("#{additional_gem_path}/gems/*").each do |file| diff --git a/zero-code-instrumentation/test/zero-code-instrumentation_test.rb b/zero-code-instrumentation/test/zero-code-instrumentation_test.rb index f32f92c7fc..f49473370d 100644 --- a/zero-code-instrumentation/test/zero-code-instrumentation_test.rb +++ b/zero-code-instrumentation/test/zero-code-instrumentation_test.rb @@ -7,7 +7,6 @@ require 'test_helper' describe 'ZeroCodeInstrumentation' do - before do OpenTelemetry::TestHelpers.reset_opentelemetry end @@ -23,7 +22,6 @@ end it 'simple_load_test' do - load './lib/zero-code-instrumentation.rb' Bundler.require @@ -42,7 +40,6 @@ end it 'simple_load_with_net_http_disabled' do - ENV['OTEL_RUBY_INSTRUMENTATION_NET_HTTP_ENABLED'] = 'false' load './lib/zero-code-instrumentation.rb' @@ -57,7 +54,6 @@ end it 'simple_load_with_desired_instrument_only' do - ENV['OTEL_RUBY_ENABLED_INSTRUMENTATIONS'] = 'net_http' load './lib/zero-code-instrumentation.rb' @@ -72,7 +68,6 @@ end it 'simple_load_with_additional_resource' do - ENV['OTEL_RUBY_RESOURCE_DETECTORS'] = 'container' load './lib/zero-code-instrumentation.rb' diff --git a/zero-code-instrumentation/zero-code-instrumentation.gemspec b/zero-code-instrumentation/zero-code-instrumentation.gemspec index 5808aae632..9be5a995fe 100644 --- a/zero-code-instrumentation/zero-code-instrumentation.gemspec +++ b/zero-code-instrumentation/zero-code-instrumentation.gemspec @@ -26,14 +26,14 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] spec.required_ruby_version = '>= 3.1' - spec.add_dependency 'opentelemetry-sdk', '~> 1.0' - spec.add_dependency 'opentelemetry-instrumentation-all', '~> 0.72.0' spec.add_dependency 'opentelemetry-exporter-otlp', '~> 0.29.1' spec.add_dependency 'opentelemetry-helpers-mysql', '~> 0.2.0' spec.add_dependency 'opentelemetry-helpers-sql-obfuscation', '~> 0.3.0' - spec.add_dependency 'opentelemetry-resource-detector-google_cloud_platform', '~> 0.2.0' + spec.add_dependency 'opentelemetry-instrumentation-all', '~> 0.72.0' spec.add_dependency 'opentelemetry-resource-detector-azure', '~> 0.2.0' spec.add_dependency 'opentelemetry-resource-detector-container', '~> 0.2.0' + spec.add_dependency 'opentelemetry-resource-detector-google_cloud_platform', '~> 0.2.0' + spec.add_dependency 'opentelemetry-sdk', '~> 1.0' spec.add_development_dependency 'bundler', '~> 2.4' spec.add_development_dependency 'minitest', '~> 5.0' From 4c0c97b01331efdd0c2766f04c65e24b2b53f6a0 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Wed, 29 Jan 2025 15:06:05 -0500 Subject: [PATCH 03/44] rubocop --- zero-code-instrumentation/.rubocop.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 zero-code-instrumentation/.rubocop.yml diff --git a/zero-code-instrumentation/.rubocop.yml b/zero-code-instrumentation/.rubocop.yml new file mode 100644 index 0000000000..92a2a4f69e --- /dev/null +++ b/zero-code-instrumentation/.rubocop.yml @@ -0,0 +1,3 @@ +inherit_from: ../.rubocop.yml +Naming/FileName: + Enabled: false From 8a2fadd4f5d7f5695f837ed605f5f67ee1ab01d7 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Thu, 30 Jan 2025 13:42:40 -0500 Subject: [PATCH 04/44] enforce the dependencies version --- .../zero-code-instrumentation.gemspec | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/zero-code-instrumentation/zero-code-instrumentation.gemspec b/zero-code-instrumentation/zero-code-instrumentation.gemspec index 9be5a995fe..d7cfe61d95 100644 --- a/zero-code-instrumentation/zero-code-instrumentation.gemspec +++ b/zero-code-instrumentation/zero-code-instrumentation.gemspec @@ -26,14 +26,15 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] spec.required_ruby_version = '>= 3.1' - spec.add_dependency 'opentelemetry-exporter-otlp', '~> 0.29.1' - spec.add_dependency 'opentelemetry-helpers-mysql', '~> 0.2.0' - spec.add_dependency 'opentelemetry-helpers-sql-obfuscation', '~> 0.3.0' - spec.add_dependency 'opentelemetry-instrumentation-all', '~> 0.72.0' - spec.add_dependency 'opentelemetry-resource-detector-azure', '~> 0.2.0' - spec.add_dependency 'opentelemetry-resource-detector-container', '~> 0.2.0' - spec.add_dependency 'opentelemetry-resource-detector-google_cloud_platform', '~> 0.2.0' - spec.add_dependency 'opentelemetry-sdk', '~> 1.0' + spec.add_dependency 'opentelemetry-api', '1.4.0' + spec.add_dependency 'opentelemetry-exporter-otlp', '0.29.1' + spec.add_dependency 'opentelemetry-helpers-mysql', '0.2.0' + spec.add_dependency 'opentelemetry-helpers-sql-obfuscation', '0.3.0' + spec.add_dependency 'opentelemetry-instrumentation-all', '0.72.0' + spec.add_dependency 'opentelemetry-resource-detector-azure', '0.2.0' + spec.add_dependency 'opentelemetry-resource-detector-container', '0.2.0' + spec.add_dependency 'opentelemetry-resource-detector-google_cloud_platform', '0.2.0' + spec.add_dependency 'opentelemetry-sdk', '1.6.0' spec.add_development_dependency 'bundler', '~> 2.4' spec.add_development_dependency 'minitest', '~> 5.0' From f96a637fb0de32b0d2a517fee673a53f25c02cf3 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Fri, 14 Feb 2025 10:31:35 -0500 Subject: [PATCH 05/44] assume use bundle exec all the time --- zero-code-instrumentation/README.md | 1 - .../lib/zero-code-instrumentation.rb | 24 +++++++++---------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/zero-code-instrumentation/README.md b/zero-code-instrumentation/README.md index 1263908ef5..d252f39529 100644 --- a/zero-code-instrumentation/README.md +++ b/zero-code-instrumentation/README.md @@ -84,7 +84,6 @@ Instrument Rails application with `bundle exec` Since installing the `zero-code-instrumentation` gem through `gem install`, anything related to the OpenTelemetry gem won't be stored in Bundler's gem path. Therefore, users need to add an additional gem path that contains these gems prior to initialization. ```console -export GEM_PATH= RUBYOPT="-r {PUT YOUR GEM PATH}/gems/zero-code-instrumentation-0.1.0/lib/zero-code-instrumentation" bundle exec rails server ``` diff --git a/zero-code-instrumentation/lib/zero-code-instrumentation.rb b/zero-code-instrumentation/lib/zero-code-instrumentation.rb index 1ff6156cd9..04c7f1dc73 100644 --- a/zero-code-instrumentation/lib/zero-code-instrumentation.rb +++ b/zero-code-instrumentation/lib/zero-code-instrumentation.rb @@ -111,19 +111,17 @@ def require_otel google_cloud_platform = ENV['OTEL_RUBY_RESOURCE_DETECTORS'].to_s.include?('google_cloud_platform') azure = ENV['OTEL_RUBY_RESOURCE_DETECTORS'].to_s.include?('azure') -if ENV['USE_BUNDLE_EXEC'].to_s == 'true' - - # assume the operator ruby image will amount the additional otel gem to this folder - operator_gem_path = ENV['OTEL_OPERATOR'].to_s == 'true' ? '/otel-auto-instrumentation-ruby' : nil - additional_gem_path = operator_gem_path || ENV['ADDITIONAL_GEM_PATH'] || Gem.dir - OpenTelemetry.logger.info { "Loading the additional gem path from #{additional_gem_path}" } - - # google-protobuf is used for otel trace exporter - Dir.glob("#{additional_gem_path}/gems/*").each do |file| - if file.include?('opentelemetry') || file.include?('google') - puts file.inspect - $LOAD_PATH.unshift("#{file}/lib") - end +# set OTEL_OPERATOR to true if in autoinstrumentation-ruby image +# /otel-auto-instrumentation-ruby is set in operator ruby.go +operator_gem_path = ENV['OTEL_OPERATOR'].to_s == 'true' ? '/otel-auto-instrumentation-ruby' : nil +additional_gem_path = operator_gem_path || ENV['ADDITIONAL_GEM_PATH'] || Gem.dir +puts "Loading the additional gem path from #{additional_gem_path}" + +# google-protobuf is used for otel trace exporter +Dir.glob("#{additional_gem_path}/gems/*").each do |file| + if file.include?('opentelemetry') || file.include?('google') + puts "Unshift #{file.inspect}" + $LOAD_PATH.unshift("#{file}/lib") end end From 60a3ab2af642be7c302391c5d483be67e343522d Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Wed, 26 Feb 2025 13:51:11 -0500 Subject: [PATCH 06/44] update readme --- zero-code-instrumentation/README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/zero-code-instrumentation/README.md b/zero-code-instrumentation/README.md index 83f0bb0082..8f8d8928e8 100644 --- a/zero-code-instrumentation/README.md +++ b/zero-code-instrumentation/README.md @@ -23,16 +23,17 @@ gem install zero-code-instrumentation ``` Install zero-code-instrumentation will automatically install following gems: - - opentelemetry-sdk - opentelemetry-api - opentelemetry-instrumentation-all - opentelemetry-exporter-otlp - opentelemetry-helpers-mysql - opentelemetry-helpers-sql-obfuscation - opentelemetry-resource-detector-google_cloud_platform - opentelemetry-resource-detector-azure - opentelemetry-resource-detector-container +```console +opentelemetry-sdk +opentelemetry-api +opentelemetry-instrumentation-all +opentelemetry-exporter-otlp +opentelemetry-helpers-mysql +opentelemetry-helpers-sql-obfuscation +opentelemetry-resource-detector-google_cloud_platform +opentelemetry-resource-detector-azure +opentelemetry-resource-detector-container +``` Instrument your application: @@ -87,7 +88,7 @@ Since installing the `zero-code-instrumentation` gem through `gem install`, anyt RUBYOPT="-r {PUT YOUR GEM PATH}/gems/zero-code-instrumentation-0.1.0/lib/zero-code-instrumentation" bundle exec rails server ``` -Instrument Sinatra application with rackup: +Instrument Sinatra application with `rackup`: If you are using a Gemfile to install the required gems but without `Bundler.require`, set `REQUIRE_BUNDLER` to true. This way, `zero-code-instrumentation` will call `Bundler.require` to initialize the required gems prior to SDK initialization. @@ -147,5 +148,4 @@ The `zero-code-instrumentation` gem is distributed under the Apache 2.0 license. [community-meetings]: https://github.com/open-telemetry/community#community-meetings [slack-channel]: https://cloud-native.slack.com/archives/C01NWKKMKMY [discussions-url]: https://github.com/open-telemetry/opentelemetry-ruby/discussions -[k8sattributesprocessor-url]: https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/processor/k8sattributesprocessor/README.md [opentelemetry-operator]: https://github.com/open-telemetry/opentelemetry-operator From 35122254425ecd59c49580606d88929f1fcc8a5e Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Wed, 26 Feb 2025 14:00:12 -0500 Subject: [PATCH 07/44] cspell --- .cspell.yml | 1 + zero-code-instrumentation/README.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.cspell.yml b/.cspell.yml index c4217065cd..fc59c3d224 100644 --- a/.cspell.yml +++ b/.cspell.yml @@ -81,3 +81,4 @@ words: - webmocks - Xuan - yardoc + - rackup diff --git a/zero-code-instrumentation/README.md b/zero-code-instrumentation/README.md index 8f8d8928e8..abbab04976 100644 --- a/zero-code-instrumentation/README.md +++ b/zero-code-instrumentation/README.md @@ -88,7 +88,7 @@ Since installing the `zero-code-instrumentation` gem through `gem install`, anyt RUBYOPT="-r {PUT YOUR GEM PATH}/gems/zero-code-instrumentation-0.1.0/lib/zero-code-instrumentation" bundle exec rails server ``` -Instrument Sinatra application with `rackup`: +Instrument Sinatra application with rackup: If you are using a Gemfile to install the required gems but without `Bundler.require`, set `REQUIRE_BUNDLER` to true. This way, `zero-code-instrumentation` will call `Bundler.require` to initialize the required gems prior to SDK initialization. From 2c880da118156d9c266eda66d23c449245299847 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Wed, 16 Apr 2025 12:48:16 -0400 Subject: [PATCH 08/44] update the script --- .../lib/zero-code-instrumentation.rb | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/zero-code-instrumentation/lib/zero-code-instrumentation.rb b/zero-code-instrumentation/lib/zero-code-instrumentation.rb index f03f1bd6ac..40dd2bd138 100644 --- a/zero-code-instrumentation/lib/zero-code-instrumentation.rb +++ b/zero-code-instrumentation/lib/zero-code-instrumentation.rb @@ -100,7 +100,7 @@ def require_otel end OpenTelemetry.logger.info { 'Auto-instrumentation initialized' } rescue StandardError => e - OpenTelemetry.logger.info { "Auto-instrumentation failed to initialize. Error: #{e.message}" } + puts "Auto-instrumentation failed to initialize. Error: #{e.message}" end end end @@ -111,18 +111,27 @@ def require_otel google_cloud_platform = ENV['OTEL_RUBY_RESOURCE_DETECTORS'].to_s.include?('google_cloud_platform') azure = ENV['OTEL_RUBY_RESOURCE_DETECTORS'].to_s.include?('azure') -# set OTEL_OPERATOR to true if in autoinstrumentation-ruby image -# /otel-auto-instrumentation-ruby is set in operator ruby.go -operator_gem_path = ENV['OTEL_OPERATOR'].to_s == 'true' ? '/otel-auto-instrumentation-ruby' : nil +# set OTEL_OPERATOR to false if not in autoinstrumentation-ruby image, default to /otel-auto-instrumentation-ruby +# /otel-auto-instrumentation-ruby is set in opentelemetry-operator ruby.go +operator_gem_path = (ENV['OTEL_OPERATOR'].nil? || ENV['OTEL_OPERATOR'] == 'true') ? '/otel-auto-instrumentation-ruby' : nil additional_gem_path = operator_gem_path || ENV['ADDITIONAL_GEM_PATH'] || Gem.dir puts "Loading the additional gem path from #{additional_gem_path}" if ENV['ZERO_CODE_DEBUG'] == 'true' -# google-protobuf is used for otel trace exporter -Dir.glob("#{additional_gem_path}/gems/*").each do |file| - if file.include?('opentelemetry') || file.include?('google') - puts "Unshift #{file.inspect}" if ENV['ZERO_CODE_DEBUG'] == 'true' - $LOAD_PATH.unshift("#{file}/lib") - end +# use UNLOAD_LIBRARY to avoid certain gem preload (esp. google protobuf) +# e.g export UNLOAD_LIBRARY=google-protobuf;googleapis-common-protos-types +unload_libraries = ENV['UNLOAD_LIBRARY'].to_s.split(';') +loaded_library_file_path = Array.new + +Dir.glob("#{additional_gem_path}/gems/*").each do |file_path| + gem_name = file_path.match(/\/gems\/([^\/]+)-\d/)[1] + include_file = (file_path.include?('opentelemetry') || file_path.include?('google')) && !unload_libraries.include? gem_name + loaded_library_file_path << file_path if include_file +end + +puts loaded_library_file_path.to_s if ENV['ZERO_CODE_DEBUG'] == 'true' + +loaded_library_file_path.each do |file_path| + $LOAD_PATH.unshift("#{file_path}/lib") end require 'opentelemetry-sdk' From 76f6d0ef75e3319fb33352c0d3231c5081e2ce31 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Wed, 4 Jun 2025 11:22:10 -0400 Subject: [PATCH 09/44] Update zero-code-instrumentation/lib/version.rb Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- zero-code-instrumentation/lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zero-code-instrumentation/lib/version.rb b/zero-code-instrumentation/lib/version.rb index 001acd6202..57bc2eb570 100644 --- a/zero-code-instrumentation/lib/version.rb +++ b/zero-code-instrumentation/lib/version.rb @@ -4,4 +4,4 @@ # # SPDX-License-Identifier: Apache-2.0 -VERSION = '0.1.0' +VERSION = '0.0.0' From 90995f7fbb84b2d57d0d09c41b9847b3691fce35 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Wed, 4 Jun 2025 11:22:19 -0400 Subject: [PATCH 10/44] Update zero-code-instrumentation/CHANGELOG.md Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- zero-code-instrumentation/CHANGELOG.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/zero-code-instrumentation/CHANGELOG.md b/zero-code-instrumentation/CHANGELOG.md index de43fbf3d1..cba9d81adf 100644 --- a/zero-code-instrumentation/CHANGELOG.md +++ b/zero-code-instrumentation/CHANGELOG.md @@ -1,5 +1 @@ # Release History: zero-code-instrumentation - -### v0.1.0 / 2025-01-21 - -* Initial release From 917cb33245fc96fe102c8a6a7a026d66a0a78d8e Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Wed, 4 Jun 2025 11:24:30 -0400 Subject: [PATCH 11/44] Update zero-code-instrumentation/README.md Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- zero-code-instrumentation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zero-code-instrumentation/README.md b/zero-code-instrumentation/README.md index abbab04976..bf5607111d 100644 --- a/zero-code-instrumentation/README.md +++ b/zero-code-instrumentation/README.md @@ -10,7 +10,7 @@ OpenTelemetry provides a single set of APIs, libraries, agents, and collector se ## How does this gem fit in? -The `zero-code-instrumentation` gem provides an easy way to load and initialize the OpenTelemetry Ruby SDK. This gem is particularly used for the [OpenTelemetry Operator][opentelemetry-operator]. +The `zero-code-instrumentation` gem provides an easy way to load and initialize the OpenTelemetry Ruby SDK without changing your code initialize the SDK. This gem is particularly used with the [OpenTelemetry Operator][opentelemetry-operator]. ## How do I get started? From 072c44aff21c09115b252805f6a8344d6e26873f Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Wed, 4 Jun 2025 11:24:36 -0400 Subject: [PATCH 12/44] Update zero-code-instrumentation/README.md Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- zero-code-instrumentation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zero-code-instrumentation/README.md b/zero-code-instrumentation/README.md index bf5607111d..5881ec2f19 100644 --- a/zero-code-instrumentation/README.md +++ b/zero-code-instrumentation/README.md @@ -97,7 +97,7 @@ export REQUIRE_BUNDLER=true RUBYOPT="-r zero-code-instrumentation" rackup config.ru ``` -If wish to load some gem outside the Gemfile, then it needs to be placed in front of zero-code-instrumentation: +If you wish to load some gems outside the Gemfile, then they need to be placed in front of zero-code-instrumentation: ```console export BUNDLE_WITHOUT=development,test From dd16883242dcfb294fa60b60520ca4af8cbaebec Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Wed, 4 Jun 2025 11:24:42 -0400 Subject: [PATCH 13/44] Update zero-code-instrumentation/README.md Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- zero-code-instrumentation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zero-code-instrumentation/README.md b/zero-code-instrumentation/README.md index 5881ec2f19..1727c48c39 100644 --- a/zero-code-instrumentation/README.md +++ b/zero-code-instrumentation/README.md @@ -107,7 +107,7 @@ RUBYOPT="-r mysql2 -r zero-code-instrumentation" ruby application.rb ## Example -In example folder, execute the following commands should see the trace output. +In example folder, executing the following commands should result in trace output. ```console # if user don't want to install zero-code-instrumentation from rubygems.org From d4de6d032336e44b01b4e5f294871a35e9a6e279 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Wed, 4 Jun 2025 11:24:48 -0400 Subject: [PATCH 14/44] Update zero-code-instrumentation/README.md Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- zero-code-instrumentation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zero-code-instrumentation/README.md b/zero-code-instrumentation/README.md index 1727c48c39..e977433419 100644 --- a/zero-code-instrumentation/README.md +++ b/zero-code-instrumentation/README.md @@ -110,7 +110,7 @@ RUBYOPT="-r mysql2 -r zero-code-instrumentation" ruby application.rb In example folder, executing the following commands should result in trace output. ```console -# if user don't want to install zero-code-instrumentation from rubygems.org +# if the user doesn't want to install zero-code-instrumentation from rubygems.org # user can build the gem and install it with gem install *.gem gem install zero-code-instrumentation From 342084f946c16eda93e1d197f65b17287a33658b Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Wed, 4 Jun 2025 11:24:54 -0400 Subject: [PATCH 15/44] Update zero-code-instrumentation/README.md Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- zero-code-instrumentation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zero-code-instrumentation/README.md b/zero-code-instrumentation/README.md index e977433419..893333658c 100644 --- a/zero-code-instrumentation/README.md +++ b/zero-code-instrumentation/README.md @@ -111,7 +111,7 @@ In example folder, executing the following commands should result in trace outpu ```console # if the user doesn't want to install zero-code-instrumentation from rubygems.org -# user can build the gem and install it with gem install *.gem +# the user can build the gem and install it with gem install *.gem gem install zero-code-instrumentation bundle install From e1e4d20868a094c1a6306718bdcc6467252b881e Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Wed, 4 Jun 2025 11:37:59 -0400 Subject: [PATCH 16/44] Update zero-code-instrumentation/lib/zero-code-instrumentation.rb Co-authored-by: Ariel Valentin --- zero-code-instrumentation/lib/zero-code-instrumentation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zero-code-instrumentation/lib/zero-code-instrumentation.rb b/zero-code-instrumentation/lib/zero-code-instrumentation.rb index 40dd2bd138..5a2c1e5a36 100644 --- a/zero-code-instrumentation/lib/zero-code-instrumentation.rb +++ b/zero-code-instrumentation/lib/zero-code-instrumentation.rb @@ -128,7 +128,7 @@ def require_otel loaded_library_file_path << file_path if include_file end -puts loaded_library_file_path.to_s if ENV['ZERO_CODE_DEBUG'] == 'true' +puts "Loaded Library File Paths " + loaded_library_file_path.join(",") if ENV['ZERO_CODE_DEBUG'] == 'true' loaded_library_file_path.each do |file_path| $LOAD_PATH.unshift("#{file_path}/lib") From 2c2b9f8cbd63ee3ab9f47137982b1193936be1c5 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Wed, 4 Jun 2025 11:39:16 -0400 Subject: [PATCH 17/44] Update zero-code-instrumentation/lib/zero-code-instrumentation.rb Co-authored-by: Ariel Valentin --- zero-code-instrumentation/lib/zero-code-instrumentation.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/zero-code-instrumentation/lib/zero-code-instrumentation.rb b/zero-code-instrumentation/lib/zero-code-instrumentation.rb index 5a2c1e5a36..82d3680d65 100644 --- a/zero-code-instrumentation/lib/zero-code-instrumentation.rb +++ b/zero-code-instrumentation/lib/zero-code-instrumentation.rb @@ -122,10 +122,9 @@ def require_otel unload_libraries = ENV['UNLOAD_LIBRARY'].to_s.split(';') loaded_library_file_path = Array.new -Dir.glob("#{additional_gem_path}/gems/*").each do |file_path| +loaded_library_file_path = Dir.glob("#{additional_gem_path}/gems/*").select do |file_path| gem_name = file_path.match(/\/gems\/([^\/]+)-\d/)[1] - include_file = (file_path.include?('opentelemetry') || file_path.include?('google')) && !unload_libraries.include? gem_name - loaded_library_file_path << file_path if include_file + (file_path.include?('opentelemetry') || file_path.include?('google')) && !unload_libraries.include? gem_name end puts "Loaded Library File Paths " + loaded_library_file_path.join(",") if ENV['ZERO_CODE_DEBUG'] == 'true' From 01a8779d732aac2d832785ae1ebda5db16ed928b Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Wed, 4 Jun 2025 11:55:53 -0400 Subject: [PATCH 18/44] revision --- zero-code-instrumentation/README.md | 10 +++--- .../lib/zero-code-instrumentation.rb | 33 +++++++++---------- .../test/zero-code-instrumentation_test.rb | 3 +- .../zero-code-instrumentation.gemspec | 20 +++++------ 4 files changed, 32 insertions(+), 34 deletions(-) diff --git a/zero-code-instrumentation/README.md b/zero-code-instrumentation/README.md index abbab04976..3a82e0900c 100644 --- a/zero-code-instrumentation/README.md +++ b/zero-code-instrumentation/README.md @@ -126,13 +126,13 @@ These environment variables are not standard OpenTelemetry environment variables | Environment Variable | Description | Default | Example | |----------------------|-------------|---------|---------| -| `REQUIRE_BUNDLER` | Set to `true` if you are using Bundler to install gems but without `Bundler.require` in your script during initialization. | nil | N/A | -| `USE_BUNDLE_EXEC` | Set to `true` if initializing through `bundle exec`. | nil | N/A | -| `ADDITIONAL_GEM_PATH` | Intended to be used for the OpenTelemetry Operator environment if you install `zero-code-instrumentation` to a customized path. | nil | N/A | -| `OTEL_OPERATOR` | Set to `true` to set the binding path for the OpenTelemetry Operator. | `/otel-auto-instrumentation-ruby` | N/A | +| `OTEL_RUBY_REQUIRE_BUNDLER` | Set to `true` if you are using Bundler to install gems but without `Bundler.require` in your script during initialization. | nil | N/A | +| `OTEL_RUBY_ADDITIONAL_GEM_PATH` | Intended to be used for the OpenTelemetry Operator environment if you install `zero-code-instrumentation` to a customized path. | nil | N/A | +| `OTEL_RUBY_OPERATOR` | Set to `true` to set the binding path for the OpenTelemetry Operator. | `/otel-auto-instrumentation-ruby` | N/A | | `OTEL_RUBY_RESOURCE_DETECTORS` | Determine what kind of resource detector is needed. Currently supports `container`, `azure`, and `google_cloud_platform`. Use commas to separate multiple detectors. | nil | `container,azure` | | `OTEL_RUBY_ENABLED_INSTRUMENTATIONS` | Shortcut used when you only want to instrument one or a couple of particular libraries. | nil | `redis,active_record` | -| `ZERO_CODE_DEBUG` | Set to `true` if want to see some debug information. This to avoid preload logger gem | nil | N/A | +| `OTEL_RUBY_ZERO_CODE_DEBUG` | Set to `true` if want to see some debug information. This to avoid preload logger gem | nil | N/A | +| `OTEL_RUBY_UNLOAD_LIBRARY` | Use OTEL_RUBY_UNLOAD_LIBRARY to avoid certain gem preload (esp. google protobuf) | nil | N/A | ## How can I get involved? diff --git a/zero-code-instrumentation/lib/zero-code-instrumentation.rb b/zero-code-instrumentation/lib/zero-code-instrumentation.rb index 40dd2bd138..abd7122cb1 100644 --- a/zero-code-instrumentation/lib/zero-code-instrumentation.rb +++ b/zero-code-instrumentation/lib/zero-code-instrumentation.rb @@ -77,7 +77,7 @@ def detect_resource_from_env def determine_enabled_instrumentation env = ENV['OTEL_RUBY_ENABLED_INSTRUMENTATIONS'].to_s - env.split(',').map { |instrumentation| OTEL_INSTRUMENTATION_MAP[instrumentation] } + env.split(',').each_with_object({}) { |instrumentation, config| config[OTEL_INSTRUMENTATION_MAP[instrumentation]] = {} } end def require_otel @@ -90,13 +90,7 @@ def require_otel OpenTelemetry::SDK.configure do |c| c.resource = detect_resource_from_env - if required_instrumentation.empty? - c.use_all # enables all instrumentation! - else - required_instrumentation.each do |instrumentation| - c.use instrumentation - end - end + c.use_all(required_instrumentation) end OpenTelemetry.logger.info { 'Auto-instrumentation initialized' } rescue StandardError => e @@ -113,27 +107,30 @@ def require_otel # set OTEL_OPERATOR to false if not in autoinstrumentation-ruby image, default to /otel-auto-instrumentation-ruby # /otel-auto-instrumentation-ruby is set in opentelemetry-operator ruby.go -operator_gem_path = (ENV['OTEL_OPERATOR'].nil? || ENV['OTEL_OPERATOR'] == 'true') ? '/otel-auto-instrumentation-ruby' : nil -additional_gem_path = operator_gem_path || ENV['ADDITIONAL_GEM_PATH'] || Gem.dir -puts "Loading the additional gem path from #{additional_gem_path}" if ENV['ZERO_CODE_DEBUG'] == 'true' +operator_gem_path = (ENV['OTEL_RUBY_OPERATOR'].nil? || ENV['OTEL_RUBY_OPERATOR'] == 'true') ? '/otel-auto-instrumentation-ruby' : nil +additional_gem_path = operator_gem_path || ENV['OTEL_RUBY_ADDITIONAL_GEM_PATH'] || Gem.dir +puts "Loading the additional gem path from #{additional_gem_path}" if ENV['OTEL_RUBY_ZERO_CODE_DEBUG'] == 'true' -# use UNLOAD_LIBRARY to avoid certain gem preload (esp. google protobuf) -# e.g export UNLOAD_LIBRARY=google-protobuf;googleapis-common-protos-types -unload_libraries = ENV['UNLOAD_LIBRARY'].to_s.split(';') +# use OTEL_RUBY_UNLOAD_LIBRARY to avoid certain gem preload (esp. google protobuf) +# e.g export OTEL_RUBY_UNLOAD_LIBRARY=google-protobuf;googleapis-common-protos-types +unload_libraries = ENV['OTEL_RUBY_UNLOAD_LIBRARY'].to_s.split(';') loaded_library_file_path = Array.new Dir.glob("#{additional_gem_path}/gems/*").each do |file_path| gem_name = file_path.match(/\/gems\/([^\/]+)-\d/)[1] - include_file = (file_path.include?('opentelemetry') || file_path.include?('google')) && !unload_libraries.include? gem_name + include_file = (file_path.include?('opentelemetry') || file_path.include?('google')) && !unload_libraries.include?(gem_name) loaded_library_file_path << file_path if include_file end -puts loaded_library_file_path.to_s if ENV['ZERO_CODE_DEBUG'] == 'true' - loaded_library_file_path.each do |file_path| $LOAD_PATH.unshift("#{file_path}/lib") end +if ENV['OTEL_RUBY_ZERO_CODE_DEBUG'] == 'true' + puts loaded_library_file_path.to_s + puts "$LOAD_PATH #{$LOAD_PATH}" +end + require 'opentelemetry-sdk' require 'opentelemetry-instrumentation-all' require 'opentelemetry-helpers-mysql' @@ -146,4 +143,4 @@ def require_otel Bundler::Runtime.prepend(OTelBundlerPatch) -Bundler.require if ENV['REQUIRE_BUNDLER'].to_s == 'true' +Bundler.require if ENV['OTEL_RUBY_REQUIRE_BUNDLER'].to_s == 'true' diff --git a/zero-code-instrumentation/test/zero-code-instrumentation_test.rb b/zero-code-instrumentation/test/zero-code-instrumentation_test.rb index f49473370d..4825183d6e 100644 --- a/zero-code-instrumentation/test/zero-code-instrumentation_test.rb +++ b/zero-code-instrumentation/test/zero-code-instrumentation_test.rb @@ -19,6 +19,8 @@ OTelBundlerPatch.send(:undef_method, :require) OpenTelemetry::Instrumentation::Net::HTTP::Instrumentation.instance_variable_get(:@instance).instance_variable_set(:@installed, false) OpenTelemetry::Instrumentation::Rake::Instrumentation.instance_variable_get(:@instance).instance_variable_set(:@installed, false) + + ENV['OTEL_RUBY_ENABLED_INSTRUMENTATIONS'] = nil end it 'simple_load_test' do @@ -64,7 +66,6 @@ _(registry.size).must_equal 1 _(registry.first.first.name).must_equal 'OpenTelemetry::Instrumentation::Net::HTTP' - ENV['OTEL_RUBY_ENABLED_INSTRUMENTATIONS'] = nil end it 'simple_load_with_additional_resource' do diff --git a/zero-code-instrumentation/zero-code-instrumentation.gemspec b/zero-code-instrumentation/zero-code-instrumentation.gemspec index d7cfe61d95..7c057428d9 100644 --- a/zero-code-instrumentation/zero-code-instrumentation.gemspec +++ b/zero-code-instrumentation/zero-code-instrumentation.gemspec @@ -26,15 +26,15 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] spec.required_ruby_version = '>= 3.1' - spec.add_dependency 'opentelemetry-api', '1.4.0' - spec.add_dependency 'opentelemetry-exporter-otlp', '0.29.1' - spec.add_dependency 'opentelemetry-helpers-mysql', '0.2.0' - spec.add_dependency 'opentelemetry-helpers-sql-obfuscation', '0.3.0' - spec.add_dependency 'opentelemetry-instrumentation-all', '0.72.0' - spec.add_dependency 'opentelemetry-resource-detector-azure', '0.2.0' - spec.add_dependency 'opentelemetry-resource-detector-container', '0.2.0' - spec.add_dependency 'opentelemetry-resource-detector-google_cloud_platform', '0.2.0' - spec.add_dependency 'opentelemetry-sdk', '1.6.0' + spec.add_dependency 'opentelemetry-api', '~> 1.4.0' + spec.add_dependency 'opentelemetry-exporter-otlp', '~> 0.29.1' + spec.add_dependency 'opentelemetry-helpers-mysql', '~> 0.2.0' + spec.add_dependency 'opentelemetry-helpers-sql-obfuscation', '~> 0.3.0' + spec.add_dependency 'opentelemetry-instrumentation-all', '~> 0.72.0' + spec.add_dependency 'opentelemetry-resource-detector-azure', '~> 0.2.0' + spec.add_dependency 'opentelemetry-resource-detector-container', '~> 0.2.0' + spec.add_dependency 'opentelemetry-resource-detector-google_cloud_platform', '~> 0.2.0' + spec.add_dependency 'opentelemetry-sdk', '~> 1.6.0' spec.add_development_dependency 'bundler', '~> 2.4' spec.add_development_dependency 'minitest', '~> 5.0' @@ -51,5 +51,5 @@ Gem::Specification.new do |spec| spec.metadata['documentation_uri'] = "https://rubydoc.info/gems/#{spec.name}/#{spec.version}" end - spec.post_install_message = File.read(File.expand_path('../POST_INSTALL_MESSAGE', __dir__)) + # spec.post_install_message = File.read(File.expand_path('../POST_INSTALL_MESSAGE', __dir__)) end From 5104dd874451556f74aad9b25bb1612fede2e8c8 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 10 Jun 2025 14:51:57 -0400 Subject: [PATCH 19/44] change gem name --- .../.rubocop.yml | 0 .../CHANGELOG.md | 1 + .../Gemfile | 0 .../LICENSE | 0 .../README.md | 50 +++++++++---------- .../Rakefile | 0 .../example/Gemfile | 0 .../example/app.rb | 0 .../lib/opentelemetry-auto-instrumentation.rb | 0 .../lib/version.rb | 0 ...opentelemetry-auto-instrumentation.gemspec | 2 +- ...opentelemetry-auto-instrumentation_test.rb | 8 +-- .../test/test_helper.rb | 0 zero-code-instrumentation/CHANGELOG.md | 1 - 14 files changed, 31 insertions(+), 31 deletions(-) rename {zero-code-instrumentation => opentelemetry-auto-instrumentation}/.rubocop.yml (100%) create mode 100644 opentelemetry-auto-instrumentation/CHANGELOG.md rename {zero-code-instrumentation => opentelemetry-auto-instrumentation}/Gemfile (100%) rename {zero-code-instrumentation => opentelemetry-auto-instrumentation}/LICENSE (100%) rename {zero-code-instrumentation => opentelemetry-auto-instrumentation}/README.md (65%) rename {zero-code-instrumentation => opentelemetry-auto-instrumentation}/Rakefile (100%) rename {zero-code-instrumentation => opentelemetry-auto-instrumentation}/example/Gemfile (100%) rename {zero-code-instrumentation => opentelemetry-auto-instrumentation}/example/app.rb (100%) rename zero-code-instrumentation/lib/zero-code-instrumentation.rb => opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb (100%) rename {zero-code-instrumentation => opentelemetry-auto-instrumentation}/lib/version.rb (100%) rename zero-code-instrumentation/zero-code-instrumentation.gemspec => opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec (97%) rename zero-code-instrumentation/test/zero-code-instrumentation_test.rb => opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb (92%) rename {zero-code-instrumentation => opentelemetry-auto-instrumentation}/test/test_helper.rb (100%) delete mode 100644 zero-code-instrumentation/CHANGELOG.md diff --git a/zero-code-instrumentation/.rubocop.yml b/opentelemetry-auto-instrumentation/.rubocop.yml similarity index 100% rename from zero-code-instrumentation/.rubocop.yml rename to opentelemetry-auto-instrumentation/.rubocop.yml diff --git a/opentelemetry-auto-instrumentation/CHANGELOG.md b/opentelemetry-auto-instrumentation/CHANGELOG.md new file mode 100644 index 0000000000..d068b6d9e8 --- /dev/null +++ b/opentelemetry-auto-instrumentation/CHANGELOG.md @@ -0,0 +1 @@ +# Release History: opentelemetry-auto-instrumentation diff --git a/zero-code-instrumentation/Gemfile b/opentelemetry-auto-instrumentation/Gemfile similarity index 100% rename from zero-code-instrumentation/Gemfile rename to opentelemetry-auto-instrumentation/Gemfile diff --git a/zero-code-instrumentation/LICENSE b/opentelemetry-auto-instrumentation/LICENSE similarity index 100% rename from zero-code-instrumentation/LICENSE rename to opentelemetry-auto-instrumentation/LICENSE diff --git a/zero-code-instrumentation/README.md b/opentelemetry-auto-instrumentation/README.md similarity index 65% rename from zero-code-instrumentation/README.md rename to opentelemetry-auto-instrumentation/README.md index a32cf45557..365ffe14af 100644 --- a/zero-code-instrumentation/README.md +++ b/opentelemetry-auto-instrumentation/README.md @@ -1,6 +1,6 @@ -# Zero-code Instrumentation +# Opentelemetry Auto Instrumentation -The `zero-code-instrumentation` gem provides an easy way to load and initialize opentelemetry-ruby for zero-code instrumentation. +The `opentelemetry-auto-instrumentation` gem provides an easy way to load and initialize opentelemetry-ruby for zero-code instrumentation. ## What is OpenTelemetry? @@ -10,19 +10,19 @@ OpenTelemetry provides a single set of APIs, libraries, agents, and collector se ## How does this gem fit in? -The `zero-code-instrumentation` gem provides an easy way to load and initialize the OpenTelemetry Ruby SDK without changing your code initialize the SDK. This gem is particularly used with the [OpenTelemetry Operator][opentelemetry-operator]. +The `opentelemetry-auto-instrumentation` gem provides an easy way to load and initialize the OpenTelemetry Ruby SDK without changing your code initialize the SDK. This gem is particularly used with the [OpenTelemetry Operator][opentelemetry-operator]. ## How do I get started? -It's recommended to install this gem through gem install rather than Bundler since it doesn't require modifying any user's codebase (including the Gemfile). +It's recommended to install this gem through `gem install` rather than Bundler since it doesn't require modifying your codebase (including the Gemfile). Install the gem using: ```console -gem install zero-code-instrumentation +gem install opentelemetry-auto-instrumentation ``` -Install zero-code-instrumentation will automatically install following gems: +Installing opentelemetry-auto-instrumentation will automatically install following gems: ```console opentelemetry-sdk opentelemetry-api @@ -38,7 +38,7 @@ opentelemetry-resource-detector-container Instrument your application: ```console -RUBYOPT="-r zero-code-instrumentation" ruby application.rb +RUBYOPT="-r opentelemetry-auto-instrumentation" ruby application.rb ``` Instrument your application with additional environment variables: @@ -49,21 +49,21 @@ export OTEL_EXPORTER_OTLP_ENDPOINT="your-endpoint" export OTEL_RUBY_RESOURCE_DETECTORS="container" export OTEL_SERVICE_NAME="your-service-name" -RUBYOPT="-r zero-code-instrumentation" ruby application.rb +RUBYOPT="-r opentelemetry-auto-instrumentation" ruby application.rb ``` Instrument your application with disabling certain instrumentation (e.g. sinatra): ```console export OTEL_RUBY_INSTRUMENTATION_SINATRA_ENABLED='false' -RUBYOPT="-r zero-code-instrumentation" ruby application.rb +RUBYOPT="-r opentelemetry-auto-instrumentation" ruby application.rb ``` Instrument your application with only certain instrumentation installed (e.g. mysql, redis): ```console export OTEL_RUBY_ENABLED_INSTRUMENTATIONS='mysql2,redis' -RUBYOPT="-r zero-code-instrumentation" ruby application.rb +RUBYOPT="-r opentelemetry-auto-instrumentation" ruby application.rb ``` Instrument your application with only redis and configure its options: @@ -71,38 +71,38 @@ Instrument your application with only redis and configure its options: ```console export OTEL_RUBY_ENABLED_INSTRUMENTATIONS='redis' export OTEL_RUBY_INSTRUMENTATION_REDIS_CONFIG_OPTS='peer_service=new_service;db_statement=omit' -RUBYOPT="-r zero-code-instrumentation" ruby application.rb +RUBYOPT="-r opentelemetry-auto-instrumentation" ruby application.rb ``` Instrument Rails application: ```console -RUBYOPT="-r zero-code-instrumentation" rails server +RUBYOPT="-r opentelemetry-auto-instrumentation" rails server ``` -Instrument Rails application with `bundle exec` +Instrument Rails application with `bundle exec`: -Since installing the `zero-code-instrumentation` gem through `gem install`, anything related to the OpenTelemetry gem won't be stored in Bundler's gem path. Therefore, users need to add an additional gem path that contains these gems prior to initialization. +Since installing the `opentelemetry-auto-instrumentation` gem through `gem install`, anything related to the OpenTelemetry gem won't be stored in Bundler's gem path. Therefore, users need to add an additional gem path that contains these gems prior to initialization. ```console -RUBYOPT="-r {PUT YOUR GEM PATH}/gems/zero-code-instrumentation-0.1.0/lib/zero-code-instrumentation" bundle exec rails server +RUBYOPT="-r {PUT YOUR GEM PATH}/gems/opentelemetry-auto-instrumentation-0.1.0/lib/opentelemetry-auto-instrumentation" bundle exec rails server ``` Instrument Sinatra application with rackup: -If you are using a Gemfile to install the required gems but without `Bundler.require`, set `REQUIRE_BUNDLER` to true. This way, `zero-code-instrumentation` will call `Bundler.require` to initialize the required gems prior to SDK initialization. +If you are using a Gemfile to install the required gems but without `Bundler.require`, set `REQUIRE_BUNDLER` to true. This way, `opentelemetry-auto-instrumentation` will call `Bundler.require` to initialize the required gems prior to SDK initialization. ```console export REQUIRE_BUNDLER=true -RUBYOPT="-r zero-code-instrumentation" rackup config.ru +RUBYOPT="-r opentelemetry-auto-instrumentation" rackup config.ru ``` -If you wish to load some gems outside the Gemfile, then they need to be placed in front of zero-code-instrumentation: +If you wish to load some gems outside the Gemfile, then they need to be placed in front of opentelemetry-auto-instrumentation: ```console export BUNDLE_WITHOUT=development,test gem install mysql2 -RUBYOPT="-r mysql2 -r zero-code-instrumentation" ruby application.rb +RUBYOPT="-r mysql2 -r opentelemetry-auto-instrumentation" ruby application.rb ``` ## Example @@ -110,14 +110,14 @@ RUBYOPT="-r mysql2 -r zero-code-instrumentation" ruby application.rb In example folder, executing the following commands should result in trace output. ```console -# if the user doesn't want to install zero-code-instrumentation from rubygems.org +# if the user doesn't want to install opentelemetry-auto-instrumentation from rubygems.org # the user can build the gem and install it with gem install *.gem -gem install zero-code-instrumentation +gem install opentelemetry-auto-instrumentation bundle install export REQUIRE_BUNDLER=true export OTEL_TRACES_EXPORTER=console -RUBYOPT="-r zero-code-instrumentation" ruby app.rb +RUBYOPT="-r opentelemetry-auto-instrumentation" ruby app.rb ``` ## Configuration @@ -127,7 +127,7 @@ These environment variables are not standard OpenTelemetry environment variables | Environment Variable | Description | Default | Example | |----------------------|-------------|---------|---------| | `OTEL_RUBY_REQUIRE_BUNDLER` | Set to `true` if you are using Bundler to install gems but without `Bundler.require` in your script during initialization. | nil | N/A | -| `OTEL_RUBY_ADDITIONAL_GEM_PATH` | Intended to be used for the OpenTelemetry Operator environment if you install `zero-code-instrumentation` to a customized path. | nil | N/A | +| `OTEL_RUBY_ADDITIONAL_GEM_PATH` | Intended to be used for the OpenTelemetry Operator environment if you install `opentelemetry-auto-instrumentation` to a customized path. | nil | N/A | | `OTEL_RUBY_OPERATOR` | Set to `true` to set the binding path for the OpenTelemetry Operator. | `/otel-auto-instrumentation-ruby` | N/A | | `OTEL_RUBY_RESOURCE_DETECTORS` | Determine what kind of resource detector is needed. Currently supports `container`, `azure`, and `google_cloud_platform`. Use commas to separate multiple detectors. | nil | `container,azure` | | `OTEL_RUBY_ENABLED_INSTRUMENTATIONS` | Shortcut used when you only want to instrument one or a couple of particular libraries. | nil | `redis,active_record` | @@ -136,13 +136,13 @@ These environment variables are not standard OpenTelemetry environment variables ## How can I get involved? -The `zero-code-instrumentation` gem source is on GitHub, along with related gems. +The `opentelemetry-auto-instrumentation` gem source is on GitHub, along with related gems. The OpenTelemetry Ruby gems are maintained by the OpenTelemetry Ruby special interest group (SIG). You can get involved by joining us on our [GitHub Discussions][discussions-url], [Slack Channel][slack-channel] or attending our weekly meeting. See the [meeting calendar][community-meetings] for dates and times. For more information on this and other language SIGs, see the OpenTelemetry [community page][ruby-sig]. ## License -The `zero-code-instrumentation` gem is distributed under the Apache 2.0 license. See LICENSE for more information. +The `opentelemetry-auto-instrumentation` gem is distributed under the Apache 2.0 license. See LICENSE for more information. [ruby-sig]: https://github.com/open-telemetry/community#ruby-sig [community-meetings]: https://github.com/open-telemetry/community#community-meetings diff --git a/zero-code-instrumentation/Rakefile b/opentelemetry-auto-instrumentation/Rakefile similarity index 100% rename from zero-code-instrumentation/Rakefile rename to opentelemetry-auto-instrumentation/Rakefile diff --git a/zero-code-instrumentation/example/Gemfile b/opentelemetry-auto-instrumentation/example/Gemfile similarity index 100% rename from zero-code-instrumentation/example/Gemfile rename to opentelemetry-auto-instrumentation/example/Gemfile diff --git a/zero-code-instrumentation/example/app.rb b/opentelemetry-auto-instrumentation/example/app.rb similarity index 100% rename from zero-code-instrumentation/example/app.rb rename to opentelemetry-auto-instrumentation/example/app.rb diff --git a/zero-code-instrumentation/lib/zero-code-instrumentation.rb b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb similarity index 100% rename from zero-code-instrumentation/lib/zero-code-instrumentation.rb rename to opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb diff --git a/zero-code-instrumentation/lib/version.rb b/opentelemetry-auto-instrumentation/lib/version.rb similarity index 100% rename from zero-code-instrumentation/lib/version.rb rename to opentelemetry-auto-instrumentation/lib/version.rb diff --git a/zero-code-instrumentation/zero-code-instrumentation.gemspec b/opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec similarity index 97% rename from zero-code-instrumentation/zero-code-instrumentation.gemspec rename to opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec index 7c057428d9..df8e5a22f6 100644 --- a/zero-code-instrumentation/zero-code-instrumentation.gemspec +++ b/opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec @@ -9,7 +9,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'version' Gem::Specification.new do |spec| - spec.name = 'zero-code-instrumentation' + spec.name = 'opentelemetry-auto-instrumentation' spec.version = VERSION spec.authors = ['OpenTelemetry Authors'] spec.email = ['cncf-opentelemetry-contributors@lists.cncf.io'] diff --git a/zero-code-instrumentation/test/zero-code-instrumentation_test.rb b/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb similarity index 92% rename from zero-code-instrumentation/test/zero-code-instrumentation_test.rb rename to opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb index 12f00cd74c..d7ff916488 100644 --- a/zero-code-instrumentation/test/zero-code-instrumentation_test.rb +++ b/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb @@ -24,7 +24,7 @@ end it 'simple_load_test' do - load './lib/zero-code-instrumentation.rb' + load './lib/opentelemetry-auto-instrumentation.rb' Bundler.require _(OpenTelemetry.tracer_provider.class).must_equal OpenTelemetry::SDK::Trace::TracerProvider @@ -44,7 +44,7 @@ it 'simple_load_with_net_http_disabled' do ENV['OTEL_RUBY_INSTRUMENTATION_NET_HTTP_ENABLED'] = 'false' - load './lib/zero-code-instrumentation.rb' + load './lib/opentelemetry-auto-instrumentation.rb' Bundler.require registry = OpenTelemetry.tracer_provider.instance_variable_get(:@registry) @@ -58,7 +58,7 @@ it 'simple_load_with_desired_instrument_only' do ENV['OTEL_RUBY_ENABLED_INSTRUMENTATIONS'] = 'net_http' - load './lib/zero-code-instrumentation.rb' + load './lib/opentelemetry-auto-instrumentation.rb' Bundler.require registry = OpenTelemetry.tracer_provider.instance_variable_get(:@registry) @@ -70,7 +70,7 @@ it 'simple_load_with_additional_resource' do ENV['OTEL_RUBY_RESOURCE_DETECTORS'] = 'container' - load './lib/zero-code-instrumentation.rb' + load './lib/opentelemetry-auto-instrumentation.rb' Bundler.require resource_attributes = OpenTelemetry.tracer_provider.instance_variable_get(:@resource).instance_variable_get(:@attributes) diff --git a/zero-code-instrumentation/test/test_helper.rb b/opentelemetry-auto-instrumentation/test/test_helper.rb similarity index 100% rename from zero-code-instrumentation/test/test_helper.rb rename to opentelemetry-auto-instrumentation/test/test_helper.rb diff --git a/zero-code-instrumentation/CHANGELOG.md b/zero-code-instrumentation/CHANGELOG.md deleted file mode 100644 index cba9d81adf..0000000000 --- a/zero-code-instrumentation/CHANGELOG.md +++ /dev/null @@ -1 +0,0 @@ -# Release History: zero-code-instrumentation From 1e8c2b250becb3f87091887b346479139cae014f Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 17 Jun 2025 12:19:29 -0400 Subject: [PATCH 20/44] remove zero as reference name --- opentelemetry-auto-instrumentation/README.md | 4 ++-- .../lib/opentelemetry-auto-instrumentation.rb | 8 ++++---- .../opentelemetry-auto-instrumentation.gemspec | 6 +++--- .../test/opentelemetry-auto-instrumentation_test.rb | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/opentelemetry-auto-instrumentation/README.md b/opentelemetry-auto-instrumentation/README.md index 365ffe14af..f46cf23b8b 100644 --- a/opentelemetry-auto-instrumentation/README.md +++ b/opentelemetry-auto-instrumentation/README.md @@ -1,6 +1,6 @@ # Opentelemetry Auto Instrumentation -The `opentelemetry-auto-instrumentation` gem provides an easy way to load and initialize opentelemetry-ruby for zero-code instrumentation. +The `opentelemetry-auto-instrumentation` gem provides an easy way to load and initialize opentelemetry-ruby for auto instrumentation. ## What is OpenTelemetry? @@ -131,7 +131,7 @@ These environment variables are not standard OpenTelemetry environment variables | `OTEL_RUBY_OPERATOR` | Set to `true` to set the binding path for the OpenTelemetry Operator. | `/otel-auto-instrumentation-ruby` | N/A | | `OTEL_RUBY_RESOURCE_DETECTORS` | Determine what kind of resource detector is needed. Currently supports `container`, `azure`, and `google_cloud_platform`. Use commas to separate multiple detectors. | nil | `container,azure` | | `OTEL_RUBY_ENABLED_INSTRUMENTATIONS` | Shortcut used when you only want to instrument one or a couple of particular libraries. | nil | `redis,active_record` | -| `OTEL_RUBY_ZERO_CODE_DEBUG` | Set to `true` if want to see some debug information. This to avoid preload logger gem | nil | N/A | +| `OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG` | Set to `true` if want to see some debug information. This to avoid preload logger gem | nil | N/A | | `OTEL_RUBY_UNLOAD_LIBRARY` | Use OTEL_RUBY_UNLOAD_LIBRARY to avoid certain gem preload (esp. google protobuf) | nil | N/A | ## How can I get involved? diff --git a/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb index 16d22ca91c..40f8def965 100644 --- a/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb +++ b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb @@ -82,7 +82,7 @@ def determine_enabled_instrumentation def require_otel lib = File.expand_path('..', __dir__) - $LOAD_PATH.reject! { |path| path.include?('zero-code-instrumentation') } + $LOAD_PATH.reject! { |path| path.include?('opentelemetry-auto-instrumentation') } $LOAD_PATH.unshift(lib) begin @@ -115,7 +115,7 @@ def require_otel # /otel-auto-instrumentation-ruby is set in opentelemetry-operator ruby.go operator_gem_path = ENV['OTEL_RUBY_OPERATOR'].nil? || ENV['OTEL_RUBY_OPERATOR'] == 'true' ? '/otel-auto-instrumentation-ruby' : nil additional_gem_path = operator_gem_path || ENV['OTEL_RUBY_ADDITIONAL_GEM_PATH'] || Gem.dir -puts "Loading the additional gem path from #{additional_gem_path}" if ENV['OTEL_RUBY_ZERO_CODE_DEBUG'] == 'true' +puts "Loading the additional gem path from #{additional_gem_path}" if ENV['OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG'] == 'true' # use OTEL_RUBY_UNLOAD_LIBRARY to avoid certain gem preload (esp. google protobuf) # e.g export OTEL_RUBY_UNLOAD_LIBRARY=google-protobuf;googleapis-common-protos-types @@ -126,13 +126,13 @@ def require_otel (file_path.include?('opentelemetry') || file_path.include?('google')) && !unload_libraries.include?(gem_name) end -puts "Loaded Library File Paths #{loaded_library_file_path.join(',')}" if ENV['ZERO_CODE_DEBUG'] == 'true' +puts "Loaded Library File Paths #{loaded_library_file_path.join(',')}" if ENV['OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG'] == 'true' loaded_library_file_path.each do |file_path| $LOAD_PATH.unshift("#{file_path}/lib") end -puts "$LOAD_PATH after unshift: #{$LOAD_PATH.join(',')}" if ENV['OTEL_RUBY_ZERO_CODE_DEBUG'] == 'true' +puts "$LOAD_PATH after unshift: #{$LOAD_PATH.join(',')}" if ENV['OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG'] == 'true' require 'opentelemetry-sdk' require 'opentelemetry-instrumentation-all' diff --git a/opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec b/opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec index df8e5a22f6..418eae9673 100644 --- a/opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec +++ b/opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec @@ -14,8 +14,8 @@ Gem::Specification.new do |spec| spec.authors = ['OpenTelemetry Authors'] spec.email = ['cncf-opentelemetry-contributors@lists.cncf.io'] - spec.summary = 'Zero-code instrumentation for opentelemetry ruby' - spec.description = 'Zero-code instrumentation for opentelemetry ruby' + spec.summary = 'auto-instrumentation for opentelemetry ruby' + spec.description = 'auto-instrumentation for opentelemetry ruby' spec.homepage = 'https://github.com/open-telemetry/opentelemetry-ruby-contrib' spec.license = 'Apache-2.0' @@ -46,7 +46,7 @@ Gem::Specification.new do |spec| if spec.respond_to?(:metadata) spec.metadata['changelog_uri'] = "https://rubydoc.info/gems/#{spec.name}/#{spec.version}/file/CHANGELOG.md" - spec.metadata['source_code_uri'] = 'https://github.com/open-telemetry/opentelemetry-ruby-contrib/zero-code-instrumentation' + spec.metadata['source_code_uri'] = 'https://github.com/open-telemetry/opentelemetry-ruby-contrib/opentelemetry-auto-instrumentation' spec.metadata['bug_tracker_uri'] = 'https://github.com/open-telemetry/opentelemetry-ruby-contrib/issues' spec.metadata['documentation_uri'] = "https://rubydoc.info/gems/#{spec.name}/#{spec.version}" end diff --git a/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb b/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb index d7ff916488..06824b8381 100644 --- a/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb +++ b/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb @@ -6,7 +6,7 @@ require 'test_helper' -describe 'ZeroCodeInstrumentation' do +describe 'AutoInstrumentation' do before do OpenTelemetry::TestHelpers.reset_opentelemetry end From 1080edc4244db86dd1a4d04b33e8a23e91aeee1f Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Mon, 21 Jul 2025 14:12:05 -0400 Subject: [PATCH 21/44] Update opentelemetry-auto-instrumentation/README.md Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- opentelemetry-auto-instrumentation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-auto-instrumentation/README.md b/opentelemetry-auto-instrumentation/README.md index f46cf23b8b..714b648f91 100644 --- a/opentelemetry-auto-instrumentation/README.md +++ b/opentelemetry-auto-instrumentation/README.md @@ -130,7 +130,7 @@ These environment variables are not standard OpenTelemetry environment variables | `OTEL_RUBY_ADDITIONAL_GEM_PATH` | Intended to be used for the OpenTelemetry Operator environment if you install `opentelemetry-auto-instrumentation` to a customized path. | nil | N/A | | `OTEL_RUBY_OPERATOR` | Set to `true` to set the binding path for the OpenTelemetry Operator. | `/otel-auto-instrumentation-ruby` | N/A | | `OTEL_RUBY_RESOURCE_DETECTORS` | Determine what kind of resource detector is needed. Currently supports `container`, `azure`, and `google_cloud_platform`. Use commas to separate multiple detectors. | nil | `container,azure` | -| `OTEL_RUBY_ENABLED_INSTRUMENTATIONS` | Shortcut used when you only want to instrument one or a couple of particular libraries. | nil | `redis,active_record` | +| `OTEL_RUBY_ENABLED_INSTRUMENTATIONS` | Configuration used when you only want to install instrumentation for specific libraries. | nil | `redis,active_record` | | `OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG` | Set to `true` if want to see some debug information. This to avoid preload logger gem | nil | N/A | | `OTEL_RUBY_UNLOAD_LIBRARY` | Use OTEL_RUBY_UNLOAD_LIBRARY to avoid certain gem preload (esp. google protobuf) | nil | N/A | From 74c73f72ae92fcbf6af656c8ec8c1a0d56be725d Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Mon, 21 Jul 2025 14:12:13 -0400 Subject: [PATCH 22/44] Update opentelemetry-auto-instrumentation/README.md Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- opentelemetry-auto-instrumentation/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/opentelemetry-auto-instrumentation/README.md b/opentelemetry-auto-instrumentation/README.md index 714b648f91..33a5e875d1 100644 --- a/opentelemetry-auto-instrumentation/README.md +++ b/opentelemetry-auto-instrumentation/README.md @@ -35,6 +35,8 @@ opentelemetry-resource-detector-azure opentelemetry-resource-detector-container ``` +### Example installation strategies + Instrument your application: ```console From f024787ce303acea3acc7fe82f6fe84a7ad2538d Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Mon, 21 Jul 2025 14:12:28 -0400 Subject: [PATCH 23/44] Update .github/workflows/ci-contrib.yml Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- .github/workflows/ci-contrib.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-contrib.yml b/.github/workflows/ci-contrib.yml index f5523c00a3..19571a009c 100644 --- a/.github/workflows/ci-contrib.yml +++ b/.github/workflows/ci-contrib.yml @@ -238,7 +238,7 @@ jobs: gem: "opentelemetry-sampler-${{ matrix.gem }}" ruby: "jruby-9.4.12.0" - zero-code-instrumentation: + auto-instrumentation: strategy: fail-fast: false matrix: From 395ce32aac82247cb53402140c722d639b8a653b Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Mon, 21 Jul 2025 14:12:37 -0400 Subject: [PATCH 24/44] Update .github/workflows/ci-contrib.yml Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- .github/workflows/ci-contrib.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-contrib.yml b/.github/workflows/ci-contrib.yml index 19571a009c..94b7cdc8e5 100644 --- a/.github/workflows/ci-contrib.yml +++ b/.github/workflows/ci-contrib.yml @@ -243,7 +243,7 @@ jobs: fail-fast: false matrix: gem: - - zero-code-instrumentation + - auto-instrumentation os: - ubuntu-latest name: "${{ matrix.gem }} / ${{ matrix.os }}" From 5fe841952eb0a5112171ad292fc3302d2fcc142b Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Mon, 21 Jul 2025 14:12:45 -0400 Subject: [PATCH 25/44] Update opentelemetry-auto-instrumentation/README.md Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- opentelemetry-auto-instrumentation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-auto-instrumentation/README.md b/opentelemetry-auto-instrumentation/README.md index 33a5e875d1..715866a9c1 100644 --- a/opentelemetry-auto-instrumentation/README.md +++ b/opentelemetry-auto-instrumentation/README.md @@ -84,7 +84,7 @@ RUBYOPT="-r opentelemetry-auto-instrumentation" rails server Instrument Rails application with `bundle exec`: -Since installing the `opentelemetry-auto-instrumentation` gem through `gem install`, anything related to the OpenTelemetry gem won't be stored in Bundler's gem path. Therefore, users need to add an additional gem path that contains these gems prior to initialization. +Since the `opentelemetry-auto-instrumentation` gem should be installed through `gem install`, anything related to the OpenTelemetry gem won't be stored in Bundler's gem path. Therefore, users need to add an additional gem path that contains these gems prior to initialization. ```console RUBYOPT="-r {PUT YOUR GEM PATH}/gems/opentelemetry-auto-instrumentation-0.1.0/lib/opentelemetry-auto-instrumentation" bundle exec rails server From 56d7ba59d584292a4f43d509b111376c41000771 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Mon, 21 Jul 2025 14:12:54 -0400 Subject: [PATCH 26/44] Update opentelemetry-auto-instrumentation/README.md Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- opentelemetry-auto-instrumentation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-auto-instrumentation/README.md b/opentelemetry-auto-instrumentation/README.md index 715866a9c1..8b5a6c4a1c 100644 --- a/opentelemetry-auto-instrumentation/README.md +++ b/opentelemetry-auto-instrumentation/README.md @@ -133,7 +133,7 @@ These environment variables are not standard OpenTelemetry environment variables | `OTEL_RUBY_OPERATOR` | Set to `true` to set the binding path for the OpenTelemetry Operator. | `/otel-auto-instrumentation-ruby` | N/A | | `OTEL_RUBY_RESOURCE_DETECTORS` | Determine what kind of resource detector is needed. Currently supports `container`, `azure`, and `google_cloud_platform`. Use commas to separate multiple detectors. | nil | `container,azure` | | `OTEL_RUBY_ENABLED_INSTRUMENTATIONS` | Configuration used when you only want to install instrumentation for specific libraries. | nil | `redis,active_record` | -| `OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG` | Set to `true` if want to see some debug information. This to avoid preload logger gem | nil | N/A | +| `OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG` | Set to `true` if want to see some debug information. This to avoid preloading the logger gem | nil | N/A | | `OTEL_RUBY_UNLOAD_LIBRARY` | Use OTEL_RUBY_UNLOAD_LIBRARY to avoid certain gem preload (esp. google protobuf) | nil | N/A | ## How can I get involved? From cd42f0b67fbf02c8bee3442bc41a371bb8fedde7 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 22 Jul 2025 15:52:15 -0400 Subject: [PATCH 27/44] update --- .github/workflows/ci-contrib.yml | 5 +++++ .../base/lib/opentelemetry/instrumentation/base.rb | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-contrib.yml b/.github/workflows/ci-contrib.yml index a8b7ccf57a..85d9018a40 100644 --- a/.github/workflows/ci-contrib.yml +++ b/.github/workflows/ci-contrib.yml @@ -253,6 +253,11 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 + - name: "Test Ruby 3.4" + uses: ./.github/actions/test_gem + with: + gem: "${{ matrix.gem }}" + ruby: "3.4" - name: "Test Ruby 3.3" uses: ./.github/actions/test_gem with: diff --git a/instrumentation/base/lib/opentelemetry/instrumentation/base.rb b/instrumentation/base/lib/opentelemetry/instrumentation/base.rb index 7a13fe3f64..ddf8289551 100644 --- a/instrumentation/base/lib/opentelemetry/instrumentation/base.rb +++ b/instrumentation/base/lib/opentelemetry/instrumentation/base.rb @@ -214,7 +214,6 @@ def initialize(name, version, install_blk, present_blk, # # @param [Hash] config The config for this instrumentation def install(config = {}) - puts "name: #{@name}" return true if installed? @config = config_options(config) From c03917fdb291e50d86065bfcf3f4ff02e39b5998 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 22 Jul 2025 16:56:18 -0400 Subject: [PATCH 28/44] update workflow file --- .github/workflows/ci-contrib.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-contrib.yml b/.github/workflows/ci-contrib.yml index 85d9018a40..42cd3b3ede 100644 --- a/.github/workflows/ci-contrib.yml +++ b/.github/workflows/ci-contrib.yml @@ -277,7 +277,7 @@ jobs: rubocop: true build: true - name: "Test JRuby" - if: "${{ matrix.os == 'ubuntu-latest'" + if: "${{ matrix.os == 'ubuntu-latest' }}" uses: ./.github/actions/test_gem with: gem: "${{ matrix.gem }}" From 501918bf1da46e89f4dfb9cfeb08e6208a328f21 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 22 Jul 2025 17:13:51 -0400 Subject: [PATCH 29/44] update ci --- .github/workflows/ci-contrib.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-contrib.yml b/.github/workflows/ci-contrib.yml index 42cd3b3ede..3082a903b4 100644 --- a/.github/workflows/ci-contrib.yml +++ b/.github/workflows/ci-contrib.yml @@ -246,7 +246,7 @@ jobs: fail-fast: false matrix: gem: - - auto-instrumentation + - opentelemetry-auto-instrumentation os: - ubuntu-latest name: "${{ matrix.gem }} / ${{ matrix.os }}" From 5bd69ee80f42e5d18d8e5efd3b50a14059d59bee Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Wed, 23 Jul 2025 11:45:05 -0400 Subject: [PATCH 30/44] use custom ci for auto-instrumentation --- .github/workflows/ci-contrib.yml | 95 ++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/.github/workflows/ci-contrib.yml b/.github/workflows/ci-contrib.yml index 3082a903b4..4fffad60ec 100644 --- a/.github/workflows/ci-contrib.yml +++ b/.github/workflows/ci-contrib.yml @@ -242,43 +242,78 @@ jobs: ruby: "jruby-9.4.12.0" auto-instrumentation: - strategy: - fail-fast: false - matrix: - gem: - - opentelemetry-auto-instrumentation - os: - - ubuntu-latest - name: "${{ matrix.gem }} / ${{ matrix.os }}" - runs-on: ${{ matrix.os }} + name: "auto-instrumentation / ubuntu-latest" + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: "Test Ruby 3.4" - uses: ./.github/actions/test_gem + uses: ruby/setup-ruby@v1.247.0 with: - gem: "${{ matrix.gem }}" - ruby: "3.4" + ruby-version: "3.4" + - name: Test Gem + shell: bash + run: | + bundle install --quiet --jobs=3 --retry=4 + bundle exec rake test + rm -f Gemfile.lock + working-directory: './opentelemetry-auto-instrumentation' - name: "Test Ruby 3.3" - uses: ./.github/actions/test_gem + uses: ruby/setup-ruby@v1.247.0 with: - gem: "${{ matrix.gem }}" - ruby: "3.3" + ruby-version: "3.3" + - name: Test Gem + shell: bash + run: | + bundle install --quiet --jobs=3 --retry=4 + bundle exec rake test + rm -f Gemfile.lock + working-directory: './opentelemetry-auto-instrumentation' - name: "Test Ruby 3.2" - uses: ./.github/actions/test_gem + uses: ruby/setup-ruby@v1.247.0 with: - gem: "${{ matrix.gem }}" - ruby: "3.2" + ruby-version: "3.2" + - name: Test Gem + shell: bash + run: | + bundle install --quiet --jobs=3 --retry=4 + bundle exec rake test + rm -f Gemfile.lock + working-directory: './opentelemetry-auto-instrumentation' - name: "Test Ruby 3.1" - uses: ./.github/actions/test_gem + uses: ruby/setup-ruby@v1.247.0 with: - gem: "${{ matrix.gem }}" - ruby: "3.1" - yard: true - rubocop: true - build: true - - name: "Test JRuby" - if: "${{ matrix.os == 'ubuntu-latest' }}" - uses: ./.github/actions/test_gem - with: - gem: "${{ matrix.gem }}" - ruby: "jruby-9.4.12.0" + ruby-version: "3.1" + - name: Test Gem + shell: bash + run: | + bundle install --quiet --jobs=3 --retry=4 + bundle exec rake test + rm -f Gemfile.lock + working-directory: './opentelemetry-auto-instrumentation' + + - name: YARD + shell: bash + run: | + # 📄 Yard Docs 📄 + bundle exec rake yard + working-directory: './opentelemetry-auto-instrumentation' + + - name: Rubocop + shell: bash + run: | + # 🤖 Rubocop 🤖 + bundle exec rake rubocop + working-directory: './opentelemetry-auto-instrumentation' + + - name: Coverage + shell: bash + run: | + bundle exec ruby -e 'require "simplecov"; SimpleCov.minimum_coverage(85)' + working-directory: './opentelemetry-auto-instrumentation' + + - name: Build Gem + shell: bash + run: | + # 📦 Build Gem 📦 + gem build opentelemetry-auto-instrumentation.gemspec + working-directory: './opentelemetry-auto-instrumentation' From e625a8094453765bca36d561c9098475b884c531 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 29 Jul 2025 14:46:46 -0400 Subject: [PATCH 31/44] revision and fix ci --- .github/workflows/ci-contrib.yml | 92 +++----- opentelemetry-auto-instrumentation/Gemfile | 30 +-- opentelemetry-auto-instrumentation/README.md | 4 +- .../example/Gemfile | 1 - .../lib/opentelemetry-auto-instrumentation.rb | 199 ++++++++++-------- ...opentelemetry-auto-instrumentation.gemspec | 13 +- ...opentelemetry-auto-instrumentation_test.rb | 47 +++-- .../test/test_helper.rb | 6 +- 8 files changed, 189 insertions(+), 203 deletions(-) diff --git a/.github/workflows/ci-contrib.yml b/.github/workflows/ci-contrib.yml index 4fffad60ec..2755535b21 100644 --- a/.github/workflows/ci-contrib.yml +++ b/.github/workflows/ci-contrib.yml @@ -242,78 +242,38 @@ jobs: ruby: "jruby-9.4.12.0" auto-instrumentation: - name: "auto-instrumentation / ubuntu-latest" - runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + gem: + - opentelemetry-auto-instrumentation + os: + - ubuntu-latest + name: "${{ matrix.gem }} / ${{ matrix.os }}" + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - name: "Test Ruby 3.4" - uses: ruby/setup-ruby@v1.247.0 + uses: ./.github/actions/test_gem with: - ruby-version: "3.4" - - name: Test Gem - shell: bash - run: | - bundle install --quiet --jobs=3 --retry=4 - bundle exec rake test - rm -f Gemfile.lock - working-directory: './opentelemetry-auto-instrumentation' + gem: "${{ matrix.gem }}" + ruby: "3.4" - name: "Test Ruby 3.3" - uses: ruby/setup-ruby@v1.247.0 + uses: ./.github/actions/test_gem with: - ruby-version: "3.3" - - name: Test Gem - shell: bash - run: | - bundle install --quiet --jobs=3 --retry=4 - bundle exec rake test - rm -f Gemfile.lock - working-directory: './opentelemetry-auto-instrumentation' + gem: "${{ matrix.gem }}" + ruby: "3.3" - name: "Test Ruby 3.2" - uses: ruby/setup-ruby@v1.247.0 + uses: ./.github/actions/test_gem with: - ruby-version: "3.2" - - name: Test Gem - shell: bash - run: | - bundle install --quiet --jobs=3 --retry=4 - bundle exec rake test - rm -f Gemfile.lock - working-directory: './opentelemetry-auto-instrumentation' - - name: "Test Ruby 3.1" - uses: ruby/setup-ruby@v1.247.0 + gem: "${{ matrix.gem }}" + ruby: "3.2" + yard: true + rubocop: true + build: true + - name: "Test JRuby" + if: "${{ matrix.os == 'ubuntu-latest' }}" + uses: ./.github/actions/test_gem with: - ruby-version: "3.1" - - name: Test Gem - shell: bash - run: | - bundle install --quiet --jobs=3 --retry=4 - bundle exec rake test - rm -f Gemfile.lock - working-directory: './opentelemetry-auto-instrumentation' - - - name: YARD - shell: bash - run: | - # 📄 Yard Docs 📄 - bundle exec rake yard - working-directory: './opentelemetry-auto-instrumentation' - - - name: Rubocop - shell: bash - run: | - # 🤖 Rubocop 🤖 - bundle exec rake rubocop - working-directory: './opentelemetry-auto-instrumentation' - - - name: Coverage - shell: bash - run: | - bundle exec ruby -e 'require "simplecov"; SimpleCov.minimum_coverage(85)' - working-directory: './opentelemetry-auto-instrumentation' - - - name: Build Gem - shell: bash - run: | - # 📦 Build Gem 📦 - gem build opentelemetry-auto-instrumentation.gemspec - working-directory: './opentelemetry-auto-instrumentation' + gem: "${{ matrix.gem }}" + ruby: "jruby-9.4.12.0" diff --git a/opentelemetry-auto-instrumentation/Gemfile b/opentelemetry-auto-instrumentation/Gemfile index 793db3cb15..2e60a70be6 100644 --- a/opentelemetry-auto-instrumentation/Gemfile +++ b/opentelemetry-auto-instrumentation/Gemfile @@ -6,18 +6,20 @@ source 'https://rubygems.org' -# avoid use gemspec to avoid circular load +gemspec -gem 'opentelemetry-sdk' -gem 'opentelemetry-instrumentation-all' -gem 'opentelemetry-exporter-otlp' -gem 'opentelemetry-test-helpers' -gem 'opentelemetry-resource-detector-container', path: '../resources/container' - -gem 'bundler' -gem 'minitest' -gem 'rake' -gem 'rubocop' -gem 'rubocop-performance' -gem 'simplecov' -gem 'yard' +group :test do + gem 'bundler' + gem 'minitest' + gem 'rake' + gem 'rubocop' + gem 'rubocop-performance' + gem 'simplecov' + gem 'yard' + gem 'opentelemetry-test-helpers' + if RUBY_VERSION >= '3.4' + gem 'base64' + gem 'bigdecimal' + gem 'mutex_m' + end +end \ No newline at end of file diff --git a/opentelemetry-auto-instrumentation/README.md b/opentelemetry-auto-instrumentation/README.md index 8b5a6c4a1c..52cc13b6e2 100644 --- a/opentelemetry-auto-instrumentation/README.md +++ b/opentelemetry-auto-instrumentation/README.md @@ -117,9 +117,7 @@ In example folder, executing the following commands should result in trace outpu gem install opentelemetry-auto-instrumentation bundle install -export REQUIRE_BUNDLER=true -export OTEL_TRACES_EXPORTER=console -RUBYOPT="-r opentelemetry-auto-instrumentation" ruby app.rb +OTEL_RUBY_REQUIRE_BUNDLER=true OTEL_TRACES_EXPORTER=console RUBYOPT="-r opentelemetry-auto-instrumentation" OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG=false OTEL_RUBY_OPERATOR=false ruby app.rb ``` ## Configuration diff --git a/opentelemetry-auto-instrumentation/example/Gemfile b/opentelemetry-auto-instrumentation/example/Gemfile index a8b0038780..c9721cb670 100644 --- a/opentelemetry-auto-instrumentation/example/Gemfile +++ b/opentelemetry-auto-instrumentation/example/Gemfile @@ -1,3 +1,2 @@ source 'https://rubygems.org' -gem 'net-http' diff --git a/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb index 40f8def965..61116b7cc5 100644 --- a/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb +++ b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb @@ -6,107 +6,123 @@ # OTelBundlerPatch module OTelBundlerPatch - # ref: https://github.com/newrelic/newrelic-ruby-agent/blob/dev/lib/boot/strap.rb - def require(*_groups) - super - require_otel - end + # Nested module to handle OpenTelemetry initialization + module Initializer + # this is used for case when user particularly want to enable single instrumentation + unless defined?(OTEL_INSTRUMENTATION_MAP) + OTEL_INSTRUMENTATION_MAP = { + 'gruf' => 'OpenTelemetry::Instrumentation::Gruf', + 'trilogy' => 'OpenTelemetry::Instrumentation::Trilogy', + 'active_support' => 'OpenTelemetry::Instrumentation::ActiveSupport', + 'action_pack' => 'OpenTelemetry::Instrumentation::ActionPack', + 'active_job' => 'OpenTelemetry::Instrumentation::ActiveJob', + 'active_record' => 'OpenTelemetry::Instrumentation::ActiveRecord', + 'action_view' => 'OpenTelemetry::Instrumentation::ActionView', + 'action_mailer' => 'OpenTelemetry::Instrumentation::ActionMailer', + 'aws_sdk' => 'OpenTelemetry::Instrumentation::AwsSdk', + 'aws_lambda' => 'OpenTelemetry::Instrumentation::AwsLambda', + 'bunny' => 'OpenTelemetry::Instrumentation::Bunny', + 'lmdb' => 'OpenTelemetry::Instrumentation::LMDB', + 'http' => 'OpenTelemetry::Instrumentation::HTTP', + 'koala' => 'OpenTelemetry::Instrumentation::Koala', + 'active_model_serializers' => 'OpenTelemetry::Instrumentation::ActiveModelSerializers', + 'concurrent_ruby' => 'OpenTelemetry::Instrumentation::ConcurrentRuby', + 'dalli' => 'OpenTelemetry::Instrumentation::Dalli', + 'delayed_job' => 'OpenTelemetry::Instrumentation::DelayedJob', + 'ethon' => 'OpenTelemetry::Instrumentation::Ethon', + 'excon' => 'OpenTelemetry::Instrumentation::Excon', + 'faraday' => 'OpenTelemetry::Instrumentation::Faraday', + 'grape' => 'OpenTelemetry::Instrumentation::Grape', + 'graphql' => 'OpenTelemetry::Instrumentation::GraphQL', + 'http_client' => 'OpenTelemetry::Instrumentation::HttpClient', + 'mongo' => 'OpenTelemetry::Instrumentation::Mongo', + 'mysql2' => 'OpenTelemetry::Instrumentation::Mysql2', + 'net_http' => 'OpenTelemetry::Instrumentation::Net::HTTP', + 'pg' => 'OpenTelemetry::Instrumentation::PG', + 'que' => 'OpenTelemetry::Instrumentation::Que', + 'racecar' => 'OpenTelemetry::Instrumentation::Racecar', + 'rack' => 'OpenTelemetry::Instrumentation::Rack', + 'rails' => 'OpenTelemetry::Instrumentation::Rails', + 'rake' => 'OpenTelemetry::Instrumentation::Rake', + 'rdkafka' => 'OpenTelemetry::Instrumentation::Rdkafka', + 'redis' => 'OpenTelemetry::Instrumentation::Redis', + 'restclient' => 'OpenTelemetry::Instrumentation::RestClient', + 'resque' => 'OpenTelemetry::Instrumentation::Resque', + 'ruby_kafka' => 'OpenTelemetry::Instrumentation::RubyKafka', + 'sidekiq' => 'OpenTelemetry::Instrumentation::Sidekiq', + 'sinatra' => 'OpenTelemetry::Instrumentation::Sinatra' + }.freeze + end + + class << self + def detect_resource_from_env + env = ENV['OTEL_RUBY_RESOURCE_DETECTORS'].to_s + additional_resource = ::OpenTelemetry::SDK::Resources::Resource.create({}) + + env.split(',').each do |detector| + case detector + when 'container' + additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::Container.detect) if defined? ::OpenTelemetry::Resource::Detector::Container + when 'google_cloud_platform' + additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::GoogleCloudPlatform.detect) if defined? ::OpenTelemetry::Resource::Detector::GoogleCloudPlatform + when 'azure' + additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::Azure.detect) if defined? ::OpenTelemetry::Resource::Detector::Azure + when 'aws' + additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::AWS.detect([:ec2, :ecs, :eks, :lambda])) if defined? ::OpenTelemetry::Resource::Detector::AWS + end + end - # this is used for case when user particularly want to enable single instrumentation - OTEL_INSTRUMENTATION_MAP = { - 'gruf' => 'OpenTelemetry::Instrumentation::Gruf', - 'trilogy' => 'OpenTelemetry::Instrumentation::Trilogy', - 'active_support' => 'OpenTelemetry::Instrumentation::ActiveSupport', - 'action_pack' => 'OpenTelemetry::Instrumentation::ActionPack', - 'active_job' => 'OpenTelemetry::Instrumentation::ActiveJob', - 'active_record' => 'OpenTelemetry::Instrumentation::ActiveRecord', - 'action_view' => 'OpenTelemetry::Instrumentation::ActionView', - 'action_mailer' => 'OpenTelemetry::Instrumentation::ActionMailer', - 'aws_sdk' => 'OpenTelemetry::Instrumentation::AwsSdk', - 'aws_lambda' => 'OpenTelemetry::Instrumentation::AwsLambda', - 'bunny' => 'OpenTelemetry::Instrumentation::Bunny', - 'lmdb' => 'OpenTelemetry::Instrumentation::LMDB', - 'http' => 'OpenTelemetry::Instrumentation::HTTP', - 'koala' => 'OpenTelemetry::Instrumentation::Koala', - 'active_model_serializers' => 'OpenTelemetry::Instrumentation::ActiveModelSerializers', - 'concurrent_ruby' => 'OpenTelemetry::Instrumentation::ConcurrentRuby', - 'dalli' => 'OpenTelemetry::Instrumentation::Dalli', - 'delayed_job' => 'OpenTelemetry::Instrumentation::DelayedJob', - 'ethon' => 'OpenTelemetry::Instrumentation::Ethon', - 'excon' => 'OpenTelemetry::Instrumentation::Excon', - 'faraday' => 'OpenTelemetry::Instrumentation::Faraday', - 'grape' => 'OpenTelemetry::Instrumentation::Grape', - 'graphql' => 'OpenTelemetry::Instrumentation::GraphQL', - 'http_client' => 'OpenTelemetry::Instrumentation::HttpClient', - 'mongo' => 'OpenTelemetry::Instrumentation::Mongo', - 'mysql2' => 'OpenTelemetry::Instrumentation::Mysql2', - 'net_http' => 'OpenTelemetry::Instrumentation::Net::HTTP', - 'pg' => 'OpenTelemetry::Instrumentation::PG', - 'que' => 'OpenTelemetry::Instrumentation::Que', - 'racecar' => 'OpenTelemetry::Instrumentation::Racecar', - 'rack' => 'OpenTelemetry::Instrumentation::Rack', - 'rails' => 'OpenTelemetry::Instrumentation::Rails', - 'rake' => 'OpenTelemetry::Instrumentation::Rake', - 'rdkafka' => 'OpenTelemetry::Instrumentation::Rdkafka', - 'redis' => 'OpenTelemetry::Instrumentation::Redis', - 'restclient' => 'OpenTelemetry::Instrumentation::RestClient', - 'resque' => 'OpenTelemetry::Instrumentation::Resque', - 'ruby_kafka' => 'OpenTelemetry::Instrumentation::RubyKafka', - 'sidekiq' => 'OpenTelemetry::Instrumentation::Sidekiq', - 'sinatra' => 'OpenTelemetry::Instrumentation::Sinatra' - }.freeze - - def detect_resource_from_env - env = ENV['OTEL_RUBY_RESOURCE_DETECTORS'].to_s - additional_resource = ::OpenTelemetry::SDK::Resources::Resource.create({}) - - env.split(',').each do |detector| - case detector - when 'container' - additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::Container.detect) if defined? ::OpenTelemetry::Resource::Detector::Container - when 'google_cloud_platform' - additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::GoogleCloudPlatform.detect) if defined? ::OpenTelemetry::Resource::Detector::GoogleCloudPlatform - when 'azure' - additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::Azure.detect) if defined? ::OpenTelemetry::Resource::Detector::Azure + additional_resource end - end - additional_resource - end + def determine_enabled_instrumentation + env = ENV['OTEL_RUBY_ENABLED_INSTRUMENTATIONS'].to_s - def determine_enabled_instrumentation - env = ENV['OTEL_RUBY_ENABLED_INSTRUMENTATIONS'].to_s + env.split(',').map { |instrumentation| OTEL_INSTRUMENTATION_MAP[instrumentation] } + end - env.split(',').map { |instrumentation| OTEL_INSTRUMENTATION_MAP[instrumentation] } - end + def setup_load_path + lib = File.expand_path('..', __dir__) + $LOAD_PATH.reject! { |path| path.include?('opentelemetry-auto-instrumentation') } + $LOAD_PATH.unshift(lib) + end - def require_otel - lib = File.expand_path('..', __dir__) - $LOAD_PATH.reject! { |path| path.include?('opentelemetry-auto-instrumentation') } - $LOAD_PATH.unshift(lib) - - begin - required_instrumentation = determine_enabled_instrumentation - - OpenTelemetry::SDK.configure do |c| - c.resource = detect_resource_from_env - if required_instrumentation.empty? - c.use_all # enables all instrumentation! - else - required_instrumentation.each do |instrumentation| - c.use instrumentation + def initialize_opentelemetry + setup_load_path + + begin + required_instrumentation = determine_enabled_instrumentation + + OpenTelemetry::SDK.configure do |c| + c.resource = detect_resource_from_env + if required_instrumentation.empty? + c.use_all # enables all instrumentation! + else + required_instrumentation.each do |instrumentation| + c.use instrumentation + end + end end + OpenTelemetry.logger.info { 'Auto-instrumentation initialized' } + rescue StandardError => e + $stderr.puts "Auto-instrumentation failed to initialize. Error: #{e.message}" end end - OpenTelemetry.logger.info { 'Auto-instrumentation initialized' } - rescue StandardError => e - puts "Auto-instrumentation failed to initialize. Error: #{e.message}" + end + end + + # ref: https://github.com/newrelic/newrelic-ruby-agent/blob/dev/lib/boot/strap.rb + unless method_defined?(:require) + def require(...) + super + Initializer.initialize_opentelemetry end end end require 'bundler' +aws = ENV['OTEL_RUBY_RESOURCE_DETECTORS'].to_s.include?('aws') container = ENV['OTEL_RUBY_RESOURCE_DETECTORS'].to_s.include?('container') google_cloud_platform = ENV['OTEL_RUBY_RESOURCE_DETECTORS'].to_s.include?('google_cloud_platform') azure = ENV['OTEL_RUBY_RESOURCE_DETECTORS'].to_s.include?('azure') @@ -115,7 +131,7 @@ def require_otel # /otel-auto-instrumentation-ruby is set in opentelemetry-operator ruby.go operator_gem_path = ENV['OTEL_RUBY_OPERATOR'].nil? || ENV['OTEL_RUBY_OPERATOR'] == 'true' ? '/otel-auto-instrumentation-ruby' : nil additional_gem_path = operator_gem_path || ENV['OTEL_RUBY_ADDITIONAL_GEM_PATH'] || Gem.dir -puts "Loading the additional gem path from #{additional_gem_path}" if ENV['OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG'] == 'true' +$stdout.puts "Loading the additional gem path from #{additional_gem_path}" if ENV['OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG'] == 'true' # use OTEL_RUBY_UNLOAD_LIBRARY to avoid certain gem preload (esp. google protobuf) # e.g export OTEL_RUBY_UNLOAD_LIBRARY=google-protobuf;googleapis-common-protos-types @@ -126,24 +142,23 @@ def require_otel (file_path.include?('opentelemetry') || file_path.include?('google')) && !unload_libraries.include?(gem_name) end -puts "Loaded Library File Paths #{loaded_library_file_path.join(',')}" if ENV['OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG'] == 'true' +$stdout.puts "Loaded Library File Paths #{loaded_library_file_path.join(',')}" if ENV['OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG'] == 'true' loaded_library_file_path.each do |file_path| $LOAD_PATH.unshift("#{file_path}/lib") end -puts "$LOAD_PATH after unshift: #{$LOAD_PATH.join(',')}" if ENV['OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG'] == 'true' +$stdout.puts "$LOAD_PATH after unshift: #{$LOAD_PATH.join(',')}" if ENV['OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG'] == 'true' require 'opentelemetry-sdk' require 'opentelemetry-instrumentation-all' -require 'opentelemetry-helpers-mysql' -require 'opentelemetry-helpers-sql-obfuscation' require 'opentelemetry-exporter-otlp' require 'opentelemetry-resource-detector-container' if container require 'opentelemetry-resource-detector-google_cloud_platform' if google_cloud_platform require 'opentelemetry-resource-detector-azure' if azure +require 'opentelemetry-resource-detector-aws' if aws Bundler::Runtime.prepend(OTelBundlerPatch) -Bundler.require if ENV['OTEL_RUBY_REQUIRE_BUNDLER'].to_s == 'true' +Bundler.require if ENV['OTEL_RUBY_REQUIRE_BUNDLER'] == 'true' diff --git a/opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec b/opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec index 418eae9673..ae66211d3f 100644 --- a/opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec +++ b/opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec @@ -24,7 +24,7 @@ Gem::Specification.new do |spec| ['LICENSE'] spec.require_paths = ['lib'] - spec.required_ruby_version = '>= 3.1' + spec.required_ruby_version = '>= 3.2' spec.add_dependency 'opentelemetry-api', '~> 1.4.0' spec.add_dependency 'opentelemetry-exporter-otlp', '~> 0.29.1' @@ -34,22 +34,13 @@ Gem::Specification.new do |spec| spec.add_dependency 'opentelemetry-resource-detector-azure', '~> 0.2.0' spec.add_dependency 'opentelemetry-resource-detector-container', '~> 0.2.0' spec.add_dependency 'opentelemetry-resource-detector-google_cloud_platform', '~> 0.2.0' + spec.add_dependency 'opentelemetry-resource-detector-aws', '~> 0.2.0' spec.add_dependency 'opentelemetry-sdk', '~> 1.6.0' - 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.69.1' - spec.add_development_dependency 'rubocop-performance', '~> 1.23.0' - spec.add_development_dependency 'simplecov', '~> 0.17' - spec.add_development_dependency 'yard', '~> 0.9' - if spec.respond_to?(:metadata) spec.metadata['changelog_uri'] = "https://rubydoc.info/gems/#{spec.name}/#{spec.version}/file/CHANGELOG.md" spec.metadata['source_code_uri'] = 'https://github.com/open-telemetry/opentelemetry-ruby-contrib/opentelemetry-auto-instrumentation' spec.metadata['bug_tracker_uri'] = 'https://github.com/open-telemetry/opentelemetry-ruby-contrib/issues' spec.metadata['documentation_uri'] = "https://rubydoc.info/gems/#{spec.name}/#{spec.version}" end - - # spec.post_install_message = File.read(File.expand_path('../POST_INSTALL_MESSAGE', __dir__)) end diff --git a/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb b/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb index 06824b8381..3c866e2644 100644 --- a/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb +++ b/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb @@ -12,15 +12,32 @@ end after do - OTelBundlerPatch.send(:remove_const, :OTEL_INSTRUMENTATION_MAP) - OTelBundlerPatch.send(:undef_method, :detect_resource_from_env) - OTelBundlerPatch.send(:undef_method, :determine_enabled_instrumentation) - OTelBundlerPatch.send(:undef_method, :require_otel) - OTelBundlerPatch.send(:undef_method, :require) - OpenTelemetry::Instrumentation::Net::HTTP::Instrumentation.instance_variable_get(:@instance).instance_variable_set(:@installed, false) - OpenTelemetry::Instrumentation::Rake::Instrumentation.instance_variable_get(:@instance).instance_variable_set(:@installed, false) - + # Clean up constants and methods if they exist + if defined?(OTelBundlerPatch::Initializer::OTEL_INSTRUMENTATION_MAP) + OTelBundlerPatch::Initializer.send(:remove_const, :OTEL_INSTRUMENTATION_MAP) + end + + if defined?(OTelBundlerPatch::Initializer) + OTelBundlerPatch.send(:remove_const, :Initializer) + end + + %i[require].each do |method| + if OTelBundlerPatch.method_defined?(method) + OTelBundlerPatch.send(:undef_method, method) + end + end # Reset instrumentation installation state + [ + OpenTelemetry::Instrumentation::Net::HTTP::Instrumentation, + OpenTelemetry::Instrumentation::Rake::Instrumentation + ].each do |instrumentation| + instance = instrumentation.instance_variable_get(:@instance) + instance&.instance_variable_set(:@installed, false) + end + + # Clean up environment variables ENV['OTEL_RUBY_ENABLED_INSTRUMENTATIONS'] = nil + ENV['OTEL_RUBY_INSTRUMENTATION_NET_HTTP_ENABLED'] = nil + ENV['OTEL_RUBY_RESOURCE_DETECTORS'] = nil end it 'simple_load_test' do @@ -37,8 +54,10 @@ _(resource_attributes.key?('container.id')).must_equal false registry = OpenTelemetry.tracer_provider.instance_variable_get(:@registry) + instrumentation_names = registry.map { |entry| entry.first.name }.sort - _(registry.size).must_equal 2 + _(instrumentation_names).must_include 'OpenTelemetry::Instrumentation::Net::HTTP' + _(instrumentation_names).must_include 'OpenTelemetry::Instrumentation::Rake' end it 'simple_load_with_net_http_disabled' do @@ -48,9 +67,10 @@ Bundler.require registry = OpenTelemetry.tracer_provider.instance_variable_get(:@registry) + instrumentation_names = registry.map { |entry| entry.first.name } - _(registry.size).must_equal 1 - _(registry.first.first.name).must_equal 'OpenTelemetry::Instrumentation::Rake' + _(instrumentation_names).must_include 'OpenTelemetry::Instrumentation::Rake' + _(instrumentation_names).wont_include 'OpenTelemetry::Instrumentation::Net::HTTP' ENV['OTEL_RUBY_INSTRUMENTATION_NET_HTTP_ENABLED'] = nil end @@ -62,9 +82,10 @@ Bundler.require registry = OpenTelemetry.tracer_provider.instance_variable_get(:@registry) + instrumentation_names = registry.map { |entry| entry.first.name } - _(registry.size).must_equal 1 - _(registry.first.first.name).must_equal 'OpenTelemetry::Instrumentation::Net::HTTP' + _(instrumentation_names).must_include 'OpenTelemetry::Instrumentation::Net::HTTP' + _(instrumentation_names).wont_include 'OpenTelemetry::Instrumentation::Rake' end it 'simple_load_with_additional_resource' do diff --git a/opentelemetry-auto-instrumentation/test/test_helper.rb b/opentelemetry-auto-instrumentation/test/test_helper.rb index 9798aead57..0442e10a17 100644 --- a/opentelemetry-auto-instrumentation/test/test_helper.rb +++ b/opentelemetry-auto-instrumentation/test/test_helper.rb @@ -7,8 +7,8 @@ require 'rake' require 'minitest' require 'minitest/autorun' -require 'opentelemetry-test-helpers' -require 'opentelemetry/resource/detector' -require 'net/http' require 'opentelemetry-sdk' require 'opentelemetry-instrumentation-all' +require 'opentelemetry-test-helpers' +require 'opentelemetry/resource/detector' +require 'net/http' \ No newline at end of file From f2781dfe0db8faf19c4cc5213fdbce60a48d5079 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 29 Jul 2025 14:49:04 -0400 Subject: [PATCH 32/44] lint --- opentelemetry-auto-instrumentation/Gemfile | 4 ++-- .../lib/opentelemetry-auto-instrumentation.rb | 4 ++-- .../opentelemetry-auto-instrumentation.gemspec | 2 +- .../opentelemetry-auto-instrumentation_test.rb | 14 ++++---------- .../test/test_helper.rb | 2 +- 5 files changed, 10 insertions(+), 16 deletions(-) diff --git a/opentelemetry-auto-instrumentation/Gemfile b/opentelemetry-auto-instrumentation/Gemfile index 2e60a70be6..228d700664 100644 --- a/opentelemetry-auto-instrumentation/Gemfile +++ b/opentelemetry-auto-instrumentation/Gemfile @@ -9,7 +9,7 @@ source 'https://rubygems.org' gemspec group :test do - gem 'bundler' + gem 'bundler' gem 'minitest' gem 'rake' gem 'rubocop' @@ -22,4 +22,4 @@ group :test do gem 'bigdecimal' gem 'mutex_m' end -end \ No newline at end of file +end diff --git a/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb index 61116b7cc5..03971b93b6 100644 --- a/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb +++ b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb @@ -68,7 +68,7 @@ def detect_resource_from_env when 'azure' additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::Azure.detect) if defined? ::OpenTelemetry::Resource::Detector::Azure when 'aws' - additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::AWS.detect([:ec2, :ecs, :eks, :lambda])) if defined? ::OpenTelemetry::Resource::Detector::AWS + additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::AWS.detect(%i[ec2 ecs eks lambda])) if defined? ::OpenTelemetry::Resource::Detector::AWS end end @@ -105,7 +105,7 @@ def initialize_opentelemetry end OpenTelemetry.logger.info { 'Auto-instrumentation initialized' } rescue StandardError => e - $stderr.puts "Auto-instrumentation failed to initialize. Error: #{e.message}" + warn "Auto-instrumentation failed to initialize. Error: #{e.message}" end end end diff --git a/opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec b/opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec index ae66211d3f..47ad6d51f6 100644 --- a/opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec +++ b/opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec @@ -31,10 +31,10 @@ Gem::Specification.new do |spec| spec.add_dependency 'opentelemetry-helpers-mysql', '~> 0.2.0' spec.add_dependency 'opentelemetry-helpers-sql-obfuscation', '~> 0.3.0' spec.add_dependency 'opentelemetry-instrumentation-all', '~> 0.72.0' + spec.add_dependency 'opentelemetry-resource-detector-aws', '~> 0.2.0' spec.add_dependency 'opentelemetry-resource-detector-azure', '~> 0.2.0' spec.add_dependency 'opentelemetry-resource-detector-container', '~> 0.2.0' spec.add_dependency 'opentelemetry-resource-detector-google_cloud_platform', '~> 0.2.0' - spec.add_dependency 'opentelemetry-resource-detector-aws', '~> 0.2.0' spec.add_dependency 'opentelemetry-sdk', '~> 1.6.0' if spec.respond_to?(:metadata) diff --git a/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb b/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb index 3c866e2644..d2fc57ab17 100644 --- a/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb +++ b/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb @@ -13,19 +13,13 @@ after do # Clean up constants and methods if they exist - if defined?(OTelBundlerPatch::Initializer::OTEL_INSTRUMENTATION_MAP) - OTelBundlerPatch::Initializer.send(:remove_const, :OTEL_INSTRUMENTATION_MAP) - end + OTelBundlerPatch::Initializer.send(:remove_const, :OTEL_INSTRUMENTATION_MAP) if defined?(OTelBundlerPatch::Initializer::OTEL_INSTRUMENTATION_MAP) - if defined?(OTelBundlerPatch::Initializer) - OTelBundlerPatch.send(:remove_const, :Initializer) - end + OTelBundlerPatch.send(:remove_const, :Initializer) if defined?(OTelBundlerPatch::Initializer) %i[require].each do |method| - if OTelBundlerPatch.method_defined?(method) - OTelBundlerPatch.send(:undef_method, method) - end - end # Reset instrumentation installation state + OTelBundlerPatch.send(:undef_method, method) if OTelBundlerPatch.method_defined?(method) + end [ OpenTelemetry::Instrumentation::Net::HTTP::Instrumentation, OpenTelemetry::Instrumentation::Rake::Instrumentation diff --git a/opentelemetry-auto-instrumentation/test/test_helper.rb b/opentelemetry-auto-instrumentation/test/test_helper.rb index 0442e10a17..0296024b2b 100644 --- a/opentelemetry-auto-instrumentation/test/test_helper.rb +++ b/opentelemetry-auto-instrumentation/test/test_helper.rb @@ -11,4 +11,4 @@ require 'opentelemetry-instrumentation-all' require 'opentelemetry-test-helpers' require 'opentelemetry/resource/detector' -require 'net/http' \ No newline at end of file +require 'net/http' From c478025918ec2f0d1c4e4121c4b01a04690b100f Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 29 Jul 2025 14:57:44 -0400 Subject: [PATCH 33/44] reverse ci to original --- .github/workflows/ci-contrib.yml | 83 +++++++++++++------ .../example/app.rb | 3 - 2 files changed, 56 insertions(+), 30 deletions(-) diff --git a/.github/workflows/ci-contrib.yml b/.github/workflows/ci-contrib.yml index 2755535b21..25bad16739 100644 --- a/.github/workflows/ci-contrib.yml +++ b/.github/workflows/ci-contrib.yml @@ -242,38 +242,67 @@ jobs: ruby: "jruby-9.4.12.0" auto-instrumentation: - strategy: - fail-fast: false - matrix: - gem: - - opentelemetry-auto-instrumentation - os: - - ubuntu-latest - name: "${{ matrix.gem }} / ${{ matrix.os }}" - runs-on: ${{ matrix.os }} + name: "auto-instrumentation / ubuntu-latest" + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: "Test Ruby 3.4" - uses: ./.github/actions/test_gem + uses: ruby/setup-ruby@v1.247.0 with: - gem: "${{ matrix.gem }}" - ruby: "3.4" + ruby-version: "3.4" + - name: Test Gem + shell: bash + run: | + bundle install --quiet --jobs=3 --retry=4 + bundle exec rake test + rm -f Gemfile.lock + working-directory: './opentelemetry-auto-instrumentation' - name: "Test Ruby 3.3" - uses: ./.github/actions/test_gem + uses: ruby/setup-ruby@v1.247.0 with: - gem: "${{ matrix.gem }}" - ruby: "3.3" + ruby-version: "3.3" + - name: Test Gem + shell: bash + run: | + bundle install --quiet --jobs=3 --retry=4 + bundle exec rake test + rm -f Gemfile.lock + working-directory: './opentelemetry-auto-instrumentation' - name: "Test Ruby 3.2" - uses: ./.github/actions/test_gem + uses: ruby/setup-ruby@v1.247.0 with: - gem: "${{ matrix.gem }}" - ruby: "3.2" - yard: true - rubocop: true - build: true - - name: "Test JRuby" - if: "${{ matrix.os == 'ubuntu-latest' }}" - uses: ./.github/actions/test_gem - with: - gem: "${{ matrix.gem }}" - ruby: "jruby-9.4.12.0" + ruby-version: "3.2" + - name: Test Gem + shell: bash + run: | + bundle install --quiet --jobs=3 --retry=4 + bundle exec rake test + rm -f Gemfile.lock + working-directory: './opentelemetry-auto-instrumentation' + + - name: YARD + shell: bash + run: | + # 📄 Yard Docs 📄 + bundle exec rake yard + working-directory: './opentelemetry-auto-instrumentation' + + - name: Rubocop + shell: bash + run: | + # 🤖 Rubocop 🤖 + bundle exec rake rubocop + working-directory: './opentelemetry-auto-instrumentation' + + - name: Coverage + shell: bash + run: | + bundle exec ruby -e 'require "simplecov"; SimpleCov.minimum_coverage(85)' + working-directory: './opentelemetry-auto-instrumentation' + + - name: Build Gem + shell: bash + run: | + # 📦 Build Gem 📦 + gem build opentelemetry-auto-instrumentation.gemspec + working-directory: './opentelemetry-auto-instrumentation' diff --git a/opentelemetry-auto-instrumentation/example/app.rb b/opentelemetry-auto-instrumentation/example/app.rb index f895369eda..2d1a4621f0 100644 --- a/opentelemetry-auto-instrumentation/example/app.rb +++ b/opentelemetry-auto-instrumentation/example/app.rb @@ -4,9 +4,6 @@ # # SPDX-License-Identifier: Apache-2.0 -require 'uri' -require 'net/http' - url = URI.parse("http://catfact.ninja/fact") req = Net::HTTP::Get.new(url.to_s) res = Net::HTTP.start(url.host, url.port) {|http| From a46253306cdf17b4dc1da477311b8b405985346b Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 29 Jul 2025 15:24:37 -0400 Subject: [PATCH 34/44] moved to a nested module --- .../lib/opentelemetry-auto-instrumentation.rb | 183 ++++++++---------- ...opentelemetry-auto-instrumentation_test.rb | 11 ++ 2 files changed, 97 insertions(+), 97 deletions(-) diff --git a/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb index 03971b93b6..374c38200e 100644 --- a/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb +++ b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb @@ -6,117 +6,106 @@ # OTelBundlerPatch module OTelBundlerPatch - # Nested module to handle OpenTelemetry initialization - module Initializer - # this is used for case when user particularly want to enable single instrumentation - unless defined?(OTEL_INSTRUMENTATION_MAP) - OTEL_INSTRUMENTATION_MAP = { - 'gruf' => 'OpenTelemetry::Instrumentation::Gruf', - 'trilogy' => 'OpenTelemetry::Instrumentation::Trilogy', - 'active_support' => 'OpenTelemetry::Instrumentation::ActiveSupport', - 'action_pack' => 'OpenTelemetry::Instrumentation::ActionPack', - 'active_job' => 'OpenTelemetry::Instrumentation::ActiveJob', - 'active_record' => 'OpenTelemetry::Instrumentation::ActiveRecord', - 'action_view' => 'OpenTelemetry::Instrumentation::ActionView', - 'action_mailer' => 'OpenTelemetry::Instrumentation::ActionMailer', - 'aws_sdk' => 'OpenTelemetry::Instrumentation::AwsSdk', - 'aws_lambda' => 'OpenTelemetry::Instrumentation::AwsLambda', - 'bunny' => 'OpenTelemetry::Instrumentation::Bunny', - 'lmdb' => 'OpenTelemetry::Instrumentation::LMDB', - 'http' => 'OpenTelemetry::Instrumentation::HTTP', - 'koala' => 'OpenTelemetry::Instrumentation::Koala', - 'active_model_serializers' => 'OpenTelemetry::Instrumentation::ActiveModelSerializers', - 'concurrent_ruby' => 'OpenTelemetry::Instrumentation::ConcurrentRuby', - 'dalli' => 'OpenTelemetry::Instrumentation::Dalli', - 'delayed_job' => 'OpenTelemetry::Instrumentation::DelayedJob', - 'ethon' => 'OpenTelemetry::Instrumentation::Ethon', - 'excon' => 'OpenTelemetry::Instrumentation::Excon', - 'faraday' => 'OpenTelemetry::Instrumentation::Faraday', - 'grape' => 'OpenTelemetry::Instrumentation::Grape', - 'graphql' => 'OpenTelemetry::Instrumentation::GraphQL', - 'http_client' => 'OpenTelemetry::Instrumentation::HttpClient', - 'mongo' => 'OpenTelemetry::Instrumentation::Mongo', - 'mysql2' => 'OpenTelemetry::Instrumentation::Mysql2', - 'net_http' => 'OpenTelemetry::Instrumentation::Net::HTTP', - 'pg' => 'OpenTelemetry::Instrumentation::PG', - 'que' => 'OpenTelemetry::Instrumentation::Que', - 'racecar' => 'OpenTelemetry::Instrumentation::Racecar', - 'rack' => 'OpenTelemetry::Instrumentation::Rack', - 'rails' => 'OpenTelemetry::Instrumentation::Rails', - 'rake' => 'OpenTelemetry::Instrumentation::Rake', - 'rdkafka' => 'OpenTelemetry::Instrumentation::Rdkafka', - 'redis' => 'OpenTelemetry::Instrumentation::Redis', - 'restclient' => 'OpenTelemetry::Instrumentation::RestClient', - 'resque' => 'OpenTelemetry::Instrumentation::Resque', - 'ruby_kafka' => 'OpenTelemetry::Instrumentation::RubyKafka', - 'sidekiq' => 'OpenTelemetry::Instrumentation::Sidekiq', - 'sinatra' => 'OpenTelemetry::Instrumentation::Sinatra' - }.freeze - end - - class << self - def detect_resource_from_env - env = ENV['OTEL_RUBY_RESOURCE_DETECTORS'].to_s - additional_resource = ::OpenTelemetry::SDK::Resources::Resource.create({}) - - env.split(',').each do |detector| - case detector - when 'container' - additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::Container.detect) if defined? ::OpenTelemetry::Resource::Detector::Container - when 'google_cloud_platform' - additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::GoogleCloudPlatform.detect) if defined? ::OpenTelemetry::Resource::Detector::GoogleCloudPlatform - when 'azure' - additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::Azure.detect) if defined? ::OpenTelemetry::Resource::Detector::Azure - when 'aws' - additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::AWS.detect(%i[ec2 ecs eks lambda])) if defined? ::OpenTelemetry::Resource::Detector::AWS - end + # Nested module to handle OpenTelemetry initialization logic + module OTelInitializer + OTEL_INSTRUMENTATION_MAP = { + 'gruf' => 'OpenTelemetry::Instrumentation::Gruf', + 'trilogy' => 'OpenTelemetry::Instrumentation::Trilogy', + 'active_support' => 'OpenTelemetry::Instrumentation::ActiveSupport', + 'action_pack' => 'OpenTelemetry::Instrumentation::ActionPack', + 'active_job' => 'OpenTelemetry::Instrumentation::ActiveJob', + 'active_record' => 'OpenTelemetry::Instrumentation::ActiveRecord', + 'action_view' => 'OpenTelemetry::Instrumentation::ActionView', + 'action_mailer' => 'OpenTelemetry::Instrumentation::ActionMailer', + 'aws_sdk' => 'OpenTelemetry::Instrumentation::AwsSdk', + 'aws_lambda' => 'OpenTelemetry::Instrumentation::AwsLambda', + 'bunny' => 'OpenTelemetry::Instrumentation::Bunny', + 'lmdb' => 'OpenTelemetry::Instrumentation::LMDB', + 'http' => 'OpenTelemetry::Instrumentation::HTTP', + 'koala' => 'OpenTelemetry::Instrumentation::Koala', + 'active_model_serializers' => 'OpenTelemetry::Instrumentation::ActiveModelSerializers', + 'concurrent_ruby' => 'OpenTelemetry::Instrumentation::ConcurrentRuby', + 'dalli' => 'OpenTelemetry::Instrumentation::Dalli', + 'delayed_job' => 'OpenTelemetry::Instrumentation::DelayedJob', + 'ethon' => 'OpenTelemetry::Instrumentation::Ethon', + 'excon' => 'OpenTelemetry::Instrumentation::Excon', + 'faraday' => 'OpenTelemetry::Instrumentation::Faraday', + 'grape' => 'OpenTelemetry::Instrumentation::Grape', + 'graphql' => 'OpenTelemetry::Instrumentation::GraphQL', + 'http_client' => 'OpenTelemetry::Instrumentation::HttpClient', + 'mongo' => 'OpenTelemetry::Instrumentation::Mongo', + 'mysql2' => 'OpenTelemetry::Instrumentation::Mysql2', + 'net_http' => 'OpenTelemetry::Instrumentation::Net::HTTP', + 'pg' => 'OpenTelemetry::Instrumentation::PG', + 'que' => 'OpenTelemetry::Instrumentation::Que', + 'racecar' => 'OpenTelemetry::Instrumentation::Racecar', + 'rack' => 'OpenTelemetry::Instrumentation::Rack', + 'rails' => 'OpenTelemetry::Instrumentation::Rails', + 'rake' => 'OpenTelemetry::Instrumentation::Rake', + 'rdkafka' => 'OpenTelemetry::Instrumentation::Rdkafka', + 'redis' => 'OpenTelemetry::Instrumentation::Redis', + 'restclient' => 'OpenTelemetry::Instrumentation::RestClient', + 'resque' => 'OpenTelemetry::Instrumentation::Resque', + 'ruby_kafka' => 'OpenTelemetry::Instrumentation::RubyKafka', + 'sidekiq' => 'OpenTelemetry::Instrumentation::Sidekiq', + 'sinatra' => 'OpenTelemetry::Instrumentation::Sinatra' + }.freeze + + def self.detect_resource_from_env + env = ENV['OTEL_RUBY_RESOURCE_DETECTORS'].to_s + additional_resource = ::OpenTelemetry::SDK::Resources::Resource.create({}) + + env.split(',').each do |detector| + case detector + when 'container' + additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::Container.detect) if defined? ::OpenTelemetry::Resource::Detector::Container + when 'google_cloud_platform' + additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::GoogleCloudPlatform.detect) if defined? ::OpenTelemetry::Resource::Detector::GoogleCloudPlatform + when 'azure' + additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::Azure.detect) if defined? ::OpenTelemetry::Resource::Detector::Azure + when 'aws' + additional_resource = additional_resource.merge(::OpenTelemetry::Resource::Detector::AWS.detect(%i[ec2 ecs eks lambda])) if defined? ::OpenTelemetry::Resource::Detector::AWS end - - additional_resource end - def determine_enabled_instrumentation - env = ENV['OTEL_RUBY_ENABLED_INSTRUMENTATIONS'].to_s - - env.split(',').map { |instrumentation| OTEL_INSTRUMENTATION_MAP[instrumentation] } - end - - def setup_load_path - lib = File.expand_path('..', __dir__) - $LOAD_PATH.reject! { |path| path.include?('opentelemetry-auto-instrumentation') } - $LOAD_PATH.unshift(lib) - end + additional_resource + end - def initialize_opentelemetry - setup_load_path + def self.determine_enabled_instrumentation + env = ENV['OTEL_RUBY_ENABLED_INSTRUMENTATIONS'].to_s - begin - required_instrumentation = determine_enabled_instrumentation + env.split(',').map { |instrumentation| OTEL_INSTRUMENTATION_MAP[instrumentation] } + end - OpenTelemetry::SDK.configure do |c| - c.resource = detect_resource_from_env - if required_instrumentation.empty? - c.use_all # enables all instrumentation! - else - required_instrumentation.each do |instrumentation| - c.use instrumentation - end + def self.require_otel + lib = File.expand_path('..', __dir__) + $LOAD_PATH.reject! { |path| path.include?('opentelemetry-auto-instrumentation') } + $LOAD_PATH.unshift(lib) + + begin + required_instrumentation = determine_enabled_instrumentation + + OpenTelemetry::SDK.configure do |c| + c.resource = detect_resource_from_env + if required_instrumentation.empty? + c.use_all # enables all instrumentation! + else + required_instrumentation.each do |instrumentation| + c.use instrumentation end end - OpenTelemetry.logger.info { 'Auto-instrumentation initialized' } - rescue StandardError => e - warn "Auto-instrumentation failed to initialize. Error: #{e.message}" end + OpenTelemetry.logger.info { 'Auto-instrumentation initialized' } + rescue StandardError => e + warn "Auto-instrumentation failed to initialize. Error: #{e.message}" end end end # ref: https://github.com/newrelic/newrelic-ruby-agent/blob/dev/lib/boot/strap.rb - unless method_defined?(:require) - def require(...) - super - Initializer.initialize_opentelemetry - end + def require(...) + super + OTelInitializer.require_otel end end diff --git a/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb b/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb index d2fc57ab17..dc6b382713 100644 --- a/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb +++ b/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb @@ -15,11 +15,22 @@ # Clean up constants and methods if they exist OTelBundlerPatch::Initializer.send(:remove_const, :OTEL_INSTRUMENTATION_MAP) if defined?(OTelBundlerPatch::Initializer::OTEL_INSTRUMENTATION_MAP) + # Remove singleton methods from Initializer + if defined?(OTelBundlerPatch::Initializer) + %i[detect_resource_from_env determine_enabled_instrumentation require_otel].each do |method| + OTelBundlerPatch::Initializer.singleton_class.send(:undef_method, method) if OTelBundlerPatch::Initializer.respond_to?(method) + end + end + + # Remove the Initializer module OTelBundlerPatch.send(:remove_const, :Initializer) if defined?(OTelBundlerPatch::Initializer) + # Remove instance methods from OTelBundlerPatch %i[require].each do |method| OTelBundlerPatch.send(:undef_method, method) if OTelBundlerPatch.method_defined?(method) end + + # Reset instrumentation installation state [ OpenTelemetry::Instrumentation::Net::HTTP::Instrumentation, OpenTelemetry::Instrumentation::Rake::Instrumentation From f811cbe4d3b1cedf717e46a0b7b836d65d1d3db2 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Mon, 11 Aug 2025 17:37:01 -0400 Subject: [PATCH 35/44] doc: add more test example --- opentelemetry-auto-instrumentation/README.md | 1 + .../example/README.md | 39 +++++++++++++++ .../example/rails-example/Gemfile | 11 +++++ .../example/rails-example/app.rb | 47 +++++++++++++++++++ .../example/rails-example/config.ru | 5 ++ .../example/{ => simple-example}/Gemfile | 3 +- .../example/{ => simple-example}/app.rb | 6 +-- .../lib/opentelemetry-auto-instrumentation.rb | 2 +- 8 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 opentelemetry-auto-instrumentation/example/README.md create mode 100644 opentelemetry-auto-instrumentation/example/rails-example/Gemfile create mode 100644 opentelemetry-auto-instrumentation/example/rails-example/app.rb create mode 100644 opentelemetry-auto-instrumentation/example/rails-example/config.ru rename opentelemetry-auto-instrumentation/example/{ => simple-example}/Gemfile (50%) rename opentelemetry-auto-instrumentation/example/{ => simple-example}/app.rb (62%) diff --git a/opentelemetry-auto-instrumentation/README.md b/opentelemetry-auto-instrumentation/README.md index 52cc13b6e2..9807097524 100644 --- a/opentelemetry-auto-instrumentation/README.md +++ b/opentelemetry-auto-instrumentation/README.md @@ -33,6 +33,7 @@ opentelemetry-helpers-sql-obfuscation opentelemetry-resource-detector-google_cloud_platform opentelemetry-resource-detector-azure opentelemetry-resource-detector-container +opentelemetry-resource-detector-aws ``` ### Example installation strategies diff --git a/opentelemetry-auto-instrumentation/example/README.md b/opentelemetry-auto-instrumentation/example/README.md new file mode 100644 index 0000000000..480a7c00e9 --- /dev/null +++ b/opentelemetry-auto-instrumentation/example/README.md @@ -0,0 +1,39 @@ +# Example + +## Installation + +Install opentelemetry-auto-instrumentation through `gem install` +Then `bundle install` + + +## Simple Example (simple-example) + +```bash +OTEL_RUBY_REQUIRE_BUNDLER=true OTEL_TRACES_EXPORTER=console RUBYOPT="-r opentelemetry-auto-instrumentation" OTEL_RUBY_OPERATOR=false ruby app.rb +``` + +## Rails Example (rails-example) + +Without auto-instrumentation +```bash +bundle exec rackup config.ru +``` + +In other terminal make the request call +```bash +wget http://localhost:9292 +# or curl http://localhost:9292 if you have curl on system +``` + +With auto-instrumentation +```bash +OTEL_RUBY_REQUIRE_BUNDLER=false OTEL_TRACES_EXPORTER=console RUBYOPT="-r opentelemetry-auto-instrumentation" OTEL_RUBY_OPERATOR=false bundle exec rackup config.ru +``` + +The load sequence must be opentelemetry-auto-instrumentation -> user library -> bundler.require (initialize otel sdk and instrumentation installation) + +In other terminal make the request call +```bash +wget http://localhost:9292 +# or curl http://localhost:9292 if you have curl on system +``` diff --git a/opentelemetry-auto-instrumentation/example/rails-example/Gemfile b/opentelemetry-auto-instrumentation/example/rails-example/Gemfile new file mode 100644 index 0000000000..5318a25bf7 --- /dev/null +++ b/opentelemetry-auto-instrumentation/example/rails-example/Gemfile @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +# Gemfile +source 'https://rubygems.org' + +gem 'rails' +gem 'rack' +gem 'rake', '13.0.6' +gem 'bigdecimal', '3.1.3' +gem 'logger', '1.5.3' +gem 'webrick' diff --git a/opentelemetry-auto-instrumentation/example/rails-example/app.rb b/opentelemetry-auto-instrumentation/example/rails-example/app.rb new file mode 100644 index 0000000000..9ffc35f864 --- /dev/null +++ b/opentelemetry-auto-instrumentation/example/rails-example/app.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'rails' +require 'action_controller/railtie' + +require 'bundler' +Bundler.require + +# MyApp +class MyApp < Rails::Application + config.secret_key_base = 'your_secret_key_here' + config.eager_load = false + config.logger = Logger.new($stdout) + config.api_only = true + config.active_support.to_time_preserves_timezone = :zone + + routes.draw do + get '/', to: 'application#index' + get '/hello', to: 'application#hello' + post '/data', to: 'application#create' + end +end + +# ApplicationController +class ApplicationController < ActionController::API + def index + render json: { message: 'Hello World!', time: Time.current } + end + + def hello + name = params[:name] || 'World' + render json: { greeting: "Hello #{name}!" } + end + + def create + render json: { + message: 'Data received', + data: params.except(:controller, :action) + } + end +end + +MyApp.initialize! diff --git a/opentelemetry-auto-instrumentation/example/rails-example/config.ru b/opentelemetry-auto-instrumentation/example/rails-example/config.ru new file mode 100644 index 0000000000..3ca0d86570 --- /dev/null +++ b/opentelemetry-auto-instrumentation/example/rails-example/config.ru @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +require_relative 'app' + +run MyApp diff --git a/opentelemetry-auto-instrumentation/example/Gemfile b/opentelemetry-auto-instrumentation/example/simple-example/Gemfile similarity index 50% rename from opentelemetry-auto-instrumentation/example/Gemfile rename to opentelemetry-auto-instrumentation/example/simple-example/Gemfile index c9721cb670..ebc45888f5 100644 --- a/opentelemetry-auto-instrumentation/example/Gemfile +++ b/opentelemetry-auto-instrumentation/example/simple-example/Gemfile @@ -1,2 +1,3 @@ -source 'https://rubygems.org' +# frozen_string_literal: true +source 'https://rubygems.org' diff --git a/opentelemetry-auto-instrumentation/example/app.rb b/opentelemetry-auto-instrumentation/example/simple-example/app.rb similarity index 62% rename from opentelemetry-auto-instrumentation/example/app.rb rename to opentelemetry-auto-instrumentation/example/simple-example/app.rb index 2d1a4621f0..4d6ce333ea 100644 --- a/opentelemetry-auto-instrumentation/example/app.rb +++ b/opentelemetry-auto-instrumentation/example/simple-example/app.rb @@ -4,8 +4,8 @@ # # SPDX-License-Identifier: Apache-2.0 -url = URI.parse("http://catfact.ninja/fact") +url = URI.parse('http://catfact.ninja/fact') req = Net::HTTP::Get.new(url.to_s) -res = Net::HTTP.start(url.host, url.port) {|http| +Net::HTTP.start(url.host, url.port) do |http| http.request(req) -} +end diff --git a/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb index 374c38200e..5f6594cf39 100644 --- a/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb +++ b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb @@ -118,7 +118,7 @@ def require(...) # set OTEL_OPERATOR to false if not in autoinstrumentation-ruby image, default to /otel-auto-instrumentation-ruby # /otel-auto-instrumentation-ruby is set in opentelemetry-operator ruby.go -operator_gem_path = ENV['OTEL_RUBY_OPERATOR'].nil? || ENV['OTEL_RUBY_OPERATOR'] == 'true' ? '/otel-auto-instrumentation-ruby' : nil +operator_gem_path = ENV['OTEL_RUBY_OPERATOR'] == 'true' ? '/otel-auto-instrumentation-ruby' : nil additional_gem_path = operator_gem_path || ENV['OTEL_RUBY_ADDITIONAL_GEM_PATH'] || Gem.dir $stdout.puts "Loading the additional gem path from #{additional_gem_path}" if ENV['OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG'] == 'true' From 5c032ca4339935857f259d6a2c9ebcbc10691a4c Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Mon, 11 Aug 2025 17:38:20 -0400 Subject: [PATCH 36/44] typo --- .../lib/opentelemetry-auto-instrumentation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb index 5f6594cf39..374c38200e 100644 --- a/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb +++ b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb @@ -118,7 +118,7 @@ def require(...) # set OTEL_OPERATOR to false if not in autoinstrumentation-ruby image, default to /otel-auto-instrumentation-ruby # /otel-auto-instrumentation-ruby is set in opentelemetry-operator ruby.go -operator_gem_path = ENV['OTEL_RUBY_OPERATOR'] == 'true' ? '/otel-auto-instrumentation-ruby' : nil +operator_gem_path = ENV['OTEL_RUBY_OPERATOR'].nil? || ENV['OTEL_RUBY_OPERATOR'] == 'true' ? '/otel-auto-instrumentation-ruby' : nil additional_gem_path = operator_gem_path || ENV['OTEL_RUBY_ADDITIONAL_GEM_PATH'] || Gem.dir $stdout.puts "Loading the additional gem path from #{additional_gem_path}" if ENV['OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG'] == 'true' From b006c5019beb582fa835516dee933a3bb6984465 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Thu, 23 Oct 2025 12:07:08 -0400 Subject: [PATCH 37/44] update otel dependencies --- ...opentelemetry-auto-instrumentation.gemspec | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec b/opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec index 47ad6d51f6..07958a168a 100644 --- a/opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec +++ b/opentelemetry-auto-instrumentation/opentelemetry-auto-instrumentation.gemspec @@ -26,16 +26,16 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] spec.required_ruby_version = '>= 3.2' - spec.add_dependency 'opentelemetry-api', '~> 1.4.0' - spec.add_dependency 'opentelemetry-exporter-otlp', '~> 0.29.1' - spec.add_dependency 'opentelemetry-helpers-mysql', '~> 0.2.0' - spec.add_dependency 'opentelemetry-helpers-sql-obfuscation', '~> 0.3.0' - spec.add_dependency 'opentelemetry-instrumentation-all', '~> 0.72.0' - spec.add_dependency 'opentelemetry-resource-detector-aws', '~> 0.2.0' - spec.add_dependency 'opentelemetry-resource-detector-azure', '~> 0.2.0' - spec.add_dependency 'opentelemetry-resource-detector-container', '~> 0.2.0' - spec.add_dependency 'opentelemetry-resource-detector-google_cloud_platform', '~> 0.2.0' - spec.add_dependency 'opentelemetry-sdk', '~> 1.6.0' + spec.add_dependency 'opentelemetry-api', '~> 1.7.0' + spec.add_dependency 'opentelemetry-exporter-otlp', '~> 0.31.1' + spec.add_dependency 'opentelemetry-helpers-mysql', '~> 0.4.0' + spec.add_dependency 'opentelemetry-helpers-sql-obfuscation', '~> 0.5.0' + spec.add_dependency 'opentelemetry-instrumentation-all', '~> 0.86.1' + spec.add_dependency 'opentelemetry-resource-detector-aws', '~> 0.5.0' + spec.add_dependency 'opentelemetry-resource-detector-azure', '~> 0.3.0' + spec.add_dependency 'opentelemetry-resource-detector-container', '~> 0.3.0' + spec.add_dependency 'opentelemetry-resource-detector-google_cloud_platform', '~> 0.3.0' + spec.add_dependency 'opentelemetry-sdk', '~> 1.10.0' if spec.respond_to?(:metadata) spec.metadata['changelog_uri'] = "https://rubydoc.info/gems/#{spec.name}/#{spec.version}/file/CHANGELOG.md" From b35cf60131f7db8e59490b39b2a57539e49b209e Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Thu, 23 Oct 2025 12:45:21 -0400 Subject: [PATCH 38/44] add updated test case --- .github/workflows/ci-contrib.yml | 30 ++++ .../lib/opentelemetry-auto-instrumentation.rb | 6 + ...opentelemetry-auto-instrumentation_test.rb | 151 +++++++++--------- 3 files changed, 113 insertions(+), 74 deletions(-) diff --git a/.github/workflows/ci-contrib.yml b/.github/workflows/ci-contrib.yml index d24873ac3d..377b4f29e3 100644 --- a/.github/workflows/ci-contrib.yml +++ b/.github/workflows/ci-contrib.yml @@ -216,3 +216,33 @@ jobs: with: gem: "opentelemetry-sampler-${{ matrix.gem }}" ruby: "jruby-10.0.2.0" + + auto-instrumentation: + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + name: "opentelemetry-auto-instrumentation / ${{ matrix.os }}" + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v5 + - name: "Test Ruby 3.4" + uses: ./.github/actions/test_gem + with: + gem: "opentelemetry-auto-instrumentation" + ruby: "3.4" + - name: "Test Ruby 3.3" + uses: ./.github/actions/test_gem + with: + gem: "opentelemetry-auto-instrumentation" + ruby: "3.3" + - name: "Test Ruby 3.2" + uses: ./.github/actions/test_gem + with: + gem: "opentelemetry-auto-instrumentation" + ruby: "3.2" + yard: true + rubocop: true + coverage: true + build: true diff --git a/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb index 374c38200e..b34460a749 100644 --- a/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb +++ b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb @@ -8,6 +8,8 @@ module OTelBundlerPatch # Nested module to handle OpenTelemetry initialization logic module OTelInitializer + @initialized = false + OTEL_INSTRUMENTATION_MAP = { 'gruf' => 'OpenTelemetry::Instrumentation::Gruf', 'trilogy' => 'OpenTelemetry::Instrumentation::Trilogy', @@ -78,6 +80,10 @@ def self.determine_enabled_instrumentation end def self.require_otel + return if @initialized + + @initialized = true + lib = File.expand_path('..', __dir__) $LOAD_PATH.reject! { |path| path.include?('opentelemetry-auto-instrumentation') } $LOAD_PATH.unshift(lib) diff --git a/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb b/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb index dc6b382713..f67406bd28 100644 --- a/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb +++ b/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb @@ -7,103 +7,106 @@ require 'test_helper' describe 'AutoInstrumentation' do + let(:auto_instrumentation_path) { File.expand_path('../lib/opentelemetry-auto-instrumentation.rb', __dir__) } + before do - OpenTelemetry::TestHelpers.reset_opentelemetry + ENV['OTEL_RUBY_ENABLED_INSTRUMENTATIONS'] = nil + ENV['OTEL_RUBY_INSTRUMENTATION_NET_HTTP_ENABLED'] = nil + ENV['OTEL_RUBY_RESOURCE_DETECTORS'] = nil + ENV['OTEL_RUBY_REQUIRE_BUNDLER'] = nil + ENV['OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG'] = nil end after do - # Clean up constants and methods if they exist - OTelBundlerPatch::Initializer.send(:remove_const, :OTEL_INSTRUMENTATION_MAP) if defined?(OTelBundlerPatch::Initializer::OTEL_INSTRUMENTATION_MAP) - - # Remove singleton methods from Initializer - if defined?(OTelBundlerPatch::Initializer) - %i[detect_resource_from_env determine_enabled_instrumentation require_otel].each do |method| - OTelBundlerPatch::Initializer.singleton_class.send(:undef_method, method) if OTelBundlerPatch::Initializer.respond_to?(method) - end - end - - # Remove the Initializer module - OTelBundlerPatch.send(:remove_const, :Initializer) if defined?(OTelBundlerPatch::Initializer) - - # Remove instance methods from OTelBundlerPatch - %i[require].each do |method| - OTelBundlerPatch.send(:undef_method, method) if OTelBundlerPatch.method_defined?(method) - end - - # Reset instrumentation installation state - [ - OpenTelemetry::Instrumentation::Net::HTTP::Instrumentation, - OpenTelemetry::Instrumentation::Rake::Instrumentation - ].each do |instrumentation| - instance = instrumentation.instance_variable_get(:@instance) - instance&.instance_variable_set(:@installed, false) - end - - # Clean up environment variables ENV['OTEL_RUBY_ENABLED_INSTRUMENTATIONS'] = nil ENV['OTEL_RUBY_INSTRUMENTATION_NET_HTTP_ENABLED'] = nil ENV['OTEL_RUBY_RESOURCE_DETECTORS'] = nil + ENV['OTEL_RUBY_REQUIRE_BUNDLER'] = nil + ENV['OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG'] = nil end - it 'simple_load_test' do - load './lib/opentelemetry-auto-instrumentation.rb' - Bundler.require - - _(OpenTelemetry.tracer_provider.class).must_equal OpenTelemetry::SDK::Trace::TracerProvider - - resource_attributes = OpenTelemetry.tracer_provider.instance_variable_get(:@resource).instance_variable_get(:@attributes) + def run_in_subprocess(env_vars = {}) + # Run the test in a subprocess to avoid contaminating the test environment + read_pipe, write_pipe = IO.pipe + + pid = fork do + read_pipe.close + env_vars.each { |key, value| ENV[key] = value } + + ENV['OTEL_RUBY_REQUIRE_BUNDLER'] = 'false' + begin + # Load the auto-instrumentation library + load auto_instrumentation_path + Bundler.require + + # Get tracer provider information + tracer_provider = OpenTelemetry.tracer_provider + resource = tracer_provider.instance_variable_get(:@resource) + resource_attributes = resource.instance_variable_get(:@attributes) + registry = tracer_provider.instance_variable_get(:@registry) + instrumentation_names = registry.map { |entry| entry.first.name } + + # Serialize and send results back to parent + result = Marshal.dump({ + tracer_provider_class: tracer_provider.class.name, + resource_attributes: resource_attributes, + instrumentation_names: instrumentation_names + }) + write_pipe.write(result) + rescue StandardError => e + error_result = Marshal.dump({ error: e.message, backtrace: e.backtrace }) + write_pipe.write(error_result) + ensure + write_pipe.close + exit!(0) + end + end - _(resource_attributes['service.name']).must_equal 'unknown_service' - _(resource_attributes['telemetry.sdk.name']).must_equal 'opentelemetry' - _(resource_attributes['telemetry.sdk.language']).must_equal 'ruby' - _(resource_attributes.key?('container.id')).must_equal false + write_pipe.close + result_data = read_pipe.read + read_pipe.close + Process.wait(pid) - registry = OpenTelemetry.tracer_provider.instance_variable_get(:@registry) - instrumentation_names = registry.map { |entry| entry.first.name }.sort + # rubocop:disable Security/MarshalLoad + Marshal.load(result_data) + # rubocop:enable Security/MarshalLoad + end - _(instrumentation_names).must_include 'OpenTelemetry::Instrumentation::Net::HTTP' - _(instrumentation_names).must_include 'OpenTelemetry::Instrumentation::Rake' + it 'simple_load_test' do + result = run_in_subprocess + + _(result[:error]).must_be_nil + _(result[:tracer_provider_class]).must_equal 'OpenTelemetry::SDK::Trace::TracerProvider' + _(result[:resource_attributes]['service.name']).must_equal 'unknown_service' + _(result[:resource_attributes]['telemetry.sdk.name']).must_equal 'opentelemetry' + _(result[:resource_attributes]['telemetry.sdk.language']).must_equal 'ruby' + _(result[:resource_attributes].key?('container.id')).must_equal false + _(result[:instrumentation_names]).must_include 'OpenTelemetry::Instrumentation::Net::HTTP' + _(result[:instrumentation_names]).must_include 'OpenTelemetry::Instrumentation::Rake' end it 'simple_load_with_net_http_disabled' do - ENV['OTEL_RUBY_INSTRUMENTATION_NET_HTTP_ENABLED'] = 'false' - - load './lib/opentelemetry-auto-instrumentation.rb' - Bundler.require - - registry = OpenTelemetry.tracer_provider.instance_variable_get(:@registry) - instrumentation_names = registry.map { |entry| entry.first.name } + result = run_in_subprocess('OTEL_RUBY_INSTRUMENTATION_NET_HTTP_ENABLED' => 'false') - _(instrumentation_names).must_include 'OpenTelemetry::Instrumentation::Rake' - _(instrumentation_names).wont_include 'OpenTelemetry::Instrumentation::Net::HTTP' - - ENV['OTEL_RUBY_INSTRUMENTATION_NET_HTTP_ENABLED'] = nil + _(result[:error]).must_be_nil + _(result[:instrumentation_names]).must_include 'OpenTelemetry::Instrumentation::Rake' + _(result[:instrumentation_names]).wont_include 'OpenTelemetry::Instrumentation::Net::HTTP' end it 'simple_load_with_desired_instrument_only' do - ENV['OTEL_RUBY_ENABLED_INSTRUMENTATIONS'] = 'net_http' - - load './lib/opentelemetry-auto-instrumentation.rb' - Bundler.require - - registry = OpenTelemetry.tracer_provider.instance_variable_get(:@registry) - instrumentation_names = registry.map { |entry| entry.first.name } + result = run_in_subprocess('OTEL_RUBY_ENABLED_INSTRUMENTATIONS' => 'net_http') - _(instrumentation_names).must_include 'OpenTelemetry::Instrumentation::Net::HTTP' - _(instrumentation_names).wont_include 'OpenTelemetry::Instrumentation::Rake' + _(result[:error]).must_be_nil + _(result[:instrumentation_names]).must_include 'OpenTelemetry::Instrumentation::Net::HTTP' + _(result[:instrumentation_names]).wont_include 'OpenTelemetry::Instrumentation::Rake' end it 'simple_load_with_additional_resource' do - ENV['OTEL_RUBY_RESOURCE_DETECTORS'] = 'container' + result = run_in_subprocess('OTEL_RUBY_RESOURCE_DETECTORS' => 'container') - load './lib/opentelemetry-auto-instrumentation.rb' - Bundler.require - - resource_attributes = OpenTelemetry.tracer_provider.instance_variable_get(:@resource).instance_variable_get(:@attributes) - _(resource_attributes.key?('container.id')).must_equal true - _(resource_attributes['telemetry.sdk.name']).must_equal 'opentelemetry' - _(resource_attributes['telemetry.sdk.language']).must_equal 'ruby' - - ENV['OTEL_RUBY_RESOURCE_DETECTORS'] = nil + _(result[:error]).must_be_nil + _(result[:resource_attributes].key?('container.id')).must_equal true + _(result[:resource_attributes]['telemetry.sdk.name']).must_equal 'opentelemetry' + _(result[:resource_attributes]['telemetry.sdk.language']).must_equal 'ruby' end end From 7bbd3729f190f9c6ae0b8f4f3b24e2d82d47e2ec Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Fri, 24 Oct 2025 12:44:27 -0400 Subject: [PATCH 39/44] remove the test case for container id because github workflow runs on non-docker env --- .../test/opentelemetry-auto-instrumentation_test.rb | 9 --------- 1 file changed, 9 deletions(-) diff --git a/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb b/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb index f67406bd28..6d93430da3 100644 --- a/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb +++ b/opentelemetry-auto-instrumentation/test/opentelemetry-auto-instrumentation_test.rb @@ -100,13 +100,4 @@ def run_in_subprocess(env_vars = {}) _(result[:instrumentation_names]).must_include 'OpenTelemetry::Instrumentation::Net::HTTP' _(result[:instrumentation_names]).wont_include 'OpenTelemetry::Instrumentation::Rake' end - - it 'simple_load_with_additional_resource' do - result = run_in_subprocess('OTEL_RUBY_RESOURCE_DETECTORS' => 'container') - - _(result[:error]).must_be_nil - _(result[:resource_attributes].key?('container.id')).must_equal true - _(result[:resource_attributes]['telemetry.sdk.name']).must_equal 'opentelemetry' - _(result[:resource_attributes]['telemetry.sdk.language']).must_equal 'ruby' - end end From b92cb61a444aa11b464093ba4707cf689203f56a Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Fri, 7 Nov 2025 14:02:39 -0500 Subject: [PATCH 40/44] Update opentelemetry-auto-instrumentation/README.md Co-authored-by: Hannah Ramadan <76922290+hannahramadan@users.noreply.github.com> --- opentelemetry-auto-instrumentation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-auto-instrumentation/README.md b/opentelemetry-auto-instrumentation/README.md index 9807097524..3ce57a5718 100644 --- a/opentelemetry-auto-instrumentation/README.md +++ b/opentelemetry-auto-instrumentation/README.md @@ -10,7 +10,7 @@ OpenTelemetry provides a single set of APIs, libraries, agents, and collector se ## How does this gem fit in? -The `opentelemetry-auto-instrumentation` gem provides an easy way to load and initialize the OpenTelemetry Ruby SDK without changing your code initialize the SDK. This gem is particularly used with the [OpenTelemetry Operator][opentelemetry-operator]. +The `opentelemetry-auto-instrumentation` gem provides an easy way to load and initialize the OpenTelemetry Ruby SDK without changing your code. This gem is particularly used with the [OpenTelemetry Operator][opentelemetry-operator]. ## How do I get started? From 69c9fd9ffb30fd8ae046ce21e953e4069ce67024 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Mon, 17 Nov 2025 13:25:36 -0500 Subject: [PATCH 41/44] add troubleshooting in readme --- opentelemetry-auto-instrumentation/README.md | 17 +++++++++++------ .../example/README.md | 5 ++++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/opentelemetry-auto-instrumentation/README.md b/opentelemetry-auto-instrumentation/README.md index 3ce57a5718..e29808744f 100644 --- a/opentelemetry-auto-instrumentation/README.md +++ b/opentelemetry-auto-instrumentation/README.md @@ -23,6 +23,7 @@ gem install opentelemetry-auto-instrumentation ``` Installing opentelemetry-auto-instrumentation will automatically install following gems: + ```console opentelemetry-sdk opentelemetry-api @@ -91,6 +92,14 @@ Since the `opentelemetry-auto-instrumentation` gem should be installed through ` RUBYOPT="-r {PUT YOUR GEM PATH}/gems/opentelemetry-auto-instrumentation-0.1.0/lib/opentelemetry-auto-instrumentation" bundle exec rails server ``` +If you wish to load some gems outside the Gemfile, then they need to be placed in front of opentelemetry-auto-instrumentation: + +```console +export BUNDLE_WITHOUT=development,test +gem install mysql2 +RUBYOPT="-r mysql2 -r opentelemetry-auto-instrumentation" ruby application.rb +``` + Instrument Sinatra application with rackup: If you are using a Gemfile to install the required gems but without `Bundler.require`, set `REQUIRE_BUNDLER` to true. This way, `opentelemetry-auto-instrumentation` will call `Bundler.require` to initialize the required gems prior to SDK initialization. @@ -100,13 +109,9 @@ export REQUIRE_BUNDLER=true RUBYOPT="-r opentelemetry-auto-instrumentation" rackup config.ru ``` -If you wish to load some gems outside the Gemfile, then they need to be placed in front of opentelemetry-auto-instrumentation: +### Troubleshooting -```console -export BUNDLE_WITHOUT=development,test -gem install mysql2 -RUBYOPT="-r mysql2 -r opentelemetry-auto-instrumentation" ruby application.rb -``` +The auto-instrumentation works by patching the `Bundler::Runtime#require` method to inject the `opentelemetry-auto-instrumentation` gem into your application. Rails applications automatically call `Bundler.require` during their boot process, so they work out of the box. However, many other frameworks (like Sinatra) do not call `Bundler.require` automatically, which means the OpenTelemetry SDK is never loaded. To fix this, explicitly call `Bundler.require` early in your application's startup process, or set the `OTEL_RUBY_REQUIRE_BUNDLER` environment variable to `true`. ## Example diff --git a/opentelemetry-auto-instrumentation/example/README.md b/opentelemetry-auto-instrumentation/example/README.md index 480a7c00e9..9c6718fbca 100644 --- a/opentelemetry-auto-instrumentation/example/README.md +++ b/opentelemetry-auto-instrumentation/example/README.md @@ -5,7 +5,6 @@ Install opentelemetry-auto-instrumentation through `gem install` Then `bundle install` - ## Simple Example (simple-example) ```bash @@ -15,17 +14,20 @@ OTEL_RUBY_REQUIRE_BUNDLER=true OTEL_TRACES_EXPORTER=console RUBYOPT="-r opentel ## Rails Example (rails-example) Without auto-instrumentation + ```bash bundle exec rackup config.ru ``` In other terminal make the request call + ```bash wget http://localhost:9292 # or curl http://localhost:9292 if you have curl on system ``` With auto-instrumentation + ```bash OTEL_RUBY_REQUIRE_BUNDLER=false OTEL_TRACES_EXPORTER=console RUBYOPT="-r opentelemetry-auto-instrumentation" OTEL_RUBY_OPERATOR=false bundle exec rackup config.ru ``` @@ -33,6 +35,7 @@ OTEL_RUBY_REQUIRE_BUNDLER=false OTEL_TRACES_EXPORTER=console RUBYOPT="-r opente The load sequence must be opentelemetry-auto-instrumentation -> user library -> bundler.require (initialize otel sdk and instrumentation installation) In other terminal make the request call + ```bash wget http://localhost:9292 # or curl http://localhost:9292 if you have curl on system From 1a27561a59d4850a6c9d090f40f27521354368c2 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Tue, 18 Nov 2025 11:04:45 -0500 Subject: [PATCH 42/44] Update opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb Co-authored-by: Ariel Valentin --- .../lib/opentelemetry-auto-instrumentation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb index b34460a749..f8bcdca08d 100644 --- a/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb +++ b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb @@ -137,7 +137,7 @@ def require(...) (file_path.include?('opentelemetry') || file_path.include?('google')) && !unload_libraries.include?(gem_name) end -$stdout.puts "Loaded Library File Paths #{loaded_library_file_path.join(',')}" if ENV['OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG'] == 'true' +$stderr.puts "Loaded Library File Paths #{loaded_library_file_path.join(',')}" if ENV['OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG'] == 'true' loaded_library_file_path.each do |file_path| $LOAD_PATH.unshift("#{file_path}/lib") From 72e21610c8ae1021d1ffae77c321d8a41ddde8cf Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 18 Nov 2025 11:08:38 -0500 Subject: [PATCH 43/44] add more troubleshooting instruction --- .../example/README.md | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/opentelemetry-auto-instrumentation/example/README.md b/opentelemetry-auto-instrumentation/example/README.md index 9c6718fbca..f9571cd82a 100644 --- a/opentelemetry-auto-instrumentation/example/README.md +++ b/opentelemetry-auto-instrumentation/example/README.md @@ -40,3 +40,33 @@ In other terminal make the request call wget http://localhost:9292 # or curl http://localhost:9292 if you have curl on system ``` + +### Troubleshooting: Default Gem Version Conflicts + +If you encounter an error like "You have already activated [gem] X.X.X, but your Gemfile requires [gem] Y.Y.Y", this indicates a version conflict with a default gem (such as `json`, `bigdecimal`, or `logger`). + +**Error example:** +``` +You have already activated json 2.6.3, but your Gemfile requires json 2.16.0. +Since json is a default gem, you can either remove your dependency on it or +try updating to a newer version of bundler that supports json as a default gem. +``` + +**Solution:** + +Install the specific gem version that your Gemfile requires: + +```bash +gem install [gem-name] -v '[version]' +``` + +For example: +```bash +gem install json -v '2.16.0' +``` + +Then run your application again with auto-instrumentation. + +**Why this happens:** + +When using `RUBYOPT="-r opentelemetry-auto-instrumentation"` with `bundle exec`, the OpenTelemetry gem is loaded before `bundle exec` runs. If the OpenTelemetry dependencies activate a default gem version that differs from what your Gemfile specifies, Bundler will raise an error. Installing the required version explicitly resolves this conflict. From fc3c33a26ce66e4f1a6397de41167cd0fbc3b5eb Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Wed, 19 Nov 2025 13:14:55 -0500 Subject: [PATCH 44/44] fix ci --- opentelemetry-auto-instrumentation/example/README.md | 4 ++-- .../lib/opentelemetry-auto-instrumentation.rb | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/opentelemetry-auto-instrumentation/example/README.md b/opentelemetry-auto-instrumentation/example/README.md index f9571cd82a..ea87807ec0 100644 --- a/opentelemetry-auto-instrumentation/example/README.md +++ b/opentelemetry-auto-instrumentation/example/README.md @@ -43,7 +43,7 @@ wget http://localhost:9292 ### Troubleshooting: Default Gem Version Conflicts -If you encounter an error like "You have already activated [gem] X.X.X, but your Gemfile requires [gem] Y.Y.Y", this indicates a version conflict with a default gem (such as `json`, `bigdecimal`, or `logger`). +If you encounter an error like "You have already activated [gem] X.X.X, but your Gemfile requires [gem] Y.Y.Y", this indicates a version conflict with a default gem (such as `json` or `logger`). **Error example:** ``` @@ -69,4 +69,4 @@ Then run your application again with auto-instrumentation. **Why this happens:** -When using `RUBYOPT="-r opentelemetry-auto-instrumentation"` with `bundle exec`, the OpenTelemetry gem is loaded before `bundle exec` runs. If the OpenTelemetry dependencies activate a default gem version that differs from what your Gemfile specifies, Bundler will raise an error. Installing the required version explicitly resolves this conflict. +The OpenTelemetry gem is loaded before `bundle exec` runs. If the OpenTelemetry dependencies activate a default gem version that differs from what your Gemfile specifies, Bundler will raise an error. Installing the required version explicitly resolves this conflict. diff --git a/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb index f8bcdca08d..1263154a43 100644 --- a/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb +++ b/opentelemetry-auto-instrumentation/lib/opentelemetry-auto-instrumentation.rb @@ -137,7 +137,9 @@ def require(...) (file_path.include?('opentelemetry') || file_path.include?('google')) && !unload_libraries.include?(gem_name) end +# rubocop:disable Style/StderrPuts $stderr.puts "Loaded Library File Paths #{loaded_library_file_path.join(',')}" if ENV['OTEL_RUBY_AUTO_INSTRUMENTATION_DEBUG'] == 'true' +# rubocop:enable Style/StderrPuts loaded_library_file_path.each do |file_path| $LOAD_PATH.unshift("#{file_path}/lib")