Class: Datadog::Core::Configuration::Components
- Inherits:
-
Object
- Object
- Datadog::Core::Configuration::Components
- Defined in:
- lib/datadog/core/configuration/components.rb
Overview
Global components for the trace library.
Constant Summary collapse
- PATCH_ONLY_ONCE =
Class-level constant to ensure fork patch is applied only once
Utils::OnlyOnce.new
Instance Attribute Summary collapse
-
#agent_info ⇒ Object
readonly
Returns the value of attribute agent_info.
-
#agent_settings ⇒ Object
readonly
Returns the value of attribute agent_settings.
-
#ai_guard ⇒ Object
readonly
Returns the value of attribute ai_guard.
-
#appsec ⇒ Object
readonly
Returns the value of attribute appsec.
-
#crashtracker ⇒ Object
readonly
Returns the value of attribute crashtracker.
-
#data_streams ⇒ Object
readonly
Returns the value of attribute data_streams.
-
#dynamic_instrumentation ⇒ Object
readonly
Returns the value of attribute dynamic_instrumentation.
-
#error_tracking ⇒ Object
readonly
Returns the value of attribute error_tracking.
-
#health_metrics ⇒ Object
readonly
Returns the value of attribute health_metrics.
-
#logger ⇒ Object
readonly
Returns the value of attribute logger.
-
#open_feature ⇒ Object
readonly
Returns the value of attribute open_feature.
-
#profiler ⇒ Object
readonly
Returns the value of attribute profiler.
-
#remote ⇒ Object
readonly
Returns the value of attribute remote.
-
#runtime_metrics ⇒ Object
readonly
Returns the value of attribute runtime_metrics.
-
#settings ⇒ Object
readonly
Returns the value of attribute settings.
-
#symbol_database ⇒ Object
readonly
Returns the value of attribute symbol_database.
-
#telemetry ⇒ Object
readonly
Returns the value of attribute telemetry.
-
#tracer ⇒ Object
readonly
Returns the value of attribute tracer.
Class Method Summary collapse
- .build_crashtracker(settings, agent_settings, logger:) ⇒ Object
- .build_data_streams(settings, agent_settings, logger, agent_info) ⇒ Object
- .build_health_metrics(settings, logger, telemetry) ⇒ Object
- .build_logger(settings) ⇒ Object
- .build_runtime_metrics(settings, logger, telemetry) ⇒ Object
- .build_runtime_metrics_worker(settings, logger, telemetry) ⇒ Object
- .build_telemetry(settings, agent_settings, logger) ⇒ Object
-
.enable_symbol_database?(settings, dynamic_instrumentation) ⇒ Boolean
Decides whether to build the SymbolDatabase component, for the tri-state symbol_database.enabled setting: true/false are explicit overrides; nil (the default) mirrors Dynamic Instrumentation by building whenever DI's component was built.
Instance Method Summary collapse
-
#after_fork ⇒ Object
Called when a fork is detected.
-
#initialize(settings) ⇒ Components
constructor
A new instance of Components.
-
#reconfigure_sampler(settings = Datadog.configuration) ⇒ Object
Hot-swaps with a new sampler.
-
#shutdown!(replacement = nil) ⇒ Object
Shuts down all the components in use.
-
#startup!(settings, old_state: nil) ⇒ Object
Starts up components.
-
#state ⇒ Object
Returns the current state of various components.
Constructor Details
#initialize(settings) ⇒ Components
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
# File 'lib/datadog/core/configuration/components.rb', line 160 def initialize(settings) @settings = settings @logger = self.class.build_logger(settings) @environment_logger_extra = {} StableConfig.log_result(@logger) Deprecations.log_deprecations_from_all_sources(@logger) # Register fork handling once globally self.class::PATCH_ONLY_ONCE.run do Utils::AtForkMonkeyPatch.apply! Utils::SpawnMonkeyPatch.apply!( env_provider: Core::Environment::Identity.method(:runtime_propagation_envs), ) # Register callback that calls Components.after_fork Utils::AtForkMonkeyPatch.at_fork(:child) do # Access via global to avoid capturing 'self' Datadog.send(:components, allow_initialization: false)&.after_fork end end # This agent_settings is intended for use within Core. If you require # agent_settings within a product outside of core you should extend # the Core resolver from within your product/component's namespace. @agent_settings = AgentSettingsResolver.call(settings, logger: @logger) # Exposes agent capability information for detection by any components @agent_info = Core::Environment::AgentInfo.new(agent_settings, logger: @logger) @telemetry = self.class.build_telemetry(settings, agent_settings, @logger) @remote = Remote::Component.build(settings, agent_settings, logger: @logger, telemetry: telemetry) @tracer = Datadog::Tracing::Component.build_tracer(settings, agent_settings, logger: @logger) @crashtracker = self.class.build_crashtracker(settings, agent_settings, logger: @logger) @profiler, profiler_logger_extra = Datadog::Profiling::Component.build_profiler_component( settings: settings, agent_settings: agent_settings, optional_tracer: @tracer, logger: @logger, ) @environment_logger_extra.merge!(profiler_logger_extra) if profiler_logger_extra @runtime_metrics = self.class.build_runtime_metrics_worker(settings, @logger, telemetry) @health_metrics = self.class.build_health_metrics(settings, @logger, telemetry) @appsec = Datadog::AppSec::Component.build_appsec_component(settings, telemetry: telemetry) @ai_guard = Datadog::AIGuard::Component.build(settings, logger: @logger, telemetry: telemetry) @open_feature = OpenFeature::Component.build(settings, agent_settings, logger: @logger, telemetry: telemetry) @dynamic_instrumentation = Datadog::DI::Component.build(settings, agent_settings, @logger, telemetry: telemetry) # Only build symbol database when enabled, so a disabled component is # never constructed. @symbol_database = if self.class.enable_symbol_database?(settings, @dynamic_instrumentation) # di_active is a live predicate, not a snapshot: DI may start after # this component is built (implicit enablement via remote config). # Symbol Database holds only this opaque proc, never a DI reference, # so the two modules stay independent — the orchestration layer # owns the cross-feature knowledge. Datadog::SymbolDatabase::Component.build( settings, agent_settings, @logger, telemetry: telemetry, di_active: -> { dynamic_instrumentation&.started? || false }, ) end @error_tracking = Datadog::ErrorTracking::Component.build(settings, @tracer, @logger) @data_streams = self.class.build_data_streams(settings, agent_settings, @logger, @agent_info) # Reflects "the customer configured DI to be on" — true iff the # component was built AND the env-var-driven enabled flag is set. # This is the post-initialize / pre-startup value visible to tests # that don't call startup!. Production overwrites this in startup! # below with `dynamic_instrumentation&.started?`, which also accounts # for RC-driven enablement carried over via ComponentsState. @environment_logger_extra[:dynamic_instrumentation_enabled] = !!(@dynamic_instrumentation && settings.dynamic_instrumentation.enabled) # Configure non-privileged components. Datadog::Tracing::Contrib::Component.configure(settings) # Load the core Rails Railtie when Rails is present so all products benefit from Rails-specific setup. if defined?(::Rails::Railtie) require_relative "../contrib/rails/railtie" end end |
Instance Attribute Details
#agent_info ⇒ Object (readonly)
Returns the value of attribute agent_info.
140 141 142 |
# File 'lib/datadog/core/configuration/components.rb', line 140 def agent_info @agent_info end |
#agent_settings ⇒ Object (readonly)
Returns the value of attribute agent_settings.
140 141 142 |
# File 'lib/datadog/core/configuration/components.rb', line 140 def agent_settings @agent_settings end |
#ai_guard ⇒ Object (readonly)
Returns the value of attribute ai_guard.
140 141 142 |
# File 'lib/datadog/core/configuration/components.rb', line 140 def ai_guard @ai_guard end |
#appsec ⇒ Object (readonly)
Returns the value of attribute appsec.
140 141 142 |
# File 'lib/datadog/core/configuration/components.rb', line 140 def appsec @appsec end |
#crashtracker ⇒ Object (readonly)
Returns the value of attribute crashtracker.
140 141 142 |
# File 'lib/datadog/core/configuration/components.rb', line 140 def crashtracker @crashtracker end |
#data_streams ⇒ Object (readonly)
Returns the value of attribute data_streams.
140 141 142 |
# File 'lib/datadog/core/configuration/components.rb', line 140 def data_streams @data_streams end |
#dynamic_instrumentation ⇒ Object (readonly)
Returns the value of attribute dynamic_instrumentation.
140 141 142 |
# File 'lib/datadog/core/configuration/components.rb', line 140 def dynamic_instrumentation @dynamic_instrumentation end |
#error_tracking ⇒ Object (readonly)
Returns the value of attribute error_tracking.
140 141 142 |
# File 'lib/datadog/core/configuration/components.rb', line 140 def error_tracking @error_tracking end |
#health_metrics ⇒ Object (readonly)
Returns the value of attribute health_metrics.
140 141 142 |
# File 'lib/datadog/core/configuration/components.rb', line 140 def health_metrics @health_metrics end |
#logger ⇒ Object (readonly)
Returns the value of attribute logger.
140 141 142 |
# File 'lib/datadog/core/configuration/components.rb', line 140 def logger @logger end |
#open_feature ⇒ Object (readonly)
Returns the value of attribute open_feature.
140 141 142 |
# File 'lib/datadog/core/configuration/components.rb', line 140 def open_feature @open_feature end |
#profiler ⇒ Object (readonly)
Returns the value of attribute profiler.
140 141 142 |
# File 'lib/datadog/core/configuration/components.rb', line 140 def profiler @profiler end |
#remote ⇒ Object (readonly)
Returns the value of attribute remote.
140 141 142 |
# File 'lib/datadog/core/configuration/components.rb', line 140 def remote @remote end |
#runtime_metrics ⇒ Object (readonly)
Returns the value of attribute runtime_metrics.
140 141 142 |
# File 'lib/datadog/core/configuration/components.rb', line 140 def runtime_metrics @runtime_metrics end |
#settings ⇒ Object (readonly)
Returns the value of attribute settings.
140 141 142 |
# File 'lib/datadog/core/configuration/components.rb', line 140 def settings @settings end |
#symbol_database ⇒ Object (readonly)
Returns the value of attribute symbol_database.
140 141 142 |
# File 'lib/datadog/core/configuration/components.rb', line 140 def symbol_database @symbol_database end |
#telemetry ⇒ Object (readonly)
Returns the value of attribute telemetry.
140 141 142 |
# File 'lib/datadog/core/configuration/components.rb', line 140 def telemetry @telemetry end |
#tracer ⇒ Object (readonly)
Returns the value of attribute tracer.
140 141 142 |
# File 'lib/datadog/core/configuration/components.rb', line 140 def tracer @tracer end |
Class Method Details
.build_crashtracker(settings, agent_settings, logger:) ⇒ Object
113 114 115 116 117 118 119 120 121 122 |
# File 'lib/datadog/core/configuration/components.rb', line 113 def build_crashtracker(settings, agent_settings, logger:) return unless settings.crashtracking.enabled if (libdatadog_api_failure = Datadog::Core::LIBDATADOG_API_FAILURE) logger.debug("Cannot enable crashtracking: #{libdatadog_api_failure}") return end Datadog::Core::Crashtracking::Component.build(settings, agent_settings, logger: logger) end |
.build_data_streams(settings, agent_settings, logger, agent_info) ⇒ Object
124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/datadog/core/configuration/components.rb', line 124 def build_data_streams(settings, agent_settings, logger, agent_info) return unless settings.data_streams.enabled Datadog::DataStreams::Processor.new( interval: settings.data_streams.interval, logger: logger, settings: settings, agent_settings: agent_settings, agent_info: agent_info ) rescue => e logger.warn("Failed to initialize Data Streams Monitoring: #{e.class}: #{e.message}") nil end |
.build_health_metrics(settings, logger, telemetry) ⇒ Object
41 42 43 44 45 46 47 |
# File 'lib/datadog/core/configuration/components.rb', line 41 def build_health_metrics(settings, logger, telemetry) settings = settings.health_metrics = {enabled: settings.enabled} [:statsd] = settings.statsd unless settings.statsd.nil? Core::Diagnostics::Health::Metrics.new(telemetry: telemetry, logger: logger, **) end |
.build_logger(settings) ⇒ Object
81 82 83 84 85 86 |
# File 'lib/datadog/core/configuration/components.rb', line 81 def build_logger(settings) logger = settings.logger.instance || Core::Logger.new($stderr) logger.level = settings.diagnostics.debug ? ::Logger::DEBUG : settings.logger.level logger end |
.build_runtime_metrics(settings, logger, telemetry) ⇒ Object
88 89 90 91 92 93 94 95 96 |
# File 'lib/datadog/core/configuration/components.rb', line 88 def build_runtime_metrics(settings, logger, telemetry) = {enabled: settings.runtime_metrics.enabled} [:statsd] = settings.runtime_metrics.statsd unless settings.runtime_metrics.statsd.nil? [:services] = [settings.service] unless settings.service.nil? [:experimental_runtime_id_enabled] = settings.runtime_metrics.experimental_runtime_id_enabled [:experimental_propagate_process_tags_enabled] = settings. Core::Runtime::Metrics.new(logger: logger, telemetry: telemetry, **) end |
.build_runtime_metrics_worker(settings, logger, telemetry) ⇒ Object
98 99 100 101 102 103 104 105 106 107 |
# File 'lib/datadog/core/configuration/components.rb', line 98 def build_runtime_metrics_worker(settings, logger, telemetry) # NOTE: Should we just ignore building the worker if its not enabled? = settings.runtime_metrics.opts.merge( enabled: settings.runtime_metrics.enabled, metrics: build_runtime_metrics(settings, logger, telemetry), logger: logger, ) Core::Workers::RuntimeMetrics.new(telemetry: telemetry, **) end |
.build_telemetry(settings, agent_settings, logger) ⇒ Object
109 110 111 |
# File 'lib/datadog/core/configuration/components.rb', line 109 def build_telemetry(settings, agent_settings, logger) Telemetry::Component.build(settings, agent_settings, logger) end |
.enable_symbol_database?(settings, dynamic_instrumentation) ⇒ Boolean
Decides whether to build the SymbolDatabase component, for the tri-state symbol_database.enabled setting: true/false are explicit overrides; nil (the default) mirrors Dynamic Instrumentation by building whenever DI's component was built. dynamic_instrumentation is DI's build result — nil only when DI is explicitly disabled or the runtime can't support it (Rails development mode, missing C extension, remote config off, non-MRI). Under the always-build model it is non-nil even when the DI setting defaults to off, so a built SymbolDatabase component is inert until an upload is actually permitted: the component's own gate (see Component#upload_allowed?) only extracts and uploads when DI is truly active or the customer opted in explicitly. This mirrors DI advertising/building a component by default while installing no probes until it is enabled. force_upload (internal/testing) always builds, since it uploads regardless of DI or the enabled setting.
67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/datadog/core/configuration/components.rb', line 67 def enable_symbol_database?(settings, dynamic_instrumentation) # The symbol_database settings group is only registered on the full # library load path; a partial load (e.g. require 'datadog/di') leaves # it absent, in which case the feature cannot be enabled. return false unless settings.respond_to?(:symbol_database) # force_upload uploads unconditionally, so the component must be built # even when the setting is nil and DI's component was not built. return true if settings.symbol_database.internal.force_upload # nil (the default) follows whether DI's component was built. Datadog::SymbolDatabase.resolve_enabled(settings.symbol_database.enabled, !dynamic_instrumentation.nil?) end |
Instance Method Details
#after_fork ⇒ Object
Called when a fork is detected
245 246 247 248 249 250 251 252 |
# File 'lib/datadog/core/configuration/components.rb', line 245 def after_fork telemetry.after_fork remote&.after_fork crashtracker&.update_on_fork ProcessDiscovery.after_fork symbol_database&.after_fork! data_streams&.restart_flush_thread end |
#reconfigure_sampler(settings = Datadog.configuration) ⇒ Object
Hot-swaps with a new sampler. This operation acquires the Components lock to ensure there is no concurrent modification of the sampler.
257 258 259 260 |
# File 'lib/datadog/core/configuration/components.rb', line 257 def reconfigure_sampler(settings = Datadog.configuration) sampler = Datadog::Tracing::Component.build_sampler(settings) Datadog.send(:safely_synchronize) { tracer.sampler.sampler = sampler } end |
#shutdown!(replacement = nil) ⇒ Object
Shuts down all the components in use. If it has another instance to compare to, it will compare and avoid tearing down parts still in use.
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 |
# File 'lib/datadog/core/configuration/components.rb', line 314 def shutdown!(replacement = nil) # Shutdown remote configuration remote&.shutdown! # Shutdown DI after remote, since remote config triggers DI operations. dynamic_instrumentation&.shutdown! # Shutdown Symbol Database symbol_database&.shutdown! # Shutdown OpenFeature component open_feature&.shutdown! # Decommission AppSec appsec&.shutdown! # Shutdown AIGuard component ai_guard&.shutdown! # Shutdown the old tracer, unless it's still being used. # (e.g. a custom tracer instance passed in.) tracer.shutdown! unless replacement && tracer.equal?(replacement.tracer) # Shutdown old profiler profiler&.shutdown! # Shutdown workers runtime_metrics.stop(true, close_metrics: false) # Shutdown Data Streams Monitoring processor data_streams&.stop(true) # Shutdown the old metrics, unless they are still being used. # (e.g. custom Statsd instances.) # # TODO: This violates the encapsulation created by Runtime::Metrics and # Health::Metrics, by directly manipulating `statsd` and changing # it's lifecycle management. # If we need to directly have ownership of `statsd` lifecycle, we should # have direct ownership of it. old_statsd = [ runtime_metrics.metrics.statsd, health_metrics.statsd, ].compact.uniq new_statsd = if replacement [ replacement.runtime_metrics.metrics.statsd, replacement.health_metrics.statsd, ].compact.uniq else [] end unused_statsd = (old_statsd - (old_statsd & new_statsd)) unused_statsd.each(&:close) Core::ProcessDiscovery.shutdown! # Shut down telemetry last so that all other components may # report shutdown errors. # # Enqueue closing event before stopping telemetry so it will be # sent out on shutdown. telemetry.emit_closing! unless replacement&.telemetry&.enabled telemetry.shutdown! end |
#startup!(settings, old_state: nil) ⇒ Object
Starts up components
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
# File 'lib/datadog/core/configuration/components.rb', line 263 def startup!(settings, old_state: nil) telemetry.start(old_state&.telemetry_enabled?, components: self) if settings.profiling.enabled if profiler profiler.start else # Display a warning for users who expected profiling to be enabled unsupported_reason = Profiling.unsupported_reason logger.warn("Profiling was requested but is not supported, profiling disabled: #{unsupported_reason}") end end if remote && old_state&.remote_started? # The library was reconfigured and previously it already started # the remote component (i.e., it received at least one request # through the installed Rack middleware which started the remote). # If the new configuration also has remote enabled, start the # new remote right away. remote.start end # Start DI component if enabled by env var or if it was implicitly enabled # (via RC) in the previous Components instance. dynamic_instrumentation is # non-nil only when Component.build's preconditions passed (Ruby 2.6+ MRI, # etc.), which is exactly the condition under which di/base.rb is loaded # and DI.activate_tracking is defined. if dynamic_instrumentation if settings.dynamic_instrumentation.enabled || old_state&.di_implicitly_enabled? DI.activate_tracking dynamic_instrumentation.start! remote&.add_products( *Datadog::DI::Remote.products, *Datadog::SymbolDatabase::Remote.deferred_products(settings), ) end end # This should stay here, not in initialize. During reconfiguration, the order of the calls is: # initialize new components, shutdown old components, startup new components. # Because this is a singleton, if we call it in initialize, it will be shutdown right away. Core::ProcessDiscovery.publish(settings) @environment_logger_extra[:dynamic_instrumentation_enabled] = dynamic_instrumentation&.started? || false Core::Diagnostics::EnvironmentLogger.collect_and_log!(@environment_logger_extra) end |
#state ⇒ Object
Returns the current state of various components.
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 |
# File 'lib/datadog/core/configuration/components.rb', line 383 def state # di_implicitly_enabled distinguishes RC-driven start from explicit # start (env var or programmatic) so that an explicit # `enabled = false` on reconfiguration can take effect. # # using_default? — not `!enabled` — because Datadog.configure has # already mutated the singleton settings by the time #state runs, # so `!enabled` would treat a customer's explicit # `enabled = false` as "implicitly enabled" and restart DI. # using_default? asks "did the customer ever touch this setting", # which is the right question for RC carry-over. di_implicit = dynamic_instrumentation&.started? && @settings.dynamic_instrumentation.using_default?(:enabled) ComponentsState.new( telemetry_enabled: telemetry.enabled, remote_started: remote&.started?, di_implicitly_enabled: di_implicit || false, ) end |