From ec8aa55eba52de72f97dce57ecb19e219f363e42 Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Sat, 25 Jun 2022 21:42:32 +0100 Subject: [PATCH 01/33] boilerplate for racecar instrumentation --- .toys/.data/releases.yml | 4 + instrumentation/racecar/.rubocop.yml | 5 + instrumentation/racecar/.yardopts | 9 + instrumentation/racecar/Appraisals | 15 ++ instrumentation/racecar/CHANGELOG.md | 1 + instrumentation/racecar/Gemfile | 17 ++ instrumentation/racecar/LICENSE | 201 ++++++++++++++++++ instrumentation/racecar/README.md | 52 +++++ instrumentation/racecar/Rakefile | 28 +++ .../opentelemetry-instrumentation-racecar.rb | 7 + .../lib/opentelemetry/instrumentation.rb | 19 ++ .../opentelemetry/instrumentation/racecar.rb | 19 ++ .../racecar/instrumentation.rb | 30 +++ .../instrumentation/racecar/version.rb | 13 ++ ...ntelemetry-instrumentation-racecar.gemspec | 49 +++++ instrumentation/racecar/test/.rubocop.yml | 4 + .../racecar/instrumentation_test.rb | 29 +++ instrumentation/racecar/test/test_helper.rb | 18 ++ 18 files changed, 520 insertions(+) create mode 100644 instrumentation/racecar/.rubocop.yml create mode 100644 instrumentation/racecar/.yardopts create mode 100644 instrumentation/racecar/Appraisals create mode 100644 instrumentation/racecar/CHANGELOG.md create mode 100644 instrumentation/racecar/Gemfile create mode 100644 instrumentation/racecar/LICENSE create mode 100644 instrumentation/racecar/README.md create mode 100644 instrumentation/racecar/Rakefile create mode 100644 instrumentation/racecar/lib/opentelemetry-instrumentation-racecar.rb create mode 100644 instrumentation/racecar/lib/opentelemetry/instrumentation.rb create mode 100644 instrumentation/racecar/lib/opentelemetry/instrumentation/racecar.rb create mode 100644 instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb create mode 100644 instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/version.rb create mode 100644 instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec create mode 100644 instrumentation/racecar/test/.rubocop.yml create mode 100644 instrumentation/racecar/test/opentelemetry/instrumentation/racecar/instrumentation_test.rb create mode 100644 instrumentation/racecar/test/test_helper.rb diff --git a/.toys/.data/releases.yml b/.toys/.data/releases.yml index 0ff8bcbaf..773897cb6 100644 --- a/.toys/.data/releases.yml +++ b/.toys/.data/releases.yml @@ -31,6 +31,10 @@ commit_lint: # * changelog_path: Path to CHANGLEOG.md relative to the gem directory. # (Required only if it is not in the expected location.) gems: + - name: opentelemetry-instrumentation-racecar + directory: instrumentation/racecar + version_constant: [OpenTelemetry, Instrumentation, Racecar, VERSION] + - name: opentelemetry-instrumentation-rdkafka directory: instrumentation/rdkafka version_constant: [OpenTelemetry, Instrumentation, Rdkafka, VERSION] diff --git a/instrumentation/racecar/.rubocop.yml b/instrumentation/racecar/.rubocop.yml new file mode 100644 index 000000000..2d18e24ae --- /dev/null +++ b/instrumentation/racecar/.rubocop.yml @@ -0,0 +1,5 @@ +inherit_from: ../.rubocop-examples.yml + +Naming/FileName: + Exclude: + - "lib/opentelemetry-instrumentation-racecar.rb" diff --git a/instrumentation/racecar/.yardopts b/instrumentation/racecar/.yardopts new file mode 100644 index 000000000..dd4d77560 --- /dev/null +++ b/instrumentation/racecar/.yardopts @@ -0,0 +1,9 @@ +--no-private +--title=OpenTelemetry Racecar Instrumentation +--markup=markdown +--main=README.md +./lib/opentelemetry/instrumentation/**/*.rb +./lib/opentelemetry/instrumentation.rb +- +README.md +CHANGELOG.md diff --git a/instrumentation/racecar/Appraisals b/instrumentation/racecar/Appraisals new file mode 100644 index 000000000..8c24e16b1 --- /dev/null +++ b/instrumentation/racecar/Appraisals @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +## TODO: Include the supported version to be tested here. +## Example: +# appraise 'rack-2.1' do +# gem 'rack', '~> 2.1.2' +# end + +# appraise 'rack-2.0' do +# gem 'rack', '2.0.8' +# end diff --git a/instrumentation/racecar/CHANGELOG.md b/instrumentation/racecar/CHANGELOG.md new file mode 100644 index 000000000..97a90eeb4 --- /dev/null +++ b/instrumentation/racecar/CHANGELOG.md @@ -0,0 +1 @@ +# Release History: opentelemetry-instrumentation-racecar diff --git a/instrumentation/racecar/Gemfile b/instrumentation/racecar/Gemfile new file mode 100644 index 000000000..a952c5002 --- /dev/null +++ b/instrumentation/racecar/Gemfile @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +source 'https://rubygems.org' + +# DO NOT ADD DEPENDENCIES HERE! +# Please declare a minimum development dependency in the gemspec, +# then target specific versions in the Appraisals file. + +gemspec + +group :test do + gem 'opentelemetry-instrumentation-base', path: '../base' +end diff --git a/instrumentation/racecar/LICENSE b/instrumentation/racecar/LICENSE new file mode 100644 index 000000000..1ef7dad2c --- /dev/null +++ b/instrumentation/racecar/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/instrumentation/racecar/README.md b/instrumentation/racecar/README.md new file mode 100644 index 000000000..ccde2ad28 --- /dev/null +++ b/instrumentation/racecar/README.md @@ -0,0 +1,52 @@ +# OpenTelemetry Racecar Instrumentation + +Todo: Add a description. + +## How do I get started? + +Install the gem using: + +``` +gem install opentelemetry-instrumentation-racecar +``` + +Or, if you use [bundler][bundler-home], include `opentelemetry-instrumentation-racecar` in your `Gemfile`. + +## Usage + +To use the instrumentation, call `use` with the name of the instrumentation: + +```ruby +OpenTelemetry::SDK.configure do |c| + c.use 'OpenTelemetry::Instrumentation::Racecar' +end +``` + +Alternatively, you can also call `use_all` to install all the available instrumentation. + +```ruby +OpenTelemetry::SDK.configure do |c| + c.use_all +end +``` + +## Examples + +Example usage can be seen in the `./example/trace_demonstration.rb` file [here](https://github.com/open-telemetry/opentelemetry-ruby-contrib/blob/main/instrumentation/racecar/example/trace_demonstration.rb) + +## How can I get involved? + +The `opentelemetry-instrumentation-racecar` gem source is [on github][repo-github], along with related gems including `opentelemetry-api` and `opentelemetry-sdk`. + +The OpenTelemetry Ruby gems are maintained by the OpenTelemetry-Ruby special interest group (SIG). You can get involved by joining us in [GitHub Discussions][discussions-url] 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 `opentelemetry-instrumentation-racecar` gem is distributed under the Apache 2.0 license. See [LICENSE][license-github] for more information. + +[bundler-home]: https://bundler.io +[repo-github]: https://github.com/open-telemetry/opentelemetry-ruby +[license-github]: https://github.com/open-telemetry/opentelemetry-ruby-contrib/blob/main/LICENSE +[ruby-sig]: https://github.com/open-telemetry/community#ruby-sig +[community-meetings]: https://github.com/open-telemetry/community#community-meetings +[discussions-url]: https://github.com/open-telemetry/opentelemetry-ruby/discussions diff --git a/instrumentation/racecar/Rakefile b/instrumentation/racecar/Rakefile new file mode 100644 index 000000000..1a64ba842 --- /dev/null +++ b/instrumentation/racecar/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/instrumentation/racecar/lib/opentelemetry-instrumentation-racecar.rb b/instrumentation/racecar/lib/opentelemetry-instrumentation-racecar.rb new file mode 100644 index 000000000..baceb3cb7 --- /dev/null +++ b/instrumentation/racecar/lib/opentelemetry-instrumentation-racecar.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require_relative './opentelemetry/instrumentation' diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation.rb new file mode 100644 index 000000000..57448c911 --- /dev/null +++ b/instrumentation/racecar/lib/opentelemetry/instrumentation.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +# 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. +# +# The OpenTelemetry module provides global accessors for telemetry objects. +# See the documentation for the `opentelemetry-api` gem for details. +module OpenTelemetry + # Instrumentation should be able to handle the case when the library is not installed on a user's system. + module Instrumentation + end +end + +require_relative './instrumentation/racecar' diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar.rb new file mode 100644 index 000000000..ece61c6e7 --- /dev/null +++ b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'opentelemetry' +require 'opentelemetry-instrumentation-base' + +module OpenTelemetry + module Instrumentation + # Contains the OpenTelemetry instrumentation for the Racecar gem + module Racecar + end + end +end + +require_relative './racecar/instrumentation' +require_relative './racecar/version' diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb new file mode 100644 index 000000000..79657c08a --- /dev/null +++ b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module Instrumentation + module Racecar + # The Instrumentation class contains logic to detect and install the Racecar instrumentation + class Instrumentation < OpenTelemetry::Instrumentation::Base + install do |_config| + require_dependencies + end + + present do + # TODO: Replace true with a definition check of the gem being instrumented + # Example: `defined?(::Rack)` + true + end + + private + + def require_dependencies + # TODO: Include instrumentation dependencies + end + end + end + end +end diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/version.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/version.rb new file mode 100644 index 000000000..5adf6dc66 --- /dev/null +++ b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/version.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module Instrumentation + module Racecar + VERSION = '0.0.0' + end + end +end diff --git a/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec b/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec new file mode 100644 index 000000000..21a426058 --- /dev/null +++ b/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec @@ -0,0 +1,49 @@ +# 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 'opentelemetry/instrumentation/racecar/version' + +Gem::Specification.new do |spec| + spec.name = 'opentelemetry-instrumentation-racecar' + spec.version = OpenTelemetry::Instrumentation::Racecar::VERSION + spec.authors = ['OpenTelemetry Authors'] + spec.email = ['cncf-opentelemetry-contributors@lists.cncf.io'] + + spec.summary = 'Racecar instrumentation for the OpenTelemetry framework' + spec.description = 'Racecar instrumentation for the OpenTelemetry framework' + spec.homepage = 'https://github.com/open-telemetry/opentelemetry-ruby-contrib' + spec.license = 'Apache-2.0' + + spec.files = ::Dir.glob('lib/**/*.rb') + + ::Dir.glob('*.md') + + ['LICENSE', '.yardopts'] + spec.require_paths = ['lib'] + spec.required_ruby_version = '>= 2.6.0' + + spec.add_dependency 'opentelemetry-api', '~> 1.0' + spec.add_dependency 'opentelemetry-instrumentation-base', '~> 0.21.0' + + spec.add_development_dependency 'appraisal', '~> 2.2.0' + spec.add_development_dependency 'bundler', '>= 1.17' + spec.add_development_dependency 'minitest', '~> 5.0' + spec.add_development_dependency 'opentelemetry-sdk', '~> 1.0' + spec.add_development_dependency 'opentelemetry-test-helpers' + spec.add_development_dependency 'rake', '~> 12.3.3' + spec.add_development_dependency 'rubocop', '~> 0.73.0' + spec.add_development_dependency 'simplecov', '~> 0.17.1' + spec.add_development_dependency 'webmock', '~> 3.7.6' + spec.add_development_dependency 'yard', '~> 0.9' + spec.add_development_dependency 'yard-doctest', '~> 0.1.6' + + if spec.respond_to?(:metadata) + spec.metadata['changelog_uri'] = "https://open-telemetry.github.io/opentelemetry-ruby-contrib/opentelemetry-instrumentation-racecar/v#{OpenTelemetry::Instrumentation::Racecar::VERSION}/file.CHANGELOG.html" + spec.metadata['source_code_uri'] = 'https://github.com/open-telemetry/opentelemetry-ruby-contrib/tree/main/instrumentation/racecar' + spec.metadata['bug_tracker_uri'] = 'https://github.com/open-telemetry/opentelemetry-ruby-contrib/issues' + spec.metadata['documentation_uri'] = "https://open-telemetry.github.io/opentelemetry-ruby-contrib/opentelemetry-instrumentation-racecar/v#{OpenTelemetry::Instrumentation::Racecar::VERSION}" + end +end diff --git a/instrumentation/racecar/test/.rubocop.yml b/instrumentation/racecar/test/.rubocop.yml new file mode 100644 index 000000000..dd9425858 --- /dev/null +++ b/instrumentation/racecar/test/.rubocop.yml @@ -0,0 +1,4 @@ +inherit_from: ../.rubocop.yml + +Metrics/BlockLength: + Enabled: false diff --git a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/instrumentation_test.rb b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/instrumentation_test.rb new file mode 100644 index 000000000..bbd9c6980 --- /dev/null +++ b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/instrumentation_test.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'test_helper' + +require_relative '../../../../lib/opentelemetry/instrumentation/racecar' + +describe OpenTelemetry::Instrumentation::Racecar do + let(:instrumentation) { OpenTelemetry::Instrumentation::Racecar::Instrumentation.instance } + + it 'has #name' do + _(instrumentation.name).must_equal 'OpenTelemetry::Instrumentation::Racecar' + end + + it 'has #version' do + _(instrumentation.version).wont_be_nil + _(instrumentation.version).wont_be_empty + end + + describe '#install' do + it 'accepts argument' do + _(instrumentation.install({})).must_equal(true) + instrumentation.instance_variable_set(:@installed, false) + end + end +end diff --git a/instrumentation/racecar/test/test_helper.rb b/instrumentation/racecar/test/test_helper.rb new file mode 100644 index 000000000..abc143534 --- /dev/null +++ b/instrumentation/racecar/test/test_helper.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'opentelemetry/sdk' + +require 'minitest/autorun' +require 'webmock/minitest' + +# global opentelemetry-sdk setup: +EXPORTER = OpenTelemetry::SDK::Trace::Export::InMemorySpanExporter.new +span_processor = OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(EXPORTER) + +OpenTelemetry::SDK.configure do |c| + c.add_span_processor span_processor +end From 132293e0ab0b397c365953049bb9f757fbf33c9d Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Mon, 27 Jun 2022 20:05:19 +0100 Subject: [PATCH 02/33] add to all --- instrumentation/all/Gemfile | 2 ++ instrumentation/all/lib/opentelemetry/instrumentation/all.rb | 1 + instrumentation/all/opentelemetry-instrumentation-all.gemspec | 2 ++ 3 files changed, 5 insertions(+) diff --git a/instrumentation/all/Gemfile b/instrumentation/all/Gemfile index f649e2f64..d13c5ac3a 100644 --- a/instrumentation/all/Gemfile +++ b/instrumentation/all/Gemfile @@ -7,3 +7,5 @@ source 'https://rubygems.org' gemspec + +gem 'opentelemetry-instrumentation-racecar', path: '../racecar' diff --git a/instrumentation/all/lib/opentelemetry/instrumentation/all.rb b/instrumentation/all/lib/opentelemetry/instrumentation/all.rb index fb941d2b2..c8844faf3 100644 --- a/instrumentation/all/lib/opentelemetry/instrumentation/all.rb +++ b/instrumentation/all/lib/opentelemetry/instrumentation/all.rb @@ -4,6 +4,7 @@ # # SPDX-License-Identifier: Apache-2.0 +require 'opentelemetry-instrumentation-racecar' require 'opentelemetry-instrumentation-trilogy' require 'opentelemetry-instrumentation-active_support' require 'opentelemetry-instrumentation-action_pack' diff --git a/instrumentation/all/opentelemetry-instrumentation-all.gemspec b/instrumentation/all/opentelemetry-instrumentation-all.gemspec index 16ca9192b..9ab8ba8a1 100644 --- a/instrumentation/all/opentelemetry-instrumentation-all.gemspec +++ b/instrumentation/all/opentelemetry-instrumentation-all.gemspec @@ -26,6 +26,8 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] spec.required_ruby_version = '>= 2.6.0' + spec.add_dependency 'opentelemetry-instrumentation-action_pack', '~> 0.2.1' + spec.add_dependency 'opentelemetry-instrumentation-racecar', '~> 0.0.0' spec.add_dependency 'opentelemetry-instrumentation-action_pack', '~> 0.2.1' spec.add_dependency 'opentelemetry-instrumentation-action_view', '~> 0.3.0' spec.add_dependency 'opentelemetry-instrumentation-active_job', '~> 0.3.0' From 3ab6081d7778411808a28920f0846790b6f16663 Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Mon, 27 Jun 2022 20:05:03 +0100 Subject: [PATCH 03/33] add tracing to #process --- instrumentation/racecar/Gemfile | 3 +- .../racecar/instrumentation.rb | 24 ++- .../instrumentation/racecar/patches/runner.rb | 49 +++++ ...ntelemetry-instrumentation-racecar.gemspec | 3 + .../racecar/patches/runner_test.rb | 203 ++++++++++++++++++ instrumentation/racecar/test/test_helper.rb | 1 + 6 files changed, 276 insertions(+), 7 deletions(-) create mode 100644 instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/runner.rb create mode 100644 instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb diff --git a/instrumentation/racecar/Gemfile b/instrumentation/racecar/Gemfile index a952c5002..1be107c0a 100644 --- a/instrumentation/racecar/Gemfile +++ b/instrumentation/racecar/Gemfile @@ -12,6 +12,7 @@ source 'https://rubygems.org' gemspec -group :test do +group :development, :test do gem 'opentelemetry-instrumentation-base', path: '../base' + gem 'opentelemetry-instrumentation-rdkafka', path: '../rdkafka' end diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb index 79657c08a..e7904cbb8 100644 --- a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb +++ b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb @@ -4,25 +4,37 @@ # # SPDX-License-Identifier: Apache-2.0 +require 'opentelemetry-instrumentation-rdkafka' + module OpenTelemetry module Instrumentation module Racecar # The Instrumentation class contains logic to detect and install the Racecar instrumentation class Instrumentation < OpenTelemetry::Instrumentation::Base + MINIMUM_VERSION = Gem::Version.new('2.0') + + compatible do + Gem.loaded_specs['racecar'].version >= MINIMUM_VERSION + end + install do |_config| - require_dependencies + OpenTelemetry::Instrumentation::Rdkafka::Instrumentation.instance.install({}) + require_patches + patch end present do - # TODO: Replace true with a definition check of the gem being instrumented - # Example: `defined?(::Rack)` - true + defined?(::Racecar) end private - def require_dependencies - # TODO: Include instrumentation dependencies + def require_patches + require_relative 'patches/runner' + end + + def patch + ::Racecar::Runner.prepend(Patches::Runner) end end end diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/runner.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/runner.rb new file mode 100644 index 000000000..59bd4e02a --- /dev/null +++ b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/runner.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module Instrumentation + module Racecar + module Patches + # This module contains logic to patch Racecar::Runner and its processors + module Runner + def initialize(*args, **kwargs) + super + @processor.extend(Consumer) + end + + # This module contains logic to patch Racecar::Consumer + module Consumer + def process(message) + attributes = { + 'messaging.system' => 'kafka', + 'messaging.destination' => message.topic, + 'messaging.destination_kind' => 'topic', + 'messaging.kafka.partition' => message.partition, + 'messaging.kafka.offset' => message.offset + } + + attributes['messaging.kafka.message_key'] = message.key if message.key + parent_context = OpenTelemetry.propagation.extract(message.headers, getter: OpenTelemetry::Common::Propagation.symbol_key_getter) + span_context = OpenTelemetry::Trace.current_span(parent_context).context + links = [OpenTelemetry::Trace::Link.new(span_context)] if span_context.valid? + + OpenTelemetry::Context.with_current(parent_context) do + tracer.in_span("#{message.topic} process", links: links, attributes: attributes, kind: :consumer) do + super message + end + end + end + + def tracer + Racecar::Instrumentation.instance.tracer + end + end + end + end + end + end +end diff --git a/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec b/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec index 21a426058..ffe9e3db9 100644 --- a/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec +++ b/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec @@ -27,6 +27,8 @@ Gem::Specification.new do |spec| spec.add_dependency 'opentelemetry-api', '~> 1.0' spec.add_dependency 'opentelemetry-instrumentation-base', '~> 0.21.0' + spec.add_dependency 'opentelemetry-instrumentation-rdkafka', '~> 0.2.0' + spec.add_dependency 'racecar', '~> 2.0' spec.add_development_dependency 'appraisal', '~> 2.2.0' spec.add_development_dependency 'bundler', '>= 1.17' @@ -34,6 +36,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'opentelemetry-sdk', '~> 1.0' spec.add_development_dependency 'opentelemetry-test-helpers' spec.add_development_dependency 'rake', '~> 12.3.3' + spec.add_development_dependency 'rspec-mocks' spec.add_development_dependency 'rubocop', '~> 0.73.0' spec.add_development_dependency 'simplecov', '~> 0.17.1' spec.add_development_dependency 'webmock', '~> 3.7.6' diff --git a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb new file mode 100644 index 000000000..a4fd237b4 --- /dev/null +++ b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb @@ -0,0 +1,203 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'test_helper' +require 'securerandom' + +require 'racecar' +require 'racecar/cli' +require_relative '../../../../../lib/opentelemetry/instrumentation/racecar' +require_relative '../../../../../lib/opentelemetry/instrumentation/racecar/patches/runner' + +describe OpenTelemetry::Instrumentation::Racecar::Patches::Runner do + let(:instrumentation) { OpenTelemetry::Instrumentation::Racecar::Instrumentation.instance } + let(:exporter) { EXPORTER } + let(:spans) { exporter.finished_spans } + let(:host) { ENV.fetch('TEST_KAFKA_HOST') { '127.0.0.1' } } + let(:port) { (ENV.fetch('TEST_KAFKA_PORT') { 29_092 }) } + + let(:racecar) do + Racecar.config.brokers = ["#{host}:#{port}"] + Racecar::Cli.new([consumer_class.name.to_s]) + end + + let(:topic_name) do + rand_hash = SecureRandom.hex(10) + "consumer-patch-trace-#{rand_hash}" + end + + before do + # Clear spans + exporter.reset + + instrumentation.install + end + + describe '#process' do + describe 'when the consumer runs and publishes acks' do + let(:consumer_class) do + # a test class + class TestConsumer < Racecar::Consumer + def self.messages_seen + @messages_seen ||= [] + end + + def process(message) + TestConsumer.messages_seen << message + produce( + 'message seen', + topic: "ack-#{message.topic}" + ) + end + end + TestConsumer.subscribes_to(topic_name) + TestConsumer + end + + it 'traces each message and traces publishing' do + config = { "bootstrap.servers": "#{host}:#{port}" } + producer = Rdkafka::Config.new(config).producer + delivery_handles = [] + + delivery_handles << producer.produce( + topic: topic_name, + payload: 'never gonna', + key: 'Key 1' + ) + + delivery_handles << producer.produce( + topic: topic_name, + payload: 'give you up', + key: 'Key 2' + ) + + delivery_handles.each(&:wait) + + producer.close + + Thread.new do + racecar.run + end + + Timeout.timeout(30) do + sleep 0.1 until consumer_class.messages_seen.size >= 2 + end + + process_spans = spans.select { |s| s.name == "#{topic_name} process" } + racecar_send_spans = spans.select { |s| s.name == "ack-#{topic_name} send" } + + _(spans.size).must_equal(6) + + # First pair for send and process spans + first_process_span = process_spans[0] + _(first_process_span.name).must_equal("#{topic_name} process") + _(first_process_span.kind).must_equal(:consumer) + _(first_process_span.attributes['messaging.destination']).must_equal(topic_name) + _(first_process_span.attributes['messaging.kafka.partition']).wont_be_nil + + first_process_span_link = first_process_span.links[0] + linked_span_context = first_process_span_link.span_context + + linked_send_span = spans.find { |s| s.span_id == linked_span_context.span_id } + _(linked_send_span.name).must_equal("#{topic_name} send") + _(linked_send_span.trace_id).must_equal(first_process_span.trace_id) + _(linked_send_span.trace_id).must_equal(linked_span_context.trace_id) + + # first racecar ack span + first_send_span = racecar_send_spans[0] + _(first_send_span.name).must_equal("ack-#{topic_name} send") + _(first_send_span.kind).must_equal(:producer) + _(first_send_span.instrumentation_library.name).must_equal('OpenTelemetry::Instrumentation::Rdkafka') + _(first_send_span.parent_span_id).must_equal(first_process_span.span_id) + _(first_send_span.trace_id).must_equal(first_process_span.trace_id) + + # Second pair of send and process spans + second_process_span = process_spans[1] + _(second_process_span.name).must_equal("#{topic_name} process") + _(second_process_span.kind).must_equal(:consumer) + + second_process_span_link = second_process_span.links[0] + linked_span_context = second_process_span_link.span_context + + linked_send_span = spans.find { |s| s.span_id == linked_span_context.span_id } + _(linked_send_span.name).must_equal("#{topic_name} send") + _(linked_send_span.trace_id).must_equal(second_process_span.trace_id) + _(linked_send_span.trace_id).must_equal(linked_span_context.trace_id) + + # second racecar ack span + second_send_span = racecar_send_spans[1] + _(second_send_span.name).must_equal("ack-#{topic_name} send") + _(second_send_span.kind).must_equal(:producer) + _(second_send_span.instrumentation_library.name).must_equal('OpenTelemetry::Instrumentation::Rdkafka') + _(second_send_span.parent_span_id).must_equal(second_process_span.span_id) + _(second_send_span.trace_id).must_equal(second_process_span.trace_id) + end + end + + describe 'for an erroring consumer' do + let(:consumer_class) do + # a test class + class ErrorConsumer < Racecar::Consumer + def self.messages_seen + @messages_seen ||= [] + end + + def process(message) + ErrorConsumer.messages_seen << message + raise 'oops' + end + end + ErrorConsumer.subscribes_to(topic_name) + ErrorConsumer + end + + it 'can consume and publish a message' do + config = { "bootstrap.servers": "#{host}:#{port}" } + producer = Rdkafka::Config.new(config).producer + + producer.produce( + topic: topic_name, + payload: 'gonna error', + key: 'Key 1' + ) + + producer.close + + Thread.new do + racecar.run + end + + Timeout.timeout(30) do + sleep 0.1 until consumer_class.messages_seen.size >= 1 + end + + process_spans = spans.select { |s| s.name == "#{topic_name} process" } + + _(spans.size).must_equal(2) + + # First pair for send and process spans + first_process_span = process_spans[0] + _(first_process_span.name).must_equal("#{topic_name} process") + _(first_process_span.kind).must_equal(:consumer) + _(first_process_span.attributes['messaging.destination']).must_equal(topic_name) + _(first_process_span.attributes['messaging.kafka.partition']).wont_be_nil + + first_process_span_link = first_process_span.links[0] + linked_span_context = first_process_span_link.span_context + + linked_send_span = spans.find { |s| s.span_id == linked_span_context.span_id } + _(linked_send_span.name).must_equal("#{topic_name} send") + _(linked_send_span.trace_id).must_equal(first_process_span.trace_id) + _(linked_send_span.trace_id).must_equal(linked_span_context.trace_id) + + event = first_process_span.events.first + _(event.name).must_equal('exception') + _(event.attributes['exception.type']).must_equal('RuntimeError') + _(event.attributes['exception.message']).must_equal('oops') + end + end + end +end diff --git a/instrumentation/racecar/test/test_helper.rb b/instrumentation/racecar/test/test_helper.rb index abc143534..2b4b89c3f 100644 --- a/instrumentation/racecar/test/test_helper.rb +++ b/instrumentation/racecar/test/test_helper.rb @@ -8,6 +8,7 @@ require 'minitest/autorun' require 'webmock/minitest' +require 'rspec/mocks/minitest_integration' # global opentelemetry-sdk setup: EXPORTER = OpenTelemetry::SDK::Trace::Export::InMemorySpanExporter.new From dbc8def9673e8f17bb2b0717e7f248496206f9ea Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Mon, 27 Jun 2022 22:03:24 +0100 Subject: [PATCH 04/33] add support for batching --- .../instrumentation/racecar/patches/runner.rb | 31 +++++- .../racecar/patches/runner_test.rb | 96 +++++++++++++++++++ 2 files changed, 126 insertions(+), 1 deletion(-) diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/runner.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/runner.rb index 59bd4e02a..a3ac50a37 100644 --- a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/runner.rb +++ b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/runner.rb @@ -12,7 +12,11 @@ module Patches module Runner def initialize(*args, **kwargs) super - @processor.extend(Consumer) + if @processor.respond_to?(:process) + @processor.extend(Consumer) + elsif @processor.respond_to?(:process_batch) + @processor.extend(BatchConsumer) + end end # This module contains logic to patch Racecar::Consumer @@ -42,6 +46,31 @@ def tracer Racecar::Instrumentation.instance.tracer end end + + # This module contains logic to patch Racecar::Consumer for batch operations + module BatchConsumer + def process_batch(messages) + attributes = { + 'messaging.system' => 'kafka', + 'messaging.destination_kind' => 'topic', + 'messaging.kafka.message_count' => messages.size + } + + links = messages.map do |message| + span_context = OpenTelemetry::Trace.current_span(OpenTelemetry.propagation.extract(message.headers, getter: OpenTelemetry::Common::Propagation.symbol_key_getter)).context + OpenTelemetry::Trace::Link.new(span_context) if span_context.valid? + end + links.compact! + + tracer.in_span('batch process', attributes: attributes, links: links, kind: :consumer) do + super messages + end + end + + def tracer + Racecar::Instrumentation.instance.tracer + end + end end end end diff --git a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb index a4fd237b4..e0f4c966e 100644 --- a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb +++ b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb @@ -200,4 +200,100 @@ def process(message) end end end + + describe '#process_batch' do + let(:consumer_class) do + # a test class + class TestBatchConsumer < Racecar::Consumer + def self.messages_seen + @messages_seen ||= [] + end + + def process_batch(messages) + messages.each do |message| + produce( + 'message seen', + topic: "ack-#{message.topic}" + ) + TestBatchConsumer.messages_seen << message + end + end + end + TestBatchConsumer.subscribes_to(topic_name) + TestBatchConsumer + end + + it 'traces the batch call' do + config = { "bootstrap.servers": "#{host}:#{port}" } + producer = Rdkafka::Config.new(config).producer + delivery_handles = [] + + delivery_handles << producer.produce( + topic: topic_name, + payload: 'never gonna', + key: 'Key 1' + ) + + delivery_handles << producer.produce( + topic: topic_name, + payload: 'give you up', + key: 'Key 2' + ) + + delivery_handles.each(&:wait) + + producer.close + + Thread.new do + racecar.run + end + + Timeout.timeout(30) do + sleep 0.1 until consumer_class.messages_seen.size >= 2 + end + + batch_spans = spans.select { |s| s.name == 'batch process' } + + racecar_send_spans = spans.select { |s| s.name == "ack-#{topic_name} send" } + + _(spans.size).must_equal(5) + + batch_span = batch_spans[0] + _(batch_span.name).must_equal('batch process') + _(batch_span.kind).must_equal(:consumer) + _(batch_span.attributes['messaging.kafka.message_count']).must_equal(2) + + batch_span_link = batch_span.links[0] + linked_span_context = batch_span_link.span_context + + linked_send_span = spans.find { |s| s.span_id == linked_span_context.span_id } + _(linked_send_span.name).must_equal("#{topic_name} send") + _(linked_send_span.trace_id).wont_equal(batch_span.trace_id) + _(linked_send_span.trace_id).must_equal(linked_span_context.trace_id) + + batch_span_link = batch_span.links[1] + linked_span_context = batch_span_link.span_context + + linked_send_span = spans.find { |s| s.span_id == linked_span_context.span_id } + _(linked_send_span.name).must_equal("#{topic_name} send") + _(linked_send_span.trace_id).wont_equal(batch_span.trace_id) + _(linked_send_span.trace_id).must_equal(linked_span_context.trace_id) + + # first racecar ack span + first_send_span = racecar_send_spans[0] + _(first_send_span.name).must_equal("ack-#{topic_name} send") + _(first_send_span.kind).must_equal(:producer) + _(first_send_span.instrumentation_library.name).must_equal('OpenTelemetry::Instrumentation::Rdkafka') + _(first_send_span.parent_span_id).must_equal(batch_span.span_id) + _(first_send_span.trace_id).must_equal(batch_span.trace_id) + + # second racecar ack span + second_send_span = racecar_send_spans[1] + _(second_send_span.name).must_equal("ack-#{topic_name} send") + _(second_send_span.kind).must_equal(:producer) + _(second_send_span.instrumentation_library.name).must_equal('OpenTelemetry::Instrumentation::Rdkafka') + _(second_send_span.parent_span_id).must_equal(batch_span.span_id) + _(second_send_span.trace_id).must_equal(batch_span.trace_id) + end + end end From 2d2df0cef0b8b7ee68a6bf955336ecdf307eb23a Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Tue, 28 Jun 2022 11:56:03 +0100 Subject: [PATCH 05/33] add an example for tracing racecar --- instrumentation/racecar/example/Gemfile | 16 +++++++++ .../racecar/example/config/racecar.rb | 8 +++++ instrumentation/racecar/example/consumer.rb | 10 ++++++ .../racecar/example/trace_demonstration.sh | 4 +++ instrumentation/racecar/example/tracing.rb | 33 +++++++++++++++++++ 5 files changed, 71 insertions(+) create mode 100644 instrumentation/racecar/example/Gemfile create mode 100644 instrumentation/racecar/example/config/racecar.rb create mode 100644 instrumentation/racecar/example/consumer.rb create mode 100755 instrumentation/racecar/example/trace_demonstration.sh create mode 100644 instrumentation/racecar/example/tracing.rb diff --git a/instrumentation/racecar/example/Gemfile b/instrumentation/racecar/example/Gemfile new file mode 100644 index 000000000..e07e77a88 --- /dev/null +++ b/instrumentation/racecar/example/Gemfile @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +source 'https://rubygems.org' + +# DO NOT ADD DEPENDENCIES HERE! +# Please declare a minimum development dependency in the gemspec, +# then target specific versions in the Appraisals file. + +gem 'opentelemetry-instrumentation-base', path: '../../base' +gem 'opentelemetry-instrumentation-racecar', path: '../' +gem 'opentelemetry-sdk' +gem 'racecar' diff --git a/instrumentation/racecar/example/config/racecar.rb b/instrumentation/racecar/example/config/racecar.rb new file mode 100644 index 000000000..a88fc36c5 --- /dev/null +++ b/instrumentation/racecar/example/config/racecar.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +Racecar.configure do |config| + # Each config variable can be set using a writer attribute. + host = ENV.fetch('TEST_KAFKA_HOST') { '127.0.0.1' } + port = ENV.fetch('TEST_KAFKA_PORT') { 29_092 } + config.brokers = ["#{host}:#{port}"] +end diff --git a/instrumentation/racecar/example/consumer.rb b/instrumentation/racecar/example/consumer.rb new file mode 100644 index 000000000..652736587 --- /dev/null +++ b/instrumentation/racecar/example/consumer.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# an example consumer class +class Consumer < Racecar::Consumer + subscribes_to 'racecar-example-topic' + + def process(message) + puts 'consuming message' + end +end diff --git a/instrumentation/racecar/example/trace_demonstration.sh b/instrumentation/racecar/example/trace_demonstration.sh new file mode 100755 index 000000000..472172914 --- /dev/null +++ b/instrumentation/racecar/example/trace_demonstration.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +bundle check || bundle install +bundle exec racecar --require consumer --require tracing Consumer diff --git a/instrumentation/racecar/example/tracing.rb b/instrumentation/racecar/example/tracing.rb new file mode 100644 index 000000000..cc5ce9e06 --- /dev/null +++ b/instrumentation/racecar/example/tracing.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'opentelemetry/sdk' +require 'opentelemetry-instrumentation-racecar' + +ENV['OTEL_TRACES_EXPORTER'] ||= 'console' +OpenTelemetry::SDK.configure do |c| + c.use 'OpenTelemetry::Instrumentation::Racecar' +end + +host = ENV.fetch('TEST_KAFKA_HOST') { '127.0.0.1' } +port = ENV.fetch('TEST_KAFKA_PORT') { 29_092 } +config = { "bootstrap.servers": "#{host}:#{port}" } +producer = Rdkafka::Config.new(config).producer +delivery_handles = [] + +topic_name = 'racecar-example-topic' + +delivery_handles << producer.produce( + topic: topic_name, + payload: 'never gonna', + key: 'Key 1' +) + +delivery_handles << producer.produce( + topic: topic_name, + payload: 'give you up', + key: 'Key 2' +) + +delivery_handles.each(&:wait) + +producer.close From 315df6d7b4b9f6279dac24ad133e92e1dcdb18e4 Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Tue, 28 Jun 2022 11:57:31 +0100 Subject: [PATCH 06/33] add readme --- instrumentation/racecar/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/instrumentation/racecar/README.md b/instrumentation/racecar/README.md index ccde2ad28..08e3b9307 100644 --- a/instrumentation/racecar/README.md +++ b/instrumentation/racecar/README.md @@ -1,6 +1,7 @@ # OpenTelemetry Racecar Instrumentation -Todo: Add a description. +The Racecar instrumentation is a community-maintained instrumentation for [Racecar](https://github.com/zendesk/racecar), a client library for Apache Kafka. + ## How do I get started? @@ -32,7 +33,7 @@ end ## Examples -Example usage can be seen in the `./example/trace_demonstration.rb` file [here](https://github.com/open-telemetry/opentelemetry-ruby-contrib/blob/main/instrumentation/racecar/example/trace_demonstration.rb) +Example usage can be seen in the `./example` directory [here](https://github.com/open-telemetry/opentelemetry-ruby-contrib/blob/main/instrumentation/racecar/example). Run `./trace_demonstration.sh` to see its behaviour. ## How can I get involved? From 77dfca40e43332a25b36bb89706a153041740cdb Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Tue, 28 Jun 2022 21:35:11 +0100 Subject: [PATCH 07/33] refactor runner tests --- .../racecar/patches/runner_test.rb | 118 +++++++++--------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb index e0f4c966e..c2413ae87 100644 --- a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb +++ b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb @@ -19,9 +19,38 @@ let(:host) { ENV.fetch('TEST_KAFKA_HOST') { '127.0.0.1' } } let(:port) { (ENV.fetch('TEST_KAFKA_PORT') { 29_092 }) } + def produce(messages) + config = { "bootstrap.servers": "#{host}:#{port}" } + producer = Rdkafka::Config.new(config).producer + + producer_messages.map { |msg| producer.produce(**msg) }.each(&:wait) + + producer.close + end + let(:racecar) do Racecar.config.brokers = ["#{host}:#{port}"] - Racecar::Cli.new([consumer_class.name.to_s]) + Racecar.config.pause_timeout = 0 # fail fast and exit + Racecar.config.load_consumer_class(consumer_class) + Racecar::Runner.new(consumer_class.new, config: Racecar.config, logger: Logger.new(STDOUT)) + end + + def run_racecar(racecar) + Thread.new do + racecar.run + rescue RuntimeError => e + raise e unless e.message == 'oops' + end + end + + def stop_racecar(racecar) + racecar.stop + end + + def wait_for_messages_seen_by_consumer(count, timeout: 20) + Timeout.timeout(20) do + sleep 0.1 until consumer_class.messages_seen.size >= count + end end let(:topic_name) do @@ -34,6 +63,14 @@ exporter.reset instrumentation.install + + produce(producer_messages) + + run_racecar(racecar) + end + + after do + stop_racecar(racecar) end describe '#process' do @@ -57,34 +94,20 @@ def process(message) TestConsumer end - it 'traces each message and traces publishing' do - config = { "bootstrap.servers": "#{host}:#{port}" } - producer = Rdkafka::Config.new(config).producer - delivery_handles = [] - - delivery_handles << producer.produce( + let(:producer_messages) do + [{ topic: topic_name, payload: 'never gonna', key: 'Key 1' - ) - - delivery_handles << producer.produce( + }, { topic: topic_name, payload: 'give you up', key: 'Key 2' - ) - - delivery_handles.each(&:wait) - - producer.close - - Thread.new do - racecar.run - end + }] + end - Timeout.timeout(30) do - sleep 0.1 until consumer_class.messages_seen.size >= 2 - end + it 'traces each message and traces publishing' do + wait_for_messages_seen_by_consumer(2) process_spans = spans.select { |s| s.name == "#{topic_name} process" } racecar_send_spans = spans.select { |s| s.name == "ack-#{topic_name} send" } @@ -154,25 +177,16 @@ def process(message) ErrorConsumer end - it 'can consume and publish a message' do - config = { "bootstrap.servers": "#{host}:#{port}" } - producer = Rdkafka::Config.new(config).producer - - producer.produce( + let(:producer_messages) do + [{ topic: topic_name, - payload: 'gonna error', + payload: 'never gonna', key: 'Key 1' - ) - - producer.close - - Thread.new do - racecar.run - end + }] + end - Timeout.timeout(30) do - sleep 0.1 until consumer_class.messages_seen.size >= 1 - end + it 'can consume and publish a message' do + wait_for_messages_seen_by_consumer(1) process_spans = spans.select { |s| s.name == "#{topic_name} process" } @@ -223,34 +237,20 @@ def process_batch(messages) TestBatchConsumer end - it 'traces the batch call' do - config = { "bootstrap.servers": "#{host}:#{port}" } - producer = Rdkafka::Config.new(config).producer - delivery_handles = [] - - delivery_handles << producer.produce( + let(:producer_messages) do + [{ topic: topic_name, payload: 'never gonna', key: 'Key 1' - ) - - delivery_handles << producer.produce( + }, { topic: topic_name, payload: 'give you up', key: 'Key 2' - ) - - delivery_handles.each(&:wait) - - producer.close - - Thread.new do - racecar.run - end + }] + end - Timeout.timeout(30) do - sleep 0.1 until consumer_class.messages_seen.size >= 2 - end + it 'traces the batch call' do + wait_for_messages_seen_by_consumer(2) batch_spans = spans.select { |s| s.name == 'batch process' } From f0602d78fd4359ed74a7f8b4778604384a8a6055 Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Wed, 29 Jun 2022 19:03:47 +0100 Subject: [PATCH 08/33] move declarations to keep rubocop happy --- .../all/opentelemetry-instrumentation-all.gemspec | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/instrumentation/all/opentelemetry-instrumentation-all.gemspec b/instrumentation/all/opentelemetry-instrumentation-all.gemspec index 9ab8ba8a1..fe2be72de 100644 --- a/instrumentation/all/opentelemetry-instrumentation-all.gemspec +++ b/instrumentation/all/opentelemetry-instrumentation-all.gemspec @@ -26,7 +26,6 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] spec.required_ruby_version = '>= 2.6.0' - spec.add_dependency 'opentelemetry-instrumentation-action_pack', '~> 0.2.1' spec.add_dependency 'opentelemetry-instrumentation-racecar', '~> 0.0.0' spec.add_dependency 'opentelemetry-instrumentation-action_pack', '~> 0.2.1' spec.add_dependency 'opentelemetry-instrumentation-action_view', '~> 0.3.0' @@ -52,7 +51,12 @@ Gem::Specification.new do |spec| spec.add_dependency 'opentelemetry-instrumentation-net_http', '~> 0.21.0' spec.add_dependency 'opentelemetry-instrumentation-pg', '~> 0.22.0' spec.add_dependency 'opentelemetry-instrumentation-que', '~> 0.4.0' +<<<<<<< HEAD spec.add_dependency 'opentelemetry-instrumentation-rack', '~> 0.21.1' +======= + spec.add_dependency 'opentelemetry-instrumentation-racecar', '~> 0.0.0' + spec.add_dependency 'opentelemetry-instrumentation-rack', '~> 0.21.0' +>>>>>>> 9fc36e3f (move declarations to keep rubocop happy) spec.add_dependency 'opentelemetry-instrumentation-rails', '~> 0.22.0' spec.add_dependency 'opentelemetry-instrumentation-rdkafka', '~> 0.2.0' spec.add_dependency 'opentelemetry-instrumentation-redis', '~> 0.23.0' From 2b68fced8b577c6476d288041018f1137682d701 Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Thu, 30 Jun 2022 12:03:55 +0100 Subject: [PATCH 09/33] dont build on windows --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 72c2d6d7e..b9e570437 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -151,6 +151,8 @@ jobs: gem: rails - os: macos-latest gem: lmdb + - os: macos-latest + gem: opentelemetry-instrumentation-racecar name: ${{ matrix.gem }} / ${{ matrix.os }} runs-on: ${{ matrix.os }} From adb7bf2af22746b98aa200d6ea528ee3e3e4f89e Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Thu, 30 Jun 2022 14:02:16 +0100 Subject: [PATCH 10/33] racecar tests should run with kafka --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b9e570437..57a6e950e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -240,6 +240,7 @@ jobs: - mysql2 - pg - que + - racecar - rdkafka - redis - resque From 798d4c06c2d5263a206b8ca7a17489ffc1131e5d Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Thu, 30 Jun 2022 15:27:09 +0100 Subject: [PATCH 11/33] racecar should be a development dependency --- .../racecar/opentelemetry-instrumentation-racecar.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec b/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec index ffe9e3db9..d160845b7 100644 --- a/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec +++ b/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec @@ -28,13 +28,13 @@ Gem::Specification.new do |spec| spec.add_dependency 'opentelemetry-api', '~> 1.0' spec.add_dependency 'opentelemetry-instrumentation-base', '~> 0.21.0' spec.add_dependency 'opentelemetry-instrumentation-rdkafka', '~> 0.2.0' - spec.add_dependency 'racecar', '~> 2.0' spec.add_development_dependency 'appraisal', '~> 2.2.0' spec.add_development_dependency 'bundler', '>= 1.17' spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'opentelemetry-sdk', '~> 1.0' spec.add_development_dependency 'opentelemetry-test-helpers' + spec.add_development_dependency 'racecar', '~> 2.0' spec.add_development_dependency 'rake', '~> 12.3.3' spec.add_development_dependency 'rspec-mocks' spec.add_development_dependency 'rubocop', '~> 0.73.0' From cb87af36b0bfe6f6563a339b41fd6e94069b5f2e Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Sun, 3 Jul 2022 11:01:32 -0500 Subject: [PATCH 12/33] use racecar VERSION constant for compatability --- .../instrumentation/racecar/instrumentation.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb index e7904cbb8..fb0b182a1 100644 --- a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb +++ b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb @@ -14,7 +14,7 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base MINIMUM_VERSION = Gem::Version.new('2.0') compatible do - Gem.loaded_specs['racecar'].version >= MINIMUM_VERSION + gem_version >= MINIMUM_VERSION end install do |_config| @@ -36,6 +36,11 @@ def require_patches def patch ::Racecar::Runner.prepend(Patches::Runner) end + + def gem_version + require 'racecar/version' + Gem::Version.new(::Racecar::VERSION) + end end end end From c058798f63b12187c6ed74e913efe1b56edc739c Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Mon, 25 Jul 2022 22:34:36 +0100 Subject: [PATCH 13/33] set Appraisals for racecar --- instrumentation/racecar/Appraisals | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/instrumentation/racecar/Appraisals b/instrumentation/racecar/Appraisals index 8c24e16b1..478e440ce 100644 --- a/instrumentation/racecar/Appraisals +++ b/instrumentation/racecar/Appraisals @@ -4,12 +4,14 @@ # # SPDX-License-Identifier: Apache-2.0 -## TODO: Include the supported version to be tested here. -## Example: -# appraise 'rack-2.1' do -# gem 'rack', '~> 2.1.2' -# end - -# appraise 'rack-2.0' do -# gem 'rack', '2.0.8' -# end +appraise 'racecar-2.8' do + gem 'racecar', '~> 2.8.2' +end + +appraise 'racecar-2.7' do + gem 'racecar', '2.7.0' +end + +appraise 'racecar-2' do + gem 'racecar', '2.0.0' +end From 894108ad609ce56d42c765d07a80c3d1901d8f84 Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Thu, 28 Jul 2022 10:07:01 +0100 Subject: [PATCH 14/33] support recent versions of racecar only --- instrumentation/racecar/Appraisals | 4 ---- .../racecar/opentelemetry-instrumentation-racecar.gemspec | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/instrumentation/racecar/Appraisals b/instrumentation/racecar/Appraisals index 478e440ce..c2a909020 100644 --- a/instrumentation/racecar/Appraisals +++ b/instrumentation/racecar/Appraisals @@ -11,7 +11,3 @@ end appraise 'racecar-2.7' do gem 'racecar', '2.7.0' end - -appraise 'racecar-2' do - gem 'racecar', '2.0.0' -end diff --git a/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec b/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec index d160845b7..de037ddc2 100644 --- a/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec +++ b/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec @@ -34,7 +34,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'opentelemetry-sdk', '~> 1.0' spec.add_development_dependency 'opentelemetry-test-helpers' - spec.add_development_dependency 'racecar', '~> 2.0' + spec.add_development_dependency 'racecar', '~> 2.7' spec.add_development_dependency 'rake', '~> 12.3.3' spec.add_development_dependency 'rspec-mocks' spec.add_development_dependency 'rubocop', '~> 0.73.0' From 90b4a29dc53c8cba0823d1539db2419dd34a3e99 Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Thu, 28 Jul 2022 12:40:04 +0100 Subject: [PATCH 15/33] set minimum version to 2.7 --- .../opentelemetry/instrumentation/racecar/instrumentation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb index fb0b182a1..f7d7eb2bb 100644 --- a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb +++ b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb @@ -11,7 +11,7 @@ module Instrumentation module Racecar # The Instrumentation class contains logic to detect and install the Racecar instrumentation class Instrumentation < OpenTelemetry::Instrumentation::Base - MINIMUM_VERSION = Gem::Version.new('2.0') + MINIMUM_VERSION = Gem::Version.new('2.7') compatible do gem_version >= MINIMUM_VERSION From 1f6cdf61dc7e00d665cfb5ce8daea0645292500c Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Thu, 28 Jul 2022 13:00:50 +0100 Subject: [PATCH 16/33] ensure messages are delivered before marked as seen --- .../instrumentation/racecar/patches/runner_test.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb index c2413ae87..c2cd77e12 100644 --- a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb +++ b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb @@ -83,11 +83,12 @@ def self.messages_seen end def process(message) - TestConsumer.messages_seen << message produce( 'message seen', topic: "ack-#{message.topic}" ) + deliver! + TestConsumer.messages_seen << message end end TestConsumer.subscribes_to(topic_name) @@ -229,6 +230,7 @@ def process_batch(messages) 'message seen', topic: "ack-#{message.topic}" ) + deliver! TestBatchConsumer.messages_seen << message end end From 4a9f69c3f208ff46a15b9f9062bf550d576256e3 Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Sat, 30 Jul 2022 16:41:07 +0100 Subject: [PATCH 17/33] remove opentelemetry-instrumentation-rdkafka dependency --- instrumentation/racecar/Gemfile | 1 - .../racecar/instrumentation.rb | 5 ++- .../racecar/patches/consumer.rb | 35 +++++++++++++++++++ ...ntelemetry-instrumentation-racecar.gemspec | 1 - .../racecar/patches/runner_test.rb | 24 +++++++++---- 5 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/consumer.rb diff --git a/instrumentation/racecar/Gemfile b/instrumentation/racecar/Gemfile index 1be107c0a..b01dff429 100644 --- a/instrumentation/racecar/Gemfile +++ b/instrumentation/racecar/Gemfile @@ -14,5 +14,4 @@ gemspec group :development, :test do gem 'opentelemetry-instrumentation-base', path: '../base' - gem 'opentelemetry-instrumentation-rdkafka', path: '../rdkafka' end diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb index f7d7eb2bb..c6cbeae76 100644 --- a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb +++ b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb @@ -4,8 +4,6 @@ # # SPDX-License-Identifier: Apache-2.0 -require 'opentelemetry-instrumentation-rdkafka' - module OpenTelemetry module Instrumentation module Racecar @@ -18,7 +16,6 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base end install do |_config| - OpenTelemetry::Instrumentation::Rdkafka::Instrumentation.instance.install({}) require_patches patch end @@ -31,10 +28,12 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base def require_patches require_relative 'patches/runner' + require_relative 'patches/consumer' end def patch ::Racecar::Runner.prepend(Patches::Runner) + ::Racecar::Consumer.prepend(Patches::Consumer) end def gem_version diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/consumer.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/consumer.rb new file mode 100644 index 000000000..f1d46eae8 --- /dev/null +++ b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/consumer.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module Instrumentation + module Racecar + module Patches + # This module contains logic to patch Racecar::Consumer + module Consumer + def produce(payload, topic:, key: nil, partition: nil, partition_key: nil, headers: nil, create_time: nil) + attributes = { + 'messaging.system' => 'kafka', + 'messaging.destination' => topic, + 'messaging.destination_kind' => 'topic' + } + + headers ||= {} + + tracer.in_span("#{topic} send", attributes: attributes, kind: :producer) do + OpenTelemetry.propagation.inject(headers) + super + end + end + + def tracer + Racecar::Instrumentation.instance.tracer + end + end + end + end + end +end diff --git a/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec b/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec index de037ddc2..1a01b6283 100644 --- a/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec +++ b/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec @@ -27,7 +27,6 @@ Gem::Specification.new do |spec| spec.add_dependency 'opentelemetry-api', '~> 1.0' spec.add_dependency 'opentelemetry-instrumentation-base', '~> 0.21.0' - spec.add_dependency 'opentelemetry-instrumentation-rdkafka', '~> 0.2.0' spec.add_development_dependency 'appraisal', '~> 2.2.0' spec.add_development_dependency 'bundler', '>= 1.17' diff --git a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb index c2cd77e12..447eed398 100644 --- a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb +++ b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb @@ -10,20 +10,30 @@ require 'racecar' require 'racecar/cli' require_relative '../../../../../lib/opentelemetry/instrumentation/racecar' -require_relative '../../../../../lib/opentelemetry/instrumentation/racecar/patches/runner' -describe OpenTelemetry::Instrumentation::Racecar::Patches::Runner do +describe OpenTelemetry::Instrumentation::Racecar do let(:instrumentation) { OpenTelemetry::Instrumentation::Racecar::Instrumentation.instance } let(:exporter) { EXPORTER } let(:spans) { exporter.finished_spans } let(:host) { ENV.fetch('TEST_KAFKA_HOST') { '127.0.0.1' } } let(:port) { (ENV.fetch('TEST_KAFKA_PORT') { 29_092 }) } + def tracer + OpenTelemetry.tracer_provider.tracer('test-tracer') + end + def produce(messages) config = { "bootstrap.servers": "#{host}:#{port}" } producer = Rdkafka::Config.new(config).producer + producer.delivery_callback = ->(_) {} - producer_messages.map { |msg| producer.produce(**msg) }.each(&:wait) + producer_messages.map do |msg| + tracer.in_span("#{msg[:topic]} send", kind: :producer) do + msg[:headers] ||= {} + OpenTelemetry.propagation.inject(msg[:headers]) + producer.produce(**msg) + end + end.each(&:wait) producer.close end @@ -134,7 +144,7 @@ def process(message) first_send_span = racecar_send_spans[0] _(first_send_span.name).must_equal("ack-#{topic_name} send") _(first_send_span.kind).must_equal(:producer) - _(first_send_span.instrumentation_library.name).must_equal('OpenTelemetry::Instrumentation::Rdkafka') + _(first_send_span.instrumentation_library.name).must_equal('OpenTelemetry::Instrumentation::Racecar') _(first_send_span.parent_span_id).must_equal(first_process_span.span_id) _(first_send_span.trace_id).must_equal(first_process_span.trace_id) @@ -155,7 +165,7 @@ def process(message) second_send_span = racecar_send_spans[1] _(second_send_span.name).must_equal("ack-#{topic_name} send") _(second_send_span.kind).must_equal(:producer) - _(second_send_span.instrumentation_library.name).must_equal('OpenTelemetry::Instrumentation::Rdkafka') + _(second_send_span.instrumentation_library.name).must_equal('OpenTelemetry::Instrumentation::Racecar') _(second_send_span.parent_span_id).must_equal(second_process_span.span_id) _(second_send_span.trace_id).must_equal(second_process_span.trace_id) end @@ -285,7 +295,7 @@ def process_batch(messages) first_send_span = racecar_send_spans[0] _(first_send_span.name).must_equal("ack-#{topic_name} send") _(first_send_span.kind).must_equal(:producer) - _(first_send_span.instrumentation_library.name).must_equal('OpenTelemetry::Instrumentation::Rdkafka') + _(first_send_span.instrumentation_library.name).must_equal('OpenTelemetry::Instrumentation::Racecar') _(first_send_span.parent_span_id).must_equal(batch_span.span_id) _(first_send_span.trace_id).must_equal(batch_span.trace_id) @@ -293,7 +303,7 @@ def process_batch(messages) second_send_span = racecar_send_spans[1] _(second_send_span.name).must_equal("ack-#{topic_name} send") _(second_send_span.kind).must_equal(:producer) - _(second_send_span.instrumentation_library.name).must_equal('OpenTelemetry::Instrumentation::Rdkafka') + _(second_send_span.instrumentation_library.name).must_equal('OpenTelemetry::Instrumentation::Racecar') _(second_send_span.parent_span_id).must_equal(batch_span.span_id) _(second_send_span.trace_id).must_equal(batch_span.trace_id) end From 0575c8159f71ed03dc3c8dd14e426f539045f85a Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Mon, 1 Aug 2022 16:13:29 +0100 Subject: [PATCH 18/33] switch message processing instrumentation to use ASN --- .../racecar/instrumentation.rb | 10 +++- .../instrumentation/racecar/patches/runner.rb | 34 +---------- .../racecar/process_message_subscriber.rb | 59 +++++++++++++++++++ ...ntelemetry-instrumentation-racecar.gemspec | 1 + .../racecar/patches/runner_test.rb | 2 +- 5 files changed, 71 insertions(+), 35 deletions(-) create mode 100644 instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/process_message_subscriber.rb diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb index c6cbeae76..36d325a38 100644 --- a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb +++ b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb @@ -18,6 +18,7 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base install do |_config| require_patches patch + add_subscribers end present do @@ -27,8 +28,15 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base private def require_patches - require_relative 'patches/runner' require_relative 'patches/consumer' + require_relative 'patches/runner' + end + + def add_subscribers + require 'active_support' + require_relative 'process_message_subscriber' + subscriber = ProcessMessageSubscriber.new + ::ActiveSupport::Notifications.subscribe('process_message.racecar', subscriber) end def patch diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/runner.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/runner.rb index a3ac50a37..6667eeded 100644 --- a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/runner.rb +++ b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/runner.rb @@ -12,39 +12,7 @@ module Patches module Runner def initialize(*args, **kwargs) super - if @processor.respond_to?(:process) - @processor.extend(Consumer) - elsif @processor.respond_to?(:process_batch) - @processor.extend(BatchConsumer) - end - end - - # This module contains logic to patch Racecar::Consumer - module Consumer - def process(message) - attributes = { - 'messaging.system' => 'kafka', - 'messaging.destination' => message.topic, - 'messaging.destination_kind' => 'topic', - 'messaging.kafka.partition' => message.partition, - 'messaging.kafka.offset' => message.offset - } - - attributes['messaging.kafka.message_key'] = message.key if message.key - parent_context = OpenTelemetry.propagation.extract(message.headers, getter: OpenTelemetry::Common::Propagation.symbol_key_getter) - span_context = OpenTelemetry::Trace.current_span(parent_context).context - links = [OpenTelemetry::Trace::Link.new(span_context)] if span_context.valid? - - OpenTelemetry::Context.with_current(parent_context) do - tracer.in_span("#{message.topic} process", links: links, attributes: attributes, kind: :consumer) do - super message - end - end - end - - def tracer - Racecar::Instrumentation.instance.tracer - end + @processor.extend(BatchConsumer) if @processor.respond_to?(:process_batch) end # This module contains logic to patch Racecar::Consumer for batch operations diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/process_message_subscriber.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/process_message_subscriber.rb new file mode 100644 index 000000000..06aad2c85 --- /dev/null +++ b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/process_message_subscriber.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +module OpenTelemetry + module Instrumentation + # This class contains the ASN subsciber that instruments message processin + class ProcessMessageSubscriber + def tracer + Racecar::Instrumentation.instance.tracer + end + + def start(_name, _id, payload) + attrs = attributes(payload) + + parent_context = OpenTelemetry.propagation.extract(payload[:headers], getter: OpenTelemetry::Common::Propagation.symbol_key_getter) + parent_token = OpenTelemetry::Context.attach(parent_context) + + span_context = OpenTelemetry::Trace.current_span(parent_context).context + links = [OpenTelemetry::Trace::Link.new(span_context)] if span_context.valid? + + span = tracer.start_span("#{payload[:topic]} process", kind: :consumer, attributes: attrs, links: links) + token = OpenTelemetry::Context.attach(OpenTelemetry::Trace.context_with_span(span)) + payload.merge!( + __opentelemetry_span: span, + __opentelemetry_ctx_token: token, + __opentelemetry_parent_ctx_token: parent_token + ) + end + + def attributes(payload) + attributes = { + 'messaging.system' => 'kafka', + 'messaging.destination' => payload[:topic], + 'messaging.destination_kind' => 'topic', + 'messaging.kafka.partition' => payload[:partition], + 'messaging.kafka.offset' => payload[:offset] + } + + attributes['messaging.kafka.message_key'] = payload[:key] if payload[:key] + attributes + end + + def finish(name, id, payload) + span = payload.delete(:__opentelemetry_span) + token = payload.delete(:__opentelemetry_ctx_token) + parent_token = payload.delete(:__opentelemetry_parent_ctx_token) + return unless span && token + + if (e = payload[:exception_object]) + span.record_exception(e) + span.status = OpenTelemetry::Trace::Status.error("Unhandled exception of type: #{e.class}") + end + + span.finish + OpenTelemetry::Context.detach(token) + OpenTelemetry::Context.detach(parent_token) + end + end + end +end diff --git a/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec b/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec index 1a01b6283..7562a11a4 100644 --- a/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec +++ b/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec @@ -25,6 +25,7 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] spec.required_ruby_version = '>= 2.6.0' + spec.add_dependency 'activesupport' spec.add_dependency 'opentelemetry-api', '~> 1.0' spec.add_dependency 'opentelemetry-instrumentation-base', '~> 0.21.0' diff --git a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb index 447eed398..f3da4dfe4 100644 --- a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb +++ b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb @@ -42,7 +42,7 @@ def produce(messages) Racecar.config.brokers = ["#{host}:#{port}"] Racecar.config.pause_timeout = 0 # fail fast and exit Racecar.config.load_consumer_class(consumer_class) - Racecar::Runner.new(consumer_class.new, config: Racecar.config, logger: Logger.new(STDOUT)) + Racecar::Runner.new(consumer_class.new, config: Racecar.config, logger: Logger.new(STDOUT), instrumenter: Racecar.instrumenter) end def run_racecar(racecar) From f42ea644c594a44cdc87e40f3fa4cffda8c12698 Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Mon, 1 Aug 2022 16:20:22 +0100 Subject: [PATCH 19/33] move integration test to racecar_test.rb --- .../{racecar/patches/runner_test.rb => racecar_test.rb} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename instrumentation/racecar/test/opentelemetry/instrumentation/{racecar/patches/runner_test.rb => racecar_test.rb} (99%) diff --git a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb similarity index 99% rename from instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb rename to instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb index f3da4dfe4..af6f3de40 100644 --- a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/patches/runner_test.rb +++ b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb @@ -9,7 +9,7 @@ require 'racecar' require 'racecar/cli' -require_relative '../../../../../lib/opentelemetry/instrumentation/racecar' +require_relative '../../../lib/opentelemetry/instrumentation/racecar' describe OpenTelemetry::Instrumentation::Racecar do let(:instrumentation) { OpenTelemetry::Instrumentation::Racecar::Instrumentation.instance } From ad8606efcbbba26e77a3bb45400fd2c024ac42ab Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Mon, 1 Aug 2022 16:23:43 +0100 Subject: [PATCH 20/33] remove the batch consumer --- .../racecar/instrumentation.rb | 2 - .../instrumentation/racecar/patches/runner.rb | 46 ---------- .../instrumentation/racecar_test.rb | 83 ------------------- 3 files changed, 131 deletions(-) delete mode 100644 instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/runner.rb diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb index 36d325a38..0c87abbc7 100644 --- a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb +++ b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb @@ -29,7 +29,6 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base def require_patches require_relative 'patches/consumer' - require_relative 'patches/runner' end def add_subscribers @@ -40,7 +39,6 @@ def add_subscribers end def patch - ::Racecar::Runner.prepend(Patches::Runner) ::Racecar::Consumer.prepend(Patches::Consumer) end diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/runner.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/runner.rb deleted file mode 100644 index 6667eeded..000000000 --- a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/patches/runner.rb +++ /dev/null @@ -1,46 +0,0 @@ -# frozen_string_literal: true - -# Copyright The OpenTelemetry Authors -# -# SPDX-License-Identifier: Apache-2.0 - -module OpenTelemetry - module Instrumentation - module Racecar - module Patches - # This module contains logic to patch Racecar::Runner and its processors - module Runner - def initialize(*args, **kwargs) - super - @processor.extend(BatchConsumer) if @processor.respond_to?(:process_batch) - end - - # This module contains logic to patch Racecar::Consumer for batch operations - module BatchConsumer - def process_batch(messages) - attributes = { - 'messaging.system' => 'kafka', - 'messaging.destination_kind' => 'topic', - 'messaging.kafka.message_count' => messages.size - } - - links = messages.map do |message| - span_context = OpenTelemetry::Trace.current_span(OpenTelemetry.propagation.extract(message.headers, getter: OpenTelemetry::Common::Propagation.symbol_key_getter)).context - OpenTelemetry::Trace::Link.new(span_context) if span_context.valid? - end - links.compact! - - tracer.in_span('batch process', attributes: attributes, links: links, kind: :consumer) do - super messages - end - end - - def tracer - Racecar::Instrumentation.instance.tracer - end - end - end - end - end - end -end diff --git a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb index af6f3de40..59a8190a5 100644 --- a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb +++ b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb @@ -225,87 +225,4 @@ def process(message) end end end - - describe '#process_batch' do - let(:consumer_class) do - # a test class - class TestBatchConsumer < Racecar::Consumer - def self.messages_seen - @messages_seen ||= [] - end - - def process_batch(messages) - messages.each do |message| - produce( - 'message seen', - topic: "ack-#{message.topic}" - ) - deliver! - TestBatchConsumer.messages_seen << message - end - end - end - TestBatchConsumer.subscribes_to(topic_name) - TestBatchConsumer - end - - let(:producer_messages) do - [{ - topic: topic_name, - payload: 'never gonna', - key: 'Key 1' - }, { - topic: topic_name, - payload: 'give you up', - key: 'Key 2' - }] - end - - it 'traces the batch call' do - wait_for_messages_seen_by_consumer(2) - - batch_spans = spans.select { |s| s.name == 'batch process' } - - racecar_send_spans = spans.select { |s| s.name == "ack-#{topic_name} send" } - - _(spans.size).must_equal(5) - - batch_span = batch_spans[0] - _(batch_span.name).must_equal('batch process') - _(batch_span.kind).must_equal(:consumer) - _(batch_span.attributes['messaging.kafka.message_count']).must_equal(2) - - batch_span_link = batch_span.links[0] - linked_span_context = batch_span_link.span_context - - linked_send_span = spans.find { |s| s.span_id == linked_span_context.span_id } - _(linked_send_span.name).must_equal("#{topic_name} send") - _(linked_send_span.trace_id).wont_equal(batch_span.trace_id) - _(linked_send_span.trace_id).must_equal(linked_span_context.trace_id) - - batch_span_link = batch_span.links[1] - linked_span_context = batch_span_link.span_context - - linked_send_span = spans.find { |s| s.span_id == linked_span_context.span_id } - _(linked_send_span.name).must_equal("#{topic_name} send") - _(linked_send_span.trace_id).wont_equal(batch_span.trace_id) - _(linked_send_span.trace_id).must_equal(linked_span_context.trace_id) - - # first racecar ack span - first_send_span = racecar_send_spans[0] - _(first_send_span.name).must_equal("ack-#{topic_name} send") - _(first_send_span.kind).must_equal(:producer) - _(first_send_span.instrumentation_library.name).must_equal('OpenTelemetry::Instrumentation::Racecar') - _(first_send_span.parent_span_id).must_equal(batch_span.span_id) - _(first_send_span.trace_id).must_equal(batch_span.trace_id) - - # second racecar ack span - second_send_span = racecar_send_spans[1] - _(second_send_span.name).must_equal("ack-#{topic_name} send") - _(second_send_span.kind).must_equal(:producer) - _(second_send_span.instrumentation_library.name).must_equal('OpenTelemetry::Instrumentation::Racecar') - _(second_send_span.parent_span_id).must_equal(batch_span.span_id) - _(second_send_span.trace_id).must_equal(batch_span.trace_id) - end - end end From bf3c8effe5c07c9bed056910c401969a07269866 Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Mon, 1 Aug 2022 17:05:43 +0100 Subject: [PATCH 21/33] fix: improve guards when stopping racecar --- .../test/opentelemetry/instrumentation/racecar_test.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb index 59a8190a5..42a7fdfcc 100644 --- a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb +++ b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb @@ -47,14 +47,16 @@ def produce(messages) def run_racecar(racecar) Thread.new do + Thread.current[:racecar] = racecar racecar.run rescue RuntimeError => e raise e unless e.message == 'oops' end end - def stop_racecar(racecar) - racecar.stop + def stop_racecar(thread) + thread[:racecar].stop + thread.join(60) end def wait_for_messages_seen_by_consumer(count, timeout: 20) @@ -76,11 +78,11 @@ def wait_for_messages_seen_by_consumer(count, timeout: 20) produce(producer_messages) - run_racecar(racecar) + @racecar_thread = run_racecar(racecar) end after do - stop_racecar(racecar) + stop_racecar(@racecar_thread) end describe '#process' do From 5b4d6e8ba09dbd03b4b96930914cfc9ae7db9f51 Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Mon, 1 Aug 2022 17:44:40 +0100 Subject: [PATCH 22/33] switch order of appraisals --- instrumentation/racecar/Appraisals | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/instrumentation/racecar/Appraisals b/instrumentation/racecar/Appraisals index c2a909020..fdef7f748 100644 --- a/instrumentation/racecar/Appraisals +++ b/instrumentation/racecar/Appraisals @@ -4,10 +4,10 @@ # # SPDX-License-Identifier: Apache-2.0 -appraise 'racecar-2.8' do - gem 'racecar', '~> 2.8.2' +appraise 'racecar-2.7' do + gem 'racecar', '~> 2.7.0' end -appraise 'racecar-2.7' do - gem 'racecar', '2.7.0' +appraise 'racecar-2.8' do + gem 'racecar', '~> 2.8.2' end From 554ee087cb39ac19e3cd0ff4b912836e02d39461 Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Mon, 1 Aug 2022 19:35:03 +0100 Subject: [PATCH 23/33] test: increase test timeouts --- .../test/opentelemetry/instrumentation/racecar_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb index 42a7fdfcc..87328e170 100644 --- a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb +++ b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb @@ -59,8 +59,8 @@ def stop_racecar(thread) thread.join(60) end - def wait_for_messages_seen_by_consumer(count, timeout: 20) - Timeout.timeout(20) do + def wait_for_messages_seen_by_consumer(count) + Timeout.timeout(60) do sleep 0.1 until consumer_class.messages_seen.size >= count end end From 99a9b4ecfe18233b352c12c770921f38f5c14906 Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Mon, 1 Aug 2022 20:46:57 +0100 Subject: [PATCH 24/33] fix: support jruby --- instrumentation/racecar/Gemfile | 1 + 1 file changed, 1 insertion(+) diff --git a/instrumentation/racecar/Gemfile b/instrumentation/racecar/Gemfile index b01dff429..b4aa971cf 100644 --- a/instrumentation/racecar/Gemfile +++ b/instrumentation/racecar/Gemfile @@ -13,5 +13,6 @@ source 'https://rubygems.org' gemspec group :development, :test do + gem 'activesupport', '~> 6' # used to test against JRuby which is only MRI 2.6 compatibile gem 'opentelemetry-instrumentation-base', path: '../base' end From 064f407596a2ef9a311608114b942f5e8933df87 Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Tue, 2 Aug 2022 12:13:30 +0100 Subject: [PATCH 25/33] fix: skip truffleruby builds for racecar --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 57a6e950e..e1d03fd90 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -298,6 +298,7 @@ jobs: run: | echo "skip=false" >> $GITHUB_OUTPUT [[ "${{ matrix.gem }}" == "que" ]] && echo "skip=true" >> $GITHUB_OUTPUT + [[ "${{ matrix.gem }}" == "racecar" ]] && echo "skip=true" >> $GITHUB_OUTPUT [[ "${{ matrix.gem }}" == "rdkafka" ]] && echo "skip=true" >> $GITHUB_OUTPUT [[ "${{ matrix.gem }}" == "ruby_kafka" ]] && echo "skip=true" >> $GITHUB_OUTPUT # This is essentially a bash script getting evaluated, so we need to return true or the whole job fails. From 178a4475a23e6ed4936cb58aa34eb65840a06289 Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Wed, 3 Aug 2022 19:50:49 +0100 Subject: [PATCH 26/33] refactor: remove the direct dependency on activesupport --- instrumentation/racecar/example/Gemfile | 1 + instrumentation/racecar/example/tracing.rb | 1 + .../opentelemetry/instrumentation/racecar/instrumentation.rb | 5 ++--- .../instrumentation/racecar/instrumentation_test.rb | 1 + .../test/opentelemetry/instrumentation/racecar_test.rb | 1 - instrumentation/racecar/test/test_helper.rb | 3 +++ 6 files changed, 8 insertions(+), 4 deletions(-) diff --git a/instrumentation/racecar/example/Gemfile b/instrumentation/racecar/example/Gemfile index e07e77a88..18a5d5f32 100644 --- a/instrumentation/racecar/example/Gemfile +++ b/instrumentation/racecar/example/Gemfile @@ -10,6 +10,7 @@ source 'https://rubygems.org' # Please declare a minimum development dependency in the gemspec, # then target specific versions in the Appraisals file. +gem 'activesupport' gem 'opentelemetry-instrumentation-base', path: '../../base' gem 'opentelemetry-instrumentation-racecar', path: '../' gem 'opentelemetry-sdk' diff --git a/instrumentation/racecar/example/tracing.rb b/instrumentation/racecar/example/tracing.rb index cc5ce9e06..7bf7143ff 100644 --- a/instrumentation/racecar/example/tracing.rb +++ b/instrumentation/racecar/example/tracing.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require 'active_support' require 'opentelemetry/sdk' require 'opentelemetry-instrumentation-racecar' diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb index 0c87abbc7..3ce37aae1 100644 --- a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb +++ b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/instrumentation.rb @@ -12,7 +12,7 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base MINIMUM_VERSION = Gem::Version.new('2.7') compatible do - gem_version >= MINIMUM_VERSION + !defined?(::ActiveSupport::Notifications).nil? && gem_version >= MINIMUM_VERSION end install do |_config| @@ -28,11 +28,10 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base private def require_patches - require_relative 'patches/consumer' + require_relative './patches/consumer' end def add_subscribers - require 'active_support' require_relative 'process_message_subscriber' subscriber = ProcessMessageSubscriber.new ::ActiveSupport::Notifications.subscribe('process_message.racecar', subscriber) diff --git a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/instrumentation_test.rb b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/instrumentation_test.rb index bbd9c6980..056993b4b 100644 --- a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/instrumentation_test.rb +++ b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar/instrumentation_test.rb @@ -22,6 +22,7 @@ describe '#install' do it 'accepts argument' do + _(instrumentation.compatible?).must_equal(true) _(instrumentation.install({})).must_equal(true) instrumentation.instance_variable_set(:@installed, false) end diff --git a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb index 87328e170..d4971997d 100644 --- a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb +++ b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb @@ -7,7 +7,6 @@ require 'test_helper' require 'securerandom' -require 'racecar' require 'racecar/cli' require_relative '../../../lib/opentelemetry/instrumentation/racecar' diff --git a/instrumentation/racecar/test/test_helper.rb b/instrumentation/racecar/test/test_helper.rb index 2b4b89c3f..32889aa09 100644 --- a/instrumentation/racecar/test/test_helper.rb +++ b/instrumentation/racecar/test/test_helper.rb @@ -17,3 +17,6 @@ OpenTelemetry::SDK.configure do |c| c.add_span_processor span_processor end + +require 'racecar' +require 'active_support' From 95cc55182846ef656493333c8537e9760a92652a Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Wed, 3 Aug 2022 19:54:54 +0100 Subject: [PATCH 27/33] docs: add a note about requiring active_support to work --- instrumentation/racecar/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/instrumentation/racecar/README.md b/instrumentation/racecar/README.md index 08e3b9307..cd41cdaf1 100644 --- a/instrumentation/racecar/README.md +++ b/instrumentation/racecar/README.md @@ -13,6 +13,10 @@ gem install opentelemetry-instrumentation-racecar Or, if you use [bundler][bundler-home], include `opentelemetry-instrumentation-racecar` in your `Gemfile`. +## Runtime requirements + +This instrumentation is built on top of Racecar's integration with `ActiveSupport::Notifications`. `ActiveSupport::Notification` will need to be loaded before the instrumentation is installed (as below) or the installation will cancel. + ## Usage To use the instrumentation, call `use` with the name of the instrumentation: From 3be803834a002cd7c343e335665273666210311f Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Wed, 3 Aug 2022 19:57:50 +0100 Subject: [PATCH 28/33] fix: set the version to 0.1.0 --- .../all/opentelemetry-instrumentation-all.gemspec | 6 +----- .../lib/opentelemetry/instrumentation/racecar/version.rb | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/instrumentation/all/opentelemetry-instrumentation-all.gemspec b/instrumentation/all/opentelemetry-instrumentation-all.gemspec index fe2be72de..1a2d81ee9 100644 --- a/instrumentation/all/opentelemetry-instrumentation-all.gemspec +++ b/instrumentation/all/opentelemetry-instrumentation-all.gemspec @@ -51,12 +51,8 @@ Gem::Specification.new do |spec| spec.add_dependency 'opentelemetry-instrumentation-net_http', '~> 0.21.0' spec.add_dependency 'opentelemetry-instrumentation-pg', '~> 0.22.0' spec.add_dependency 'opentelemetry-instrumentation-que', '~> 0.4.0' -<<<<<<< HEAD + spec.add_dependency 'opentelemetry-instrumentation-racecar', '~> 0.1.0' spec.add_dependency 'opentelemetry-instrumentation-rack', '~> 0.21.1' -======= - spec.add_dependency 'opentelemetry-instrumentation-racecar', '~> 0.0.0' - spec.add_dependency 'opentelemetry-instrumentation-rack', '~> 0.21.0' ->>>>>>> 9fc36e3f (move declarations to keep rubocop happy) spec.add_dependency 'opentelemetry-instrumentation-rails', '~> 0.22.0' spec.add_dependency 'opentelemetry-instrumentation-rdkafka', '~> 0.2.0' spec.add_dependency 'opentelemetry-instrumentation-redis', '~> 0.23.0' diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/version.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/version.rb index 5adf6dc66..db6106879 100644 --- a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/version.rb +++ b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/version.rb @@ -7,7 +7,7 @@ module OpenTelemetry module Instrumentation module Racecar - VERSION = '0.0.0' + VERSION = '0.1.0' end end end From cbf0bf25805f581473acec2b8aad19a92be5d3be Mon Sep 17 00:00:00 2001 From: Ariel Valentin Date: Tue, 27 Sep 2022 15:55:00 -0500 Subject: [PATCH 29/33] docs: Correct Spelling Error Co-authored-by: Eric Mustin --- .../instrumentation/racecar/process_message_subscriber.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/process_message_subscriber.rb b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/process_message_subscriber.rb index 06aad2c85..31199dfd5 100644 --- a/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/process_message_subscriber.rb +++ b/instrumentation/racecar/lib/opentelemetry/instrumentation/racecar/process_message_subscriber.rb @@ -2,7 +2,7 @@ module OpenTelemetry module Instrumentation - # This class contains the ASN subsciber that instruments message processin + # This class contains the ASN subsciber that instruments message processing class ProcessMessageSubscriber def tracer Racecar::Instrumentation.instance.tracer From 0108765c628830dd6b2ed3d1607deace8f4644ba Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Tue, 4 Oct 2022 12:46:14 +0100 Subject: [PATCH 30/33] make activesupport a development dependency --- .../racecar/opentelemetry-instrumentation-racecar.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec b/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec index 7562a11a4..c94604e2c 100644 --- a/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec +++ b/instrumentation/racecar/opentelemetry-instrumentation-racecar.gemspec @@ -25,10 +25,10 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] spec.required_ruby_version = '>= 2.6.0' - spec.add_dependency 'activesupport' spec.add_dependency 'opentelemetry-api', '~> 1.0' spec.add_dependency 'opentelemetry-instrumentation-base', '~> 0.21.0' + spec.add_development_dependency 'activesupport' spec.add_development_dependency 'appraisal', '~> 2.2.0' spec.add_development_dependency 'bundler', '>= 1.17' spec.add_development_dependency 'minitest', '~> 5.0' From ae6dee431c8a49d9ed7c84c7180be654dc25a253 Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Wed, 12 Oct 2022 21:39:34 +0100 Subject: [PATCH 31/33] refactor: simplifty test consumers by changing waiting logic Rather than counting the messages received by the tests consumer the tests will now wait count for an expected number of spans received at the exporter. This has an equivalent outcome, but simplifies the contents of the consumers. --- .../instrumentation/racecar_test.rb | 78 ++++++++----------- 1 file changed, 31 insertions(+), 47 deletions(-) diff --git a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb index d4971997d..1f51feb35 100644 --- a/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb +++ b/instrumentation/racecar/test/opentelemetry/instrumentation/racecar_test.rb @@ -14,10 +14,23 @@ let(:instrumentation) { OpenTelemetry::Instrumentation::Racecar::Instrumentation.instance } let(:exporter) { EXPORTER } let(:spans) { exporter.finished_spans } - let(:host) { ENV.fetch('TEST_KAFKA_HOST') { '127.0.0.1' } } - let(:port) { (ENV.fetch('TEST_KAFKA_PORT') { 29_092 }) } + let(:host) { ENV.fetch('TEST_KAFKA_HOST', '127.0.0.1') } + let(:port) { ENV.fetch('TEST_KAFKA_PORT', 29_092) } - def tracer + def wait_for_spans(count) + Timeout.timeout(60) do + sleep 0.1 while exporter.finished_spans.size < count + end + end + + let(:consumer_class) do + klass = Class.new(Racecar::Consumer) + klass.define_method(:process, &process_method) + klass.subscribes_to(topic_name) + stub_const('TestConsumer', klass) + end + + let(:tracer) do OpenTelemetry.tracer_provider.tracer('test-tracer') end @@ -58,12 +71,6 @@ def stop_racecar(thread) thread.join(60) end - def wait_for_messages_seen_by_consumer(count) - Timeout.timeout(60) do - sleep 0.1 until consumer_class.messages_seen.size >= count - end - end - let(:topic_name) do rand_hash = SecureRandom.hex(10) "consumer-patch-trace-#{rand_hash}" @@ -78,6 +85,7 @@ def wait_for_messages_seen_by_consumer(count) produce(producer_messages) @racecar_thread = run_racecar(racecar) + wait_for_spans(expected_spans) end after do @@ -86,24 +94,14 @@ def wait_for_messages_seen_by_consumer(count) describe '#process' do describe 'when the consumer runs and publishes acks' do - let(:consumer_class) do - # a test class - class TestConsumer < Racecar::Consumer - def self.messages_seen - @messages_seen ||= [] - end - - def process(message) - produce( - 'message seen', - topic: "ack-#{message.topic}" - ) - deliver! - TestConsumer.messages_seen << message - end + let(:process_method) do + lambda do |message| + produce( + 'message seen', + topic: "ack-#{message.topic}" + ) + deliver! end - TestConsumer.subscribes_to(topic_name) - TestConsumer end let(:producer_messages) do @@ -118,14 +116,12 @@ def process(message) }] end - it 'traces each message and traces publishing' do - wait_for_messages_seen_by_consumer(2) + let(:expected_spans) { 6 } + it 'traces each message and traces publishing' do process_spans = spans.select { |s| s.name == "#{topic_name} process" } racecar_send_spans = spans.select { |s| s.name == "ack-#{topic_name} send" } - _(spans.size).must_equal(6) - # First pair for send and process spans first_process_span = process_spans[0] _(first_process_span.name).must_equal("#{topic_name} process") @@ -173,20 +169,10 @@ def process(message) end describe 'for an erroring consumer' do - let(:consumer_class) do - # a test class - class ErrorConsumer < Racecar::Consumer - def self.messages_seen - @messages_seen ||= [] - end - - def process(message) - ErrorConsumer.messages_seen << message - raise 'oops' - end + let(:process_method) do + lambda do |_message| + raise 'oops' end - ErrorConsumer.subscribes_to(topic_name) - ErrorConsumer end let(:producer_messages) do @@ -197,13 +183,11 @@ def process(message) }] end - it 'can consume and publish a message' do - wait_for_messages_seen_by_consumer(1) + let(:expected_spans) { 2 } + it 'can consume and publish a message' do process_spans = spans.select { |s| s.name == "#{topic_name} process" } - _(spans.size).must_equal(2) - # First pair for send and process spans first_process_span = process_spans[0] _(first_process_span.name).must_equal("#{topic_name} process") From 1b047d6178bcee3f6950273cb84c17787e512b0b Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Thu, 13 Oct 2022 22:54:57 +0100 Subject: [PATCH 32/33] fix: list racecar in all correctly --- instrumentation/all/lib/opentelemetry/instrumentation/all.rb | 2 +- instrumentation/all/opentelemetry-instrumentation-all.gemspec | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/instrumentation/all/lib/opentelemetry/instrumentation/all.rb b/instrumentation/all/lib/opentelemetry/instrumentation/all.rb index c8844faf3..3ac338188 100644 --- a/instrumentation/all/lib/opentelemetry/instrumentation/all.rb +++ b/instrumentation/all/lib/opentelemetry/instrumentation/all.rb @@ -4,7 +4,6 @@ # # SPDX-License-Identifier: Apache-2.0 -require 'opentelemetry-instrumentation-racecar' require 'opentelemetry-instrumentation-trilogy' require 'opentelemetry-instrumentation-active_support' require 'opentelemetry-instrumentation-action_pack' @@ -30,6 +29,7 @@ require 'opentelemetry-instrumentation-net_http' require 'opentelemetry-instrumentation-pg' require 'opentelemetry-instrumentation-que' +require 'opentelemetry-instrumentation-racecar' require 'opentelemetry-instrumentation-rack' require 'opentelemetry-instrumentation-rails' require 'opentelemetry-instrumentation-rdkafka' diff --git a/instrumentation/all/opentelemetry-instrumentation-all.gemspec b/instrumentation/all/opentelemetry-instrumentation-all.gemspec index 1a2d81ee9..d08daf3b4 100644 --- a/instrumentation/all/opentelemetry-instrumentation-all.gemspec +++ b/instrumentation/all/opentelemetry-instrumentation-all.gemspec @@ -26,7 +26,6 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] spec.required_ruby_version = '>= 2.6.0' - spec.add_dependency 'opentelemetry-instrumentation-racecar', '~> 0.0.0' spec.add_dependency 'opentelemetry-instrumentation-action_pack', '~> 0.2.1' spec.add_dependency 'opentelemetry-instrumentation-action_view', '~> 0.3.0' spec.add_dependency 'opentelemetry-instrumentation-active_job', '~> 0.3.0' From bfe220e0ea12bd6bdcd5bbca6009ef935b15e277 Mon Sep 17 00:00:00 2001 From: Christopher Holmes Date: Thu, 3 Nov 2022 14:30:57 +0000 Subject: [PATCH 33/33] add the racecar instrumentaiton back to CI --- .github/workflows/ci-instrumentation-with-services.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci-instrumentation-with-services.yml b/.github/workflows/ci-instrumentation-with-services.yml index f919817f5..7e72729d0 100644 --- a/.github/workflows/ci-instrumentation-with-services.yml +++ b/.github/workflows/ci-instrumentation-with-services.yml @@ -24,6 +24,7 @@ jobs: - mysql2 - pg - que + - racecar - rdkafka - redis - resque @@ -61,6 +62,7 @@ jobs: [[ "${{ matrix.gem }}" == "mysql2" ]] && echo "skip=true" >> $GITHUB_OUTPUT [[ "${{ matrix.gem }}" == "pg" ]] && echo "skip=true" >> $GITHUB_OUTPUT [[ "${{ matrix.gem }}" == "que" ]] && echo "skip=true" >> $GITHUB_OUTPUT + [[ "${{ matrix.gem }}" == "racecar" ]] && echo "skip=true" >> $GITHUB_OUTPUT [[ "${{ matrix.gem }}" == "rdkafka" ]] && echo "skip=true" >> $GITHUB_OUTPUT [[ "${{ matrix.gem }}" == "redis" ]] && echo "skip=true" >> $GITHUB_OUTPUT [[ "${{ matrix.gem }}" == "resque" ]] && echo "skip=true" >> $GITHUB_OUTPUT