Module: Datadog::CI::Contrib::Instrumentation
- Defined in:
- lib/datadog/ci/contrib/instrumentation.rb
Defined Under Namespace
Classes: InvalidIntegrationError
Class Method Summary collapse
- .auto_configure_datadog ⇒ Object
-
.auto_instrument ⇒ Object
Auto instrumentation of all integrations.
-
.configure_once ⇒ Object
This is not thread safe, it is synchronized by the caller in the tracepoint.
- .fetch_auto_instrumented_integrations ⇒ Object
- .fetch_integration(name) ⇒ Object
-
.instrument(integration_name, options = {}, &block) ⇒ Object
Manual instrumentation of a specific integration.
-
.instrument_on_session_start ⇒ Object
This method instruments all additional test libraries (ex: selenium-webdriver) that need to be instrumented later in the test suite run.
-
.integration_name(subclass) ⇒ Object
take the parent module name and downcase it for example for Datadog::CI::Contrib::RSpec::Integration it will be :rspec.
- .patch_integration(integration, with_dependencies: false) ⇒ Object
- .register_integration(integration_class) ⇒ Object
- .registry ⇒ Object
Class Method Details
.auto_configure_datadog ⇒ Object
150 151 152 153 154 155 156 157 158 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 150 def self.auto_configure_datadog configure_once.run do Datadog.logger.debug("Applying Datadog configuration in CI mode...") Datadog.configure do |c| c.ci.enabled = true c.tracing.enabled = true end end end |
.auto_instrument ⇒ Object
Auto instrumentation of all integrations.
Registers a :script_compiled tracepoint to watch for new Ruby files being loaded. On every file load it checks if any of the integrations are patchable now. Only the integrations that are available in the environment are checked.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 26 def self.auto_instrument Datadog.logger.debug("Auto instrumenting all integrations...") auto_instrumented_integrations = fetch_auto_instrumented_integrations if auto_instrumented_integrations.empty? Datadog.logger.warn( "Auto instrumentation was requested, but no available integrations were found. " \ "Tests will be run without Datadog instrumentation." ) return end # note that `Kernel.require` might be called from a different thread, so # there is a possibility of concurrent execution of this tracepoint mutex = Mutex.new script_compiled_tracepoint = TracePoint.new(:script_compiled) do |tp| all_patched = true mutex.synchronize do auto_instrumented_integrations.each do |integration| next if integration.patched? all_patched = false next unless integration.loaded? auto_configure_datadog Datadog.logger.debug("#{integration.class} is loaded") patch_integration(integration) end if all_patched Datadog.logger.debug("All expected integrations are patched, disabling the script_compiled tracepoint") tp.disable end end end script_compiled_tracepoint.enable end |
.configure_once ⇒ Object
This is not thread safe, it is synchronized by the caller in the tracepoint
161 162 163 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 161 def self.configure_once @configure_once ||= Datadog::Core::Utils::OnlyOnce.new end |
.fetch_auto_instrumented_integrations ⇒ Object
137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 137 def self.fetch_auto_instrumented_integrations @registry.filter_map do |name, integration| # ignore integrations that are not in the Gemfile or have incompatible versions next unless integration.compatible? # late instrumented integrations will be patched when the test session starts next if integration.late_instrument? Datadog.logger.debug("#{name} should be auto instrumented") integration end end |
.fetch_integration(name) ⇒ Object
100 101 102 103 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 100 def self.fetch_integration(name) @registry[name] || raise(InvalidIntegrationError, "'#{name}' is not a valid integration.") end |
.instrument(integration_name, options = {}, &block) ⇒ Object
Manual instrumentation of a specific integration.
This method is called when user has ‘c.ci.instrument :integration_name` in their code.
70 71 72 73 74 75 76 77 78 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 70 def self.instrument(integration_name, = {}, &block) integration = fetch_integration(integration_name) # when manually instrumented, it might be configured via code integration.configure(, &block) return unless integration.enabled patch_integration(integration, with_dependencies: true) end |
.instrument_on_session_start ⇒ Object
This method instruments all additional test libraries (ex: selenium-webdriver) that need to be instrumented later in the test suite run.
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.
87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 87 def self.instrument_on_session_start Datadog.logger.debug("Instrumenting all late instrumented integrations...") @registry.each do |name, integration| next unless integration.late_instrument? next unless integration.enabled Datadog.logger.debug "#{name} is allowed to be late instrumented" patch_integration(integration) end end |
.integration_name(subclass) ⇒ Object
take the parent module name and downcase it for example for Datadog::CI::Contrib::RSpec::Integration it will be :rspec
107 108 109 110 111 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 107 def self.integration_name(subclass) result = subclass.name&.split("::")&.[](-2)&.downcase&.to_sym raise "Integration name could not be derived for #{subclass}" if result.nil? result end |
.patch_integration(integration, with_dependencies: false) ⇒ Object
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 113 def self.patch_integration(integration, with_dependencies: false) patch_results = integration.patch if patch_results[:ok] Datadog.logger.debug("#{integration.class} is patched") return unless with_dependencies # try to patch dependant integrations (for example knapsack that depends on rspec) dependants = integration.dependants .map { |name| fetch_integration(name) } .filter { |integration| integration.patchable? } Datadog.logger.debug("Found dependent integrations for #{integration.class}: #{dependants}") dependants.each do |dependent_integration| patch_integration(dependent_integration, with_dependencies: true) end else Datadog.logger.debug("Attention: #{integration.class} is not patched (#{patch_results})") end end |
.register_integration(integration_class) ⇒ Object
17 18 19 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 17 def self.register_integration(integration_class) @registry[integration_name(integration_class)] = integration_class.new end |
.registry ⇒ Object
13 14 15 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 13 def self.registry @registry end |