refactor(settings): move standalone/APM opt-out logic out of ASMConfig - #19893
refactor(settings): move standalone/APM opt-out logic out of ASMConfig#19893avara1986 wants to merge 4 commits into
Conversation
Standalone (APM opt-out) is not an ASM concept: it turns on whenever AppSec,
IAST, SCA or AI Guard is enabled while APM tracing is off. Aggregating that
decision inside ASMConfig forced a lazy aiguard import and made all ~20 call
sites read as if they were toggling an AppSec setting.
Introduce ddtrace/internal/settings/standalone.py, which now owns:
- DD_APM_TRACING_ENABLED, moved off ASMConfig; its constant moved from
APPSEC.APM_TRACING_ENV to ddtrace.internal.constants.APM_TRACING_ENV
- the aggregated apm_opt_out decision, was ASMConfig._apm_opt_out
LLMObs read DD_APM_TRACING_ENABLED straight from os.environ in two places;
both now use the shared config, so LLMObs and the tracer can no longer
disagree about whether APM tracing is on. Behaviour change: the value is
resolved at import time like every other DD_ setting, so mutating
os.environ after importing ddtrace no longer affects LLMObs.
StandaloneConfig reports itself to configuration telemetry: no product
plugin owns it, and DD_APM_TRACING_ENABLED previously reached telemetry by
riding along with the appsec product's ASMConfig.
In tests, override_global_config routes apm_tracing_enabled (renamed from
_apm_tracing_enabled) to standalone_config.
Jira: https://datadoghq.atlassian.net/browse/APPSEC-69192
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Circular import analysis
|
Dependency direction analysis
|
Codeowners resolved asResolved from the full PR diff against |
🎉 All green!🧪 All tests passed 🔗 Commit SHA: f368e38 | Docs | View more details | Give us feedback! |
BenchmarksBenchmark execution time: 2026-08-28 10:55:02 Comparing candidate commit f368e38 in PR branch Found 0 performance improvements and 6 performance regressions! Performance is the same for 580 metrics, 10 unstable metrics, 3 known flaky benchmarks, 15 flaky benchmarks without significant changes.
|
|
@codex review |
|
Codex Review: Didn't find any major issues. You're on a roll. Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
The llmobs/mistralai py3.10 + mistralai 2.0.5 job fails with two mistralai.request spans where one is expected, only on this branch. Rule out runtime config leakage as the cause: standalone_config.apm_tracing_enabled is mutable at runtime (Tracer.configure(apm_tracing_disabled=...) and override_global_config), unlike the os.environ read it replaced, so a value left behind by an earlier test would now be visible to LLMObs span routing. Reset it around every test in this suite so each one starts from the environment. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
cc08c1e to
650c313
Compare
Description
Jira: APPSEC-69192
Standalone (a.k.a. APM opt-out) is not an ASM concept. It turns on whenever any of AppSec,
IAST, SCA or AI Guard is enabled while APM tracing is off — yet the decision lived on
ASMConfigas_apm_opt_out, which meant:ASMConfighad to lazy-importaiguard_config(with an explanatory comment) purely to avoid animport-time dependency on a package it doesn't own;
read as if they were toggling an AppSec setting.
This PR introduces
ddtrace/internal/settings/standalone.py.StandaloneConfignow owns:DD_APM_TRACING_ENABLED, moved offASMConfig. Its constant moved fromAPPSEC.APM_TRACING_ENVtoddtrace.internal.constants.APM_TRACING_ENV(it had exactly oneconsumer, and nothing iterates the
APPSECconstant class to enumerate env vars).apm_opt_outdecision, previouslyASMConfig._apm_opt_out._apm_opt_outwas removed fromASMConfigoutright rather than left as a delegating property:delegating would have made
asm.pyimportstandalone.py, which importsasm.py. Full migrationalso deletes the lazy
aiguardimport that was the original symptom.propagation/http.py,_trace/pin.py,_trace/processor/__init__.pyandcontrib/internal/requests/connection.pynolonger import
asm_configat all.StandaloneConfigis a realDDConfigsubclass soDD_APM_TRACING_ENABLEDkeeps resolvingthrough fleet/local stable config, not just
os.environ.DD_APM_TRACING_ENABLEDis deliberately still readable/writable at runtime viaTracer.configure(apm_tracing_disabled=...), andapm_opt_outreads every product flag live, soin-process config mutation keeps working exactly as before.
LLMObs de-duplication
LLMObs read
DD_APM_TRACING_ENABLEDstraight fromos.environin two places(
_processor.py,_llmobs.py). Both now use the shared config, so LLMObs and the tracer can nolonger disagree about whether APM tracing is on. See Risks below.
Configuration telemetry
StandaloneConfigreports itself viareport_configuration(). This is not incidental: noproduct plugin owns this config, and
DD_APM_TRACING_ENABLEDpreviously reachedapp-startedconfiguration telemetry by riding along with the
appsecproduct plugin'sASMConfig(
products.pyreports any product module'sconfigattribute). Without the explicit call thekey would silently vanish from config telemetry and break the cross-language config-parity
registry. It is reported from
standalone.pyrather than the explicit list intelemetry/__init__.pybecause the latter creates a cycle(
telemetry→standalone→asm→_config→telemetry).Verified:
Risks
Behaviour change (LLMObs).
DD_APM_TRACING_ENABLEDis now resolved once atddtraceimporttime, like every other
DD_setting. Setting it in the process environment before startup isunaffected — the case that changes is mutating
os.environ["DD_APM_TRACING_ENABLED"]afterimport ddtracebut beforeLLMObs.enable(), which previously took effect and no longer does.LLMObs was the outlier here (the tracer and
ASMConfigalready snapshotted at import), and theold split meant LLMObs could disagree with
tracer.enabledabout whether APM tracing was on.Flagging explicitly because it is the one non-mechanical part of this change.
No public API change.
_apm_opt_outand_apm_tracing_enabledwere both private.