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.
- .auto_instrumented? ⇒ Boolean
-
.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
156 157 158 159 160 161 162 163 164 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 156 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.
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 66 67 68 69 70 71 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 31 def self.auto_instrument Datadog.logger.debug("Auto instrumenting all integrations...") @auto_instrumented = true 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 |
.auto_instrumented? ⇒ Boolean
22 23 24 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 22 def self.auto_instrumented? @auto_instrumented end |
.configure_once ⇒ Object
This is not thread safe, it is synchronized by the caller in the tracepoint
167 168 169 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 167 def self.configure_once @configure_once ||= Datadog::Core::Utils::OnlyOnce.new end |
.fetch_auto_instrumented_integrations ⇒ Object
143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 143 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
106 107 108 109 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 106 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.
76 77 78 79 80 81 82 83 84 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 76 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.
93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 93 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
113 114 115 116 117 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 113 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
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 119 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
18 19 20 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 18 def self.register_integration(integration_class) @registry[integration_name(integration_class)] = integration_class.new end |
.registry ⇒ Object
14 15 16 |
# File 'lib/datadog/ci/contrib/instrumentation.rb', line 14 def self.registry @registry end |