Module: Datadog::DI::Remote Private
- Defined in:
- lib/datadog/di/remote.rb
Overview
This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.
Provides an interface expected by the core Remote subsystem to receive DI-specific remote configuration.
In order to apply (i.e., act on) the configuration, we need the state stored under DI Component. Thus, this module forwards actual configuration application to the ProbeManager associated with the global DI Component.
Constant Summary collapse
- PRODUCT =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
"LIVE_DEBUGGING"- CAPABILITIES =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Declared here (not in Tracing::Remote::CAPABILITIES) so it is registered only with the gated DI block in Capabilities#register: when DI is explicitly disabled, or the runtime cannot run DI (JRuby, Ruby 2.5), that block — including this bit — is skipped. The enable signal itself is delivered in APM_TRACING payloads and routed here by Tracing::Remote.merge_and_apply_configs.
[ 1 << 38, # APM_TRACING_ENABLE_DYNAMIC_INSTRUMENTATION: Implicit DI enablement ].freeze
Class Method Summary collapse
- .capabilities ⇒ Object private
-
.explicitly_disabled?(settings = Datadog.configuration) ⇒ Boolean
private
Symmetric to Component.explicitly_enabled? (see there for why using_default? rather than options.default_precedence?).
-
.handle_rc_enablement(enabled, repository = nil) ⇒ void
private
Entry point for the RC-driven DI enable/disable path.
- .products ⇒ Object private
- .receiver(products = [PRODUCT], &block) ⇒ Object private
- .receivers(telemetry) ⇒ Object private
Class Method Details
.capabilities ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
34 35 36 |
# File 'lib/datadog/di/remote.rb', line 34 def capabilities CAPABILITIES end |
.explicitly_disabled?(settings = Datadog.configuration) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Symmetric to Component.explicitly_enabled? (see there for why using_default? rather than options.default_precedence?).
Canonical home for the explicit-disable check: it gates
Component.build and the DI block in
Core::Remote::Client::Capabilities#register. The latter runs before
DI::Component is loaded, so the check lives here on DI::Remote (always
required by capabilities.rb) rather than on DI::Component. The
settings argument lets those startup callers pass the settings being
configured; the RC handler omits it and reads the global config.
136 137 138 139 |
# File 'lib/datadog/di/remote.rb', line 136 def explicitly_disabled?(settings = Datadog.configuration) !settings.dynamic_instrumentation.using_default?(:enabled) && !settings.dynamic_instrumentation.enabled end |
.handle_rc_enablement(enabled, repository = nil) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Entry point for the RC-driven DI enable/disable path.
Invoked from Tracing::Remote.merge_and_apply_configs when an
APM_TRACING payload carries dynamic_instrumentation_enabled. Runs
on the remote-config thread; never raises.
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/datadog/di/remote.rb', line 53 def handle_rc_enablement(enabled, repository = nil) # allow_initialization: false because this runs on the remote-config # thread (a callback context). The default `true` would synchronously # build the entire component tree from the wrong thread if the RC # signal lands before Components#initialize completed. components = Datadog.send(:components, allow_initialization: false) component = components&.dynamic_instrumentation unless component # The component is nil because Component.build returned nil at # startup — a runtime precondition is not met (RC disabled, MRI # required, Ruby 2.6+ required, Rails dev env, C extension absent). # On disable, silently no-op: RC asking us to turn off something we # don't have is fine. On enable, warn with the reason: this is the # implicit-enablement counterpart to the warn-on-explicit message # at build time. The customer who clicked "create probe" in the UI # gets the same visibility a customer who set # DD_DYNAMIC_INSTRUMENTATION_ENABLED would have gotten at boot. if enabled if explicitly_disabled? Datadog.logger.warn( "di: cannot enable dynamic instrumentation via remote configuration " \ "because DD_DYNAMIC_INSTRUMENTATION_ENABLED is explicitly set to false", ) else reason = DI.unsupported_reason Datadog.logger.warn( "di: cannot enable dynamic instrumentation via remote configuration: " \ "#{reason || "dynamic instrumentation was not initialized at startup"}", ) end end return end if enabled if explicitly_disabled? Datadog.logger.warn( "di: ignoring implicit enablement signal from remote configuration " \ "because DD_DYNAMIC_INSTRUMENTATION_ENABLED is explicitly set to false. " \ "To allow remote enablement, unset DD_DYNAMIC_INSTRUMENTATION_ENABLED.", ) return end # component is non-nil here only because Component.build's preconditions # passed, which is the same condition under which di/base.rb is loaded # and DI.activate_tracking is defined. DI.activate_tracking was_started = component.started? component.start! # A probe delivered in an earlier poll while the component was stopped # was dropped by #receivers (which ignores changes while !started?) and # never entered the probe repository. RC dispatch only re-delivers a # config when its content hash changes (Core::Remote::Client#apply_config # skips unchanged content), so the probe would otherwise stay dropped # until the customer edits it. On the stopped->started transition, # reconcile against the current LIVE_DEBUGGING contents so it installs now. replay_current_probes(repository, component) if repository && !was_started else component.stop! end rescue => e Datadog.logger.debug { "di: error handling implicit enablement: #{e.class}: #{e.}" } Datadog.send(:components, allow_initialization: false)&.telemetry&.report( e, description: "Error handling DI implicit enablement", ) end |
.products ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
30 31 32 |
# File 'lib/datadog/di/remote.rb', line 30 def products [PRODUCT] end |
.receiver(products = [PRODUCT], &block) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
177 178 179 180 |
# File 'lib/datadog/di/remote.rb', line 177 def receiver(products = [PRODUCT], &block) matcher = Core::Remote::Dispatcher::Matcher::Product.new(products) [Core::Remote::Dispatcher::Receiver.new(matcher, &block)] end |
.receivers(telemetry) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/datadog/di/remote.rb', line 141 def receivers(telemetry) receiver do |repository, changes| # DEV: Filter our by product. Given it will be very common # DEV: we can filter this out before we receive the data in this method. # DEV: Apply this refactor to AppSec as well if implemented. component = DI.component if component&.started? changes.each do |change| case change.type when :insert # A stopped->started reconcile (#replay_current_probes) may have # installed this probe earlier in the same dispatch — the enable # signal is carried by the Tracing receiver, which runs before the # DI receiver. Skip the redundant install rather than letting # probe_manager raise AlreadyInstrumented and report a false error. unless probe_in_content_known?(change.content, component) # steep:ignore NoMethod add_probe(change.content, component) # steep:ignore NoMethod end when :update # We do not implement updates at the moment, remove the # probe and reinstall. remove_probe(change.content, component) # steep:ignore NoMethod add_probe(change.content, component) # steep:ignore NoMethod when :delete remove_probe(change.previous, component) # steep:ignore NoMethod else # This really should never happen since we generate the # change types in the library. component.logger.debug { "di: unrecognized change type: #{change.type}" } end end end end end |