Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SDTEST-228] auto instrumentation #230

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 0 additions & 15 deletions bin/console

This file was deleted.

11 changes: 11 additions & 0 deletions bin/ddcirb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env ruby

rubyopts = [
"-rdatadog/ci/auto_instrument"
]

existing_rubyopt = ENV["RUBYOPT"]

ENV["RUBYOPT"] = existing_rubyopt ? "#{existing_rubyopt} #{rubyopts.join(" ")}" : rubyopts.join(" ")

::Kernel.exec(*ARGV)
8 changes: 0 additions & 8 deletions bin/setup

This file was deleted.

2 changes: 2 additions & 0 deletions datadog-ci.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Gem::Specification.new do |spec|

spec.homepage = "https://github.com/DataDog/datadog-ci-rb"
spec.license = "BSD-3-Clause"
spec.executables = ["ddcirb"]

spec.metadata["allowed_push_host"] = "https://rubygems.org"
spec.metadata["changelog_uri"] = "https://github.com/DataDog/datadog-ci-rb/blob/main/CHANGELOG.md"
Expand All @@ -36,6 +37,7 @@ Gem::Specification.new do |spec|
README.md
ext/**/*
lib/**/*
bin/**/*
]].select { |fn| File.file?(fn) } # We don't want directories, only files
.reject { |fn| fn.end_with?(".so", ".bundle") } # Exclude local native binary artifacts

Expand Down
1 change: 1 addition & 0 deletions lib/datadog/ci.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
require_relative "ci/ext/app_types"
require_relative "ci/ext/telemetry"

require "datadog"
require "datadog/core"

module Datadog
Expand Down
4 changes: 4 additions & 0 deletions lib/datadog/ci/auto_instrument.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
require "datadog/ci"
require "datadog/ci/contrib/contrib"

Datadog::CI::Contrib.auto_instrument!
73 changes: 69 additions & 4 deletions lib/datadog/ci/contrib/contrib.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,83 @@
module Datadog
module CI
module Contrib
@@auto_instrumented_integrations = {}

def self.auto_instrument!
Datadog.logger.debug("Auto instrumenting all integrations...")

Integration.registry.each do |name, integration|
next unless integration.auto_instrument?

Datadog.logger.debug "#{name} is allowed to be auto instrumented"

if integration.class.loaded?
Datadog.logger.debug("#{name} is already loaded")

configure_ci_with_framework(name)
else
Datadog.logger.debug("#{name} is not loaded yet")

Datadog.logger.debug("Registering on require hook for #{name}...")

@@auto_instrumented_integrations[name] = integration
end
end

enable_trace_requires
end

def self.enable_trace_requires
@@trp = TracePoint.new(:script_compiled) do |tp|
on_require(tp.instruction_sequence.path)
end

@@trp.enable
end

def self.disable_trace_requires
@@trp.disable
end

def self.on_require(path)
Datadog.logger.debug { "Path: #{path}" }
@@auto_instrumented_integrations.each do |gem_name, integration|
if path.include?(gem_name.to_s) && integration.class.loaded?
Datadog.logger.debug { "Gem '#{gem_name}' loaded. Configuring integration." }

Contrib.disable_trace_requires

configure_ci_with_framework(gem_name)
end
end
rescue => e
Datadog.logger.debug do
"Failed to execute callback for gem: #{e.class.name} #{e.message} at #{Array(e.backtrace).join("\n")}"
end
end

def self.configure_ci_with_framework(framework)
Datadog.logger.debug("Configuring CI with #{framework}...")

Datadog.configure do |c|
c.tracing.enabled = true
c.ci.enabled = true
c.ci.instrument framework
end
end

# This method auto instruments all test libraries (ex: selenium-webdriver).
# It is intended to be called when test session starts to add additional capabilities to test visibility.
#
# This method does not automatically instrument test frameworks (ex: RSpec, Cucumber, etc), it requires
# test framework to be already instrumented.
def self.auto_instrument_on_session_start!
Datadog.logger.debug("Auto instrumenting all integrations...")
def self.instrument_on_session_start!
Datadog.logger.debug("Instrumenting additional libraries when session starts...")

Integration.registry.each do |name, integration|
next unless integration.auto_instrument?
next unless integration.instrument_on_session_start?

Datadog.logger.debug "#{name} is allowed to be auto instrumented"
Datadog.logger.debug "#{name} is allowed to be instrumented when session starts"

patch_results = integration.patch
if patch_results == true
Expand Down
7 changes: 5 additions & 2 deletions lib/datadog/ci/contrib/cucumber/integration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,18 @@ def self.version
end

def self.loaded?
!defined?(::Cucumber).nil? && !defined?(::Cucumber::Runtime).nil?
!defined?(::Cucumber).nil? && !defined?(::Cucumber::Runtime).nil? && !defined?(::Cucumber::Configuration).nil?
end

def self.compatible?
super && version >= MINIMUM_VERSION
end

# test environments should not auto instrument test libraries
def auto_instrument?
true
end

def instrument_on_session_start?
false
end

Expand Down
8 changes: 6 additions & 2 deletions lib/datadog/ci/contrib/minitest/integration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,19 @@ def self.version
end

def self.loaded?
!defined?(::Minitest).nil?
!defined?(::Minitest).nil? && !defined?(::Minitest::Runnable).nil? && !defined?(::Minitest::Test).nil? &&
!defined?(::Minitest::CompositeReporter).nil?
end

def self.compatible?
super && version >= MINIMUM_VERSION
end

# test environments should not auto instrument test libraries
def auto_instrument?
true
end

def instrument_on_session_start?
false
end

Expand Down
11 changes: 9 additions & 2 deletions lib/datadog/ci/contrib/rspec/integration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,22 @@ def self.version

def self.loaded?
!defined?(::RSpec).nil? && !defined?(::RSpec::Core).nil? &&
!defined?(::RSpec::Core::Example).nil?
!defined?(::RSpec::Core::Example).nil? &&
!defined?(::RSpec::Core::Runner).nil? &&
!defined?(::RSpec::Core::ExampleGroup).nil?
end

def self.compatible?
super && version >= MINIMUM_VERSION
end

# test environments should not auto instrument test libraries
# TODO: rename the following 2 methods: the difference is not about auto or on session start:
# the difference is that the first one is for test frameworks, the second one is for additional libraries
def auto_instrument?
true
end

def instrument_on_session_start?
false
end

Expand Down
6 changes: 5 additions & 1 deletion lib/datadog/ci/contrib/selenium/integration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@ def self.compatible?
super && version >= MINIMUM_VERSION
end

# additional instrumentations for test helpers are auto instrumented on test session start
def auto_instrument?
false
end

# additional instrumentations for test helpers are instrumented on test session start
def instrument_on_session_start?
true
end

Expand Down
2 changes: 1 addition & 1 deletion lib/datadog/ci/test_visibility/component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ def on_test_session_started(test_session)
git_tree_upload_worker.perform(test_session.git_repository_url)

# finds and instruments additional test libraries that we support (ex: selenium-webdriver)
Contrib.auto_instrument_on_session_start!
Contrib.instrument_on_session_start!

# sends internal telemetry events
Telemetry.test_session_started(test_session)
Expand Down
2 changes: 1 addition & 1 deletion sig/datadog/ci/contrib/selenium/integration.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ module Datadog

def self.compatible?: () -> bool

def auto_instrument?: () -> true
def auto_instrument?: () -> bool

def new_configuration: () -> untyped

Expand Down
4 changes: 4 additions & 0 deletions spec/datadog/ci/configuration/settings_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ def self.auto_instrument?
false
end

def instrument_on_session_start?
false
end

def patcher
Patcher
end
Expand Down
2 changes: 1 addition & 1 deletion spec/datadog/ci/contrib/cucumber/integration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
describe "#auto_instrument?" do
subject(:auto_instrument?) { integration.auto_instrument? }

it { is_expected.to be(false) }
it { is_expected.to be(true) }
end

describe "#configuration" do
Expand Down
2 changes: 1 addition & 1 deletion spec/datadog/ci/contrib/minitest/integration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
describe "#auto_instrument?" do
subject(:auto_instrument?) { integration.auto_instrument? }

it { is_expected.to be(false) }
it { is_expected.to be(true) }
end

describe "#configuration" do
Expand Down
2 changes: 1 addition & 1 deletion spec/datadog/ci/contrib/rspec/integration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
describe "#auto_instrument?" do
subject(:auto_instrument?) { integration.auto_instrument? }

it { is_expected.to be(false) }
it { is_expected.to be(true) }
end

describe "#configuration" do
Expand Down
1 change: 0 additions & 1 deletion spec/datadog/ci/release_gem_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
|\.circleci
|\.github
|\.vscode
| bin
|gemfiles
|integration
|tasks
Expand Down
Loading