Class: Datadog::DI::Component Private
- Inherits:
-
Object
- Object
- Datadog::DI::Component
- Defined in:
- lib/datadog/di/component.rb
Overview
This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.
Component for dynamic instrumentation.
Only one instance of the Component should ever be active; if configuration is changed, the old distance should be shut down prior to the new instance being created.
The Component instance stores all state related to DI, for example which probes have been retrieved via remote config, intalled tracepoints and so on. Component will clean up all resources and installed tracepoints upon shutdown.
Instance Attribute Summary collapse
- #agent_settings ⇒ Object readonly private
- #code_tracker ⇒ Object readonly private
- #instrumenter ⇒ Object readonly private
- #logger ⇒ Object readonly private
- #probe_manager ⇒ Object readonly private
- #probe_notification_builder ⇒ Object readonly private
- #probe_notifier_worker ⇒ Object readonly private
- #probe_repository ⇒ Object readonly private
- #redactor ⇒ Object readonly private
- #serializer ⇒ Object readonly private
- #settings ⇒ Object readonly private
- #telemetry ⇒ Object readonly private
Class Method Summary collapse
- .build(settings, agent_settings, logger, telemetry: nil) ⇒ Object private
-
.explicitly_enabled?(settings) ⇒ Boolean
private
True when the customer explicitly set DD_DYNAMIC_INSTRUMENTATION_ENABLED=true (or its equivalent in code).
Instance Method Summary collapse
-
#initialize(settings, agent_settings, logger, code_tracker: nil, telemetry: nil) ⇒ Component
constructor
private
A new instance of Component.
- #parse_probe_spec_and_notify(probe_spec) ⇒ Object private
-
#shutdown!(replacement = nil) ⇒ Object
private
Shuts down dynamic instrumentation permanently.
-
#start! ⇒ void
private
Starts the DI component: begins accepting probes and processing snapshots.
-
#started? ⇒ Boolean
private
Whether the component is currently started.
-
#stop! ⇒ void
private
Stops the DI component: removes all probes and stops background threads.
Constructor Details
#initialize(settings, agent_settings, logger, code_tracker: nil, telemetry: nil) ⇒ Component
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.
Returns a new instance of Component.
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 |
# File 'lib/datadog/di/component.rb', line 68 def initialize(settings, agent_settings, logger, code_tracker: nil, telemetry: nil) @settings = settings @agent_settings = agent_settings logger = DI::Logger.new(settings, logger) @logger = logger @telemetry = telemetry @code_tracker = code_tracker @redactor = Redactor.new(settings) @serializer = Serializer.new(settings, redactor, telemetry: telemetry) @instrumenter = Instrumenter.new(settings, serializer, logger, code_tracker: code_tracker, telemetry: telemetry) @probe_repository = ProbeRepository.new @probe_notification_builder = ProbeNotificationBuilder.new(settings, serializer, logger, telemetry: telemetry) @probe_notifier_worker = ProbeNotifierWorker.new( settings, logger, agent_settings: agent_settings, probe_repository: probe_repository, probe_notification_builder: probe_notification_builder, telemetry: telemetry, ) @probe_manager = ProbeManager.new( settings, instrumenter, probe_notification_builder, probe_notifier_worker, logger, probe_repository, telemetry: telemetry, ) # @started transitions are serialized by @lifecycle_mutex so that # concurrent RC callbacks (which run on the remote-config thread) # cannot race a foreground start! with a background stop!. @lifecycle_mutex = Mutex.new @started = false end |
Instance Attribute Details
#agent_settings ⇒ Object (readonly)
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.
99 100 101 |
# File 'lib/datadog/di/component.rb', line 99 def agent_settings @agent_settings end |
#code_tracker ⇒ Object (readonly)
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.
102 103 104 |
# File 'lib/datadog/di/component.rb', line 102 def code_tracker @code_tracker end |
#instrumenter ⇒ Object (readonly)
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.
103 104 105 |
# File 'lib/datadog/di/component.rb', line 103 def instrumenter @instrumenter end |
#logger ⇒ Object (readonly)
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.
100 101 102 |
# File 'lib/datadog/di/component.rb', line 100 def logger @logger end |
#probe_manager ⇒ Object (readonly)
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.
107 108 109 |
# File 'lib/datadog/di/component.rb', line 107 def probe_manager @probe_manager end |
#probe_notification_builder ⇒ Object (readonly)
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.
106 107 108 |
# File 'lib/datadog/di/component.rb', line 106 def probe_notification_builder @probe_notification_builder end |
#probe_notifier_worker ⇒ Object (readonly)
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.
105 106 107 |
# File 'lib/datadog/di/component.rb', line 105 def probe_notifier_worker @probe_notifier_worker end |
#probe_repository ⇒ Object (readonly)
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.
104 105 106 |
# File 'lib/datadog/di/component.rb', line 104 def probe_repository @probe_repository end |
#redactor ⇒ Object (readonly)
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.
108 109 110 |
# File 'lib/datadog/di/component.rb', line 108 def redactor @redactor end |
#serializer ⇒ Object (readonly)
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.
109 110 111 |
# File 'lib/datadog/di/component.rb', line 109 def serializer @serializer end |
#settings ⇒ Object (readonly)
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.
98 99 100 |
# File 'lib/datadog/di/component.rb', line 98 def settings @settings end |
#telemetry ⇒ Object (readonly)
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.
101 102 103 |
# File 'lib/datadog/di/component.rb', line 101 def telemetry @telemetry end |
Class Method Details
.build(settings, agent_settings, logger, telemetry: nil) ⇒ 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.
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/datadog/di/component.rb', line 19 def build(settings, agent_settings, logger, telemetry: nil) return unless settings.respond_to?(:dynamic_instrumentation) # Explicit DD_DYNAMIC_INSTRUMENTATION_ENABLED=false: do not build the # component at all. This is customer intent, not a failure — log at # debug and emit no telemetry error. Capabilities#register skips the # DI RC block under the same condition, so no enable signal arrives. if Remote.explicitly_disabled?(settings) logger.debug("di: dynamic instrumentation is explicitly disabled (DD_DYNAMIC_INSTRUMENTATION_ENABLED=false); not building component") return end reason = DI.unsupported_reason(settings) if reason # Log level mirrors customer intent: if the customer explicitly # opted in via DD_DYNAMIC_INSTRUMENTATION_ENABLED, warn. Otherwise # debug — with always-build, this path runs on every tracer boot # for every customer, including those who never wanted DI. Spamming # warnings to silent users (especially on JRuby or Ruby 2.5) would # be noise. Customers who later trigger implicit enablement via the # Datadog UI get a symmetric warn from Remote.handle_rc_enablement # when the RC enable signal finds no component to start. level = explicitly_enabled?(settings) ? :warn : :debug logger.public_send(level, "di: dynamic instrumentation is disabled: #{reason}") return end new(settings, agent_settings, logger, code_tracker: DI.code_tracker, telemetry: telemetry).tap do |component| DI.add_current_component(component) end end |
.explicitly_enabled?(settings) ⇒ 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.
True when the customer explicitly set DD_DYNAMIC_INSTRUMENTATION_ENABLED=true (or its equivalent in code). Symmetric to Remote.explicitly_disabled?.
Uses Core::Configuration::Options::InstanceMethods#using_default?
rather than options[:enabled].default_precedence? because the option
hash is populated lazily on first access; reading the underlying option
before build touches the value would NoMethodError on nil.
62 63 64 65 |
# File 'lib/datadog/di/component.rb', line 62 def explicitly_enabled?(settings) !settings.dynamic_instrumentation.using_default?(:enabled) && settings.dynamic_instrumentation.enabled end |
Instance Method Details
#parse_probe_spec_and_notify(probe_spec) ⇒ 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.
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/datadog/di/component.rb', line 195 def parse_probe_spec_and_notify(probe_spec) probe = ProbeBuilder.build_from_remote_config(probe_spec, logger: logger) rescue Exception => exc # standard:disable Lint/RescueException Datadog::DI.reraise_if_fatal(exc) begin probe = Struct.new(:id).new( probe_spec["id"], ) payload = probe_notification_builder.build_errored(probe, exc) probe_notifier_worker.add_status(payload) rescue Exception => nested_exc # standard:disable Lint/RescueException Datadog::DI.reraise_if_fatal(nested_exc) logger.debug { "di: failed to build error notification: #{nested_exc.class}: #{nested_exc.message}" } telemetry&.report(nested_exc, description: "Error building probe error notification") raise end raise else payload = probe_notification_builder.build_received(probe) probe_notifier_worker.add_status(payload, probe: probe) probe end |
#shutdown!(replacement = nil) ⇒ 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.
Shuts down dynamic instrumentation permanently.
Removes all code hooks and stops background threads. Called by Components#shutdown! during component destruction. Unlike #stop!, this is not reversible.
Does not clear out the code tracker, because it's only populated by code when code is compiled and therefore, if the code tracker was replaced by a new instance, the new instance of it wouldn't have any of the already loaded code tracked.
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/datadog/di/component.rb', line 179 def shutdown!(replacement = nil) DI.remove_current_component(self) # Hold the lifecycle mutex so all transitions of @started are # serialized — start! / stop! / shutdown! cannot interleave with # one another. Without the mutex an in-flight stop! from an RC # callback could complete after shutdown!'s probe_manager.close, # producing an inconsistent state. @lifecycle_mutex.synchronize do @started = false probe_manager.clear_hooks probe_manager.close probe_notifier_worker.stop end end |
#start! ⇒ 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.
Starts the DI component: begins accepting probes and processing snapshots.
Starts the probe notifier worker thread before enabling the definition trace point, so any future status emission from a trace-point-driven installation has a worker to drain it. Today ProbeManager#reopen re-hooks without emitting statuses, so the order is defensive rather than load-bearing. No-op if already started. Serialized by @lifecycle_mutex.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/datadog/di/component.rb', line 122 def start! @lifecycle_mutex.synchronize do return if @started # DI.activate_tracking creates the global code tracker lazily. When DI # is enabled after boot via remote configuration (in-product # enablement), this component and its instrumenter were built with a # nil tracker; adopt the now-current global tracker so line probes # can be targeted. @code_tracker = DI.code_tracker instrumenter.code_tracker = @code_tracker probe_notifier_worker.start probe_manager.reopen @started = true end end |
#started? ⇒ 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.
Whether the component is currently started.
Read by remote config dispatch to decide whether to apply probe changes (changes received while stopped are dropped, since the next start! will reconcile from the latest RC state).
165 166 167 |
# File 'lib/datadog/di/component.rb', line 165 def started? @started end |
#stop! ⇒ 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.
Stops the DI component: removes all probes and stops background threads.
The component remains alive and can be restarted with #start!. Does not clear out the code tracker. No-op if already stopped. Serialized by @lifecycle_mutex.
148 149 150 151 152 153 154 155 156 |
# File 'lib/datadog/di/component.rb', line 148 def stop! @lifecycle_mutex.synchronize do return unless @started probe_manager.stop probe_notifier_worker.stop @started = false end end |