Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: introduce APM_TRACING RC product #11980

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions ddtrace/debugging/_debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,6 @@ def enable(cls) -> None:

di_config.enabled = True

cls.__watchdog__.install()

if di_config.metrics:
metrics.enable()

Expand Down Expand Up @@ -307,7 +305,6 @@ def disable(cls, join: bool = True) -> None:
cls._instance.stop(join=join)
cls._instance = None

cls.__watchdog__.uninstall()
if di_config.metrics:
metrics.disable()

Expand Down
36 changes: 32 additions & 4 deletions ddtrace/debugging/_products/dynamic_instrumentation.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
from ddtrace.internal.core.event_hub import on
from ddtrace.settings.dynamic_instrumentation import config


requires = ["remote-configuration"]


def post_preload():
pass
from ddtrace.debugging._debugger import Debugger

# We need to install this on start-up because if DI gets enabled remotely
# we won't be able to capture many of the code objects from the modules
# that are already loaded.
Debugger.__watchdog__.install()


def _start():
from ddtrace.debugging import DynamicInstrumentation

DynamicInstrumentation.enable()


def start():
if config.enabled:
from ddtrace.debugging import DynamicInstrumentation

DynamicInstrumentation.enable()
_start()


def restart(join=False):
Expand All @@ -29,3 +39,21 @@ def stop(join=False):

def at_exit(join=False):
stop(join=join)


def apm_tracing_rc(lib_config):
enabled = lib_config.get("dynamic_instrumentation_enabled")
try:
if enabled is not None: # and config.spec.enabled.full_name not in config.source:
if (config.spec.enabled.full_name not in config.source or config.enabled) and enabled:
_start()
else:
stop()
except Exception:
from traceback import print_exc

print_exc()
raise


on("apm-tracing.rc", apm_tracing_rc, "dynamic-instrumentation")
Empty file.
31 changes: 31 additions & 0 deletions ddtrace/internal/remoteconfig/products/apm_tracing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from ddtrace import config


requires = ["remote-configuration"]


def post_preload():
pass


def start():
if config._remote_config_enabled:
from ddtrace.internal.remoteconfig.worker import remoteconfig_poller
from ddtrace.settings.remoteconfig import APMTracingAdapter

remoteconfig_poller.register("APM_TRACING", APMTracingAdapter(), restart_on_fork=True)


def restart(join=False):
pass


def stop(join=False):
if config._remote_config_enabled:
from ddtrace.internal.remoteconfig.worker import remoteconfig_poller

remoteconfig_poller.unregister("APM_TRACING")


def at_exit(join=False):
stop(join=join)
40 changes: 40 additions & 0 deletions ddtrace/settings/remoteconfig.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from ddtrace import config
from ddtrace.internal.core.event_hub import dispatch
from ddtrace.internal.logger import get_logger
from ddtrace.internal.remoteconfig._connectors import PublisherSubscriberConnector
from ddtrace.internal.remoteconfig._publishers import RemoteConfigPublisher
from ddtrace.internal.remoteconfig._pubsub import PubSub
from ddtrace.internal.remoteconfig._subscribers import RemoteConfigSubscriber


log = get_logger(__name__)


def _rc_callback(data, test_tracer=None):
for metadata, data in zip(data["metadata"], data["config"]):
if metadata is None or not isinstance(data, dict):
continue

service_target = data.get("service_target")
if service_target is not None:
service = service_target.get("service")
if service is not None and service != config.service:
continue

env = service_target.get("env")
if env is not None and env != config.env:
continue

lib_config = data.get("lib_config")
if lib_config is not None:
dispatch("apm-tracing.rc", (lib_config,))


class APMTracingAdapter(PubSub):
__publisher_class__ = RemoteConfigPublisher
__subscriber_class__ = RemoteConfigSubscriber
__shared_data__ = PublisherSubscriberConnector()

def __init__(self):
self._publisher = self.__publisher_class__(self.__shared_data__)
self._subscriber = self.__subscriber_class__(self.__shared_data__, _rc_callback, "APM_TRACING")
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,11 @@ ddtrace = "ddtrace.contrib.pytest.plugin"
"ddtrace.pytest_benchmark" = "ddtrace.contrib.pytest_benchmark.plugin"

[project.entry-points.'ddtrace.products']
"apm-tracing-rc" = "ddtrace.internal.remoteconfig.products.apm_tracing"
"code-origin-for-spans" = "ddtrace.debugging._products.code_origin.span"
"dynamic-instrumentation" = "ddtrace.debugging._products.dynamic_instrumentation"
"exception-replay" = "ddtrace.debugging._products.exception_replay"
"remote-configuration" = "ddtrace.internal.remoteconfig.product"
"remote-configuration" = "ddtrace.internal.remoteconfig.products.client"
"symbol-database" = "ddtrace.internal.symbol_db.product"

[project.urls]
Expand Down
Loading