-
Notifications
You must be signed in to change notification settings - Fork 375
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
DEBUG-2334 dynamic instrumentation probe manager + instrumentation in…
…tegration tests (#4097) - Adds a probe manager class whose function is to maintain the list of probes received from remote config and their state (pending/instrumented/failed). - Probe manager drives Instrumenter (already in master) to perform instrumentation. - Probe manager keeps track of when instrumentation fails for reasons other than the target is not yet loaded, adds such probes to the list of failed probes and does not attempt to instrument them again. - Integration tests for instrumentation of the supported cases (method/line probes, basic/enriched, target is loaded/is loaded later) are included and comprise majority of the diff - DI Component is also part of this PR, it is needed to link Code Tracker and globally installed trace points for code loading and class definition to Probe Manager to install the pending probes
- Loading branch information
Showing
23 changed files
with
1,533 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
# frozen_string_literal: true | ||
|
||
module Datadog | ||
module DI | ||
# 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. | ||
class Component | ||
class << self | ||
def build(settings, agent_settings, telemetry: nil) | ||
return unless settings.respond_to?(:dynamic_instrumentation) && settings.dynamic_instrumentation.enabled | ||
|
||
unless settings.respond_to?(:remote) && settings.remote.enabled | ||
Datadog.logger.debug("Dynamic Instrumentation could not be enabled because Remote Configuration Management is not available. To enable Remote Configuration, see https://docs.datadoghq.com/agent/remote_config") | ||
return | ||
end | ||
|
||
return unless environment_supported?(settings) | ||
|
||
new(settings, agent_settings, Datadog.logger, code_tracker: DI.code_tracker, telemetry: telemetry) | ||
end | ||
|
||
def build!(settings, agent_settings, telemetry: nil) | ||
unless settings.respond_to?(:dynamic_instrumentation) && settings.dynamic_instrumentation.enabled | ||
raise "Requested DI component but DI is not enabled in settings" | ||
end | ||
|
||
unless settings.respond_to?(:remote) && settings.remote.enabled | ||
raise "Requested DI component but remote config is not enabled in settings" | ||
end | ||
|
||
unless environment_supported?(settings) | ||
raise "DI does not support the environment (development or Ruby version too low or not MRI)" | ||
end | ||
|
||
new(settings, agent_settings, Datadog.logger, code_tracker: DI.code_tracker, telemetry: telemetry) | ||
end | ||
|
||
# Checks whether the runtime environment is supported by | ||
# dynamic instrumentation. Currently we only require that, if Rails | ||
# is used, that Rails environment is not development because | ||
# DI does not currently support code unloading and reloading. | ||
def environment_supported?(settings) | ||
# TODO add tests? | ||
unless settings.dynamic_instrumentation.internal.development | ||
if Datadog::Core::Environment::Execution.development? | ||
Datadog.logger.debug("Not enabling dynamic instrumentation because we are in development environment") | ||
return false | ||
end | ||
end | ||
if RUBY_ENGINE != 'ruby' || RUBY_VERSION < '2.6' | ||
Datadog.logger.debug("Not enabling dynamic instrumentation because of unsupported Ruby version") | ||
return false | ||
end | ||
true | ||
end | ||
end | ||
|
||
def initialize(settings, agent_settings, logger, code_tracker: nil, telemetry: nil) | ||
@settings = settings | ||
@agent_settings = agent_settings | ||
@logger = logger | ||
@telemetry = telemetry | ||
@redactor = Redactor.new(settings) | ||
@serializer = Serializer.new(settings, redactor, telemetry: telemetry) | ||
@instrumenter = Instrumenter.new(settings, serializer, logger, code_tracker: code_tracker, telemetry: telemetry) | ||
@transport = Transport.new(agent_settings) | ||
@probe_notifier_worker = ProbeNotifierWorker.new(settings, transport, logger, telemetry: telemetry) | ||
@probe_notification_builder = ProbeNotificationBuilder.new(settings, serializer) | ||
@probe_manager = ProbeManager.new(settings, instrumenter, probe_notification_builder, probe_notifier_worker, logger, telemetry: telemetry) | ||
probe_notifier_worker.start | ||
end | ||
|
||
attr_reader :settings | ||
attr_reader :agent_settings | ||
attr_reader :logger | ||
attr_reader :telemetry | ||
attr_reader :instrumenter | ||
attr_reader :transport | ||
attr_reader :probe_notifier_worker | ||
attr_reader :probe_notification_builder | ||
attr_reader :probe_manager | ||
attr_reader :redactor | ||
attr_reader :serializer | ||
|
||
# Shuts down dynamic instrumentation. | ||
# | ||
# Removes all code hooks and stops background threads. | ||
# | ||
# 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. | ||
def shutdown!(replacement = nil) | ||
probe_manager.clear_hooks | ||
probe_manager.close | ||
probe_notifier_worker.stop | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.