Skip to content

chore(py3.15): peripheral compat for profiling, logging, and appsec - #19267

Draft
vlad-scherbich wants to merge 5 commits into
mainfrom
vlad/315-peripheral-compat
Draft

chore(py3.15): peripheral compat for profiling, logging, and appsec#19267
vlad-scherbich wants to merge 5 commits into
mainfrom
vlad/315-peripheral-compat

Conversation

@vlad-scherbich

@vlad-scherbich vlad-scherbich commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

prev: #19724 (on main) | next: #19269

Summary

Peripheral compat for profiling, logging, and appsec on 3.15, plus eject_all_hooks for FunctionStore.restore_all. Import degrade is already on main via #19724 — this PR is the remaining Tier B prep before native work.

Layer This PR
Compiled
Armed peripheral hooks / restore paths
Observable fewer crashes/skips outside wrapping core

Test plan

Tracker

@datadog-prod-us1-5

datadog-prod-us1-5 Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Pipelines  Tests

⚠️ Warnings

🚦 2 Pipeline jobs failed

Changelog | Validate changelog

View in Datadog · View in GitHub Actions

Release note not found during changelog validation.

DataDog/apm-reliability/dd-trace-py | prechecks

View in Datadog · View in GitLab

ℹ️ Info

No other issues found (see more)

🧪 All tests passed
❄️ No new flaky tests detected

🔄 Datadog auto-retried 1 job - 1 passed on retry View in Datadog

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 107d29b | Docs | View more details | Give us feedback!

vlad-scherbich added a commit that referenced this pull request Jul 24, 2026
Update pr-numbers, generate-pr-urls, MANUAL_EXISTING_PRS, and rebuild-stack
to reflect linear stack with peripheral/profiling before packaging (#19254).
Replacement PRs #19267#19275 supersede wrongly-merged #19255#19259.
@vlad-scherbich
vlad-scherbich changed the base branch from vlad/315-ci-autoregen-lockfiles to vlad/ci-fix-smoke-tests-py315 August 21, 2026 04:51
@vlad-scherbich
vlad-scherbich force-pushed the vlad/315-peripheral-compat branch from 32359ee to 9e90c28 Compare August 21, 2026 04:53
vlad-scherbich added a commit that referenced this pull request Aug 21, 2026
Update pr-numbers, generate-pr-urls, MANUAL_EXISTING_PRS, and rebuild-stack
to reflect linear stack with peripheral/profiling before packaging (#19254).
Replacement PRs #19267#19275 supersede wrongly-merged #19255#19259.
@pr-commenter

pr-commenter Bot commented Aug 21, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-08-21 09:11:14

Comparing candidate commit 107d29b in PR branch vlad/315-peripheral-compat with baseline commit 69baea3 in branch main.

📊 Benchmarking dashboard

Found 0 performance improvements and 9 performance regressions! Performance is the same for 609 metrics, 10 unstable metrics.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

scenario:httppropagationextract-empty_headers

  • 🟥 execution_time [+133.166ns; +168.546ns] or [+12.867%; +16.286%]

scenario:httppropagationinject-ids_only

  • 🟥 execution_time [+1.747µs; +1.888µs] or [+9.112%; +9.848%]

scenario:iastaspects-casefold_noaspect

  • 🟥 execution_time [+36.551µs; +48.432µs] or [+14.392%; +19.070%]

scenario:iastaspects-swapcase_aspect

  • 🟥 execution_time [+38.529µs; +49.509µs] or [+13.516%; +17.368%]

scenario:iastaspectsospath-ospathbasename_aspect

  • 🟥 execution_time [+108.992µs; +116.304µs] or [+25.981%; +27.724%]

scenario:iastaspectssplit-rsplit_aspect

  • 🟥 execution_time [+16.065µs; +21.501µs] or [+11.115%; +14.876%]

scenario:span-start

  • 🟥 execution_time [+1.354ms; +1.505ms] or [+9.027%; +10.035%]

scenario:telemetryaddmetric-1-count-metric-1-times

  • 🟥 execution_time [+397.763ns; +435.602ns] or [+15.050%; +16.482%]

scenario:tracer-small

  • 🟥 execution_time [+27.102µs; +29.274µs] or [+8.043%; +8.688%]

Unstable benchmarks

These benchmarks have a confidence interval too wide to call a change; treat them as noise rather than signal.

scenario:coreapiscenario-context_with_data_listeners

  • unstable execution_time [-751.171ns; +722.562ns] or [-6.871%; +6.610%]

scenario:coreapiscenario-core_dispatch_1_listener

  • unstable execution_time [-26.618ns; +39.813ns] or [-4.381%; +6.552%]

scenario:coreapiscenario-core_dispatch_50_listeners

  • unstable execution_time [-1574.213ns; +1734.489ns] or [-9.284%; +10.229%]

scenario:coreapiscenario-core_dispatch_exception_listeners

  • unstable execution_time [-1384.324ns; +1161.027ns] or [-10.356%; +8.686%]

scenario:coreapiscenario-core_dispatch_listeners

  • unstable execution_time [-320.905ns; +326.922ns] or [-8.794%; +8.959%]

scenario:coreapiscenario-core_dispatch_no_args_listeners

  • unstable execution_time [-251.387ns; +250.535ns] or [-8.694%; +8.665%]

scenario:coreapiscenario-core_dispatch_with_results_1_listener

  • unstable execution_time [-71.006ns; +73.611ns] or [-6.266%; +6.495%]

scenario:coreapiscenario-core_dispatch_with_results_50_listeners

  • unstable execution_time [-3961.253ns; +3944.402ns] or [-9.754%; +9.713%]

scenario:coreapiscenario-core_dispatch_with_results_listeners

  • unstable execution_time [-797.136ns; +779.375ns] or [-9.692%; +9.476%]

scenario:packagesupdateimporteddependencies-import_many_stdlib_cached

  • unstable execution_time [-56.863µs; +64.966µs] or [-8.868%; +10.131%]

Base automatically changed from vlad/ci-fix-smoke-tests-py315 to main August 21, 2026 06:01
@vlad-scherbich
vlad-scherbich requested a lite review from Copilot August 21, 2026 07:52
@vlad-scherbich

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9e90c28497

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

Comment thread ddtrace/debugging/_function/store.py

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR is part of the Python 3.15 compatibility/parity effort (#17809), focusing on making import-time behavior degrade gracefully (rather than crashing) for profiling, bytecode wrapping/injection dependents, logging, and AppSec-related instrumentation, with targeted tests and documentation updates.

Changes:

  • Make wrapping/bytecode-injection modules importable on Python 3.15+ while keeping runtime APIs (wrap(), inject_hook(), etc.) raising NotImplementedError when invoked.
  • Add profiling “availability” gating (is_available / failure_msg) so ddtrace.profiling.auto can warn and skip instead of crashing when native extensions are missing.
  • Add/adjust tests and docs for the new degradation behavior; suppress Python 3.15+ logging.__version__ deprecation warnings.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/smoke_test.py Restores environment safely and asserts product plugin loading doesn’t silently fail during WAF smoke test.
tests/profiling/test_profiler.py Adds subprocess test ensuring ddtrace.profiling.auto import degrades when profiling is unavailable.
tests/internal/test_py315_import_degrade.py New tests validating import-time degradation and expected NotImplementedError behavior on 3.15+.
docs/basic_usage.rst Documents profiling availability checks and auto-import warning/skip behavior.
ddtrace/profiling/bootstrap/sitecustomize.py Gates profiler startup on ddtrace.profiling.is_available, warning and returning when unavailable.
ddtrace/profiling/init.py Implements is_available / failure_msg pattern and provides a stub Profiler that raises on construction when unavailable.
ddtrace/internal/wrapping/generators.py Avoids import-time failure on 3.15+ and raises NotImplementedError at runtime for unsupported wrapping.
ddtrace/internal/wrapping/context.py Same degradation pattern for wrapping context on 3.15+.
ddtrace/internal/wrapping/asyncs.py Same degradation pattern for async wrapping on 3.15+.
ddtrace/internal/wrapping/init.py Adds runtime guards so wrap() / wrap_bytecode() raise NotImplementedError on 3.15+.
ddtrace/internal/module.py Adds _exec_lazy_init fallback to support @lazy module initialization without bytecode wrapping on 3.15+.
ddtrace/internal/compat.py Introduces centralized “next unsupported Python” constants/messages used by wrapping/injection code.
ddtrace/internal/bytecode_injection/init.py Avoids import-time failure on 3.15+ and raises NotImplementedError at runtime for injection APIs.
ddtrace/debugging/_function/store.py Adjusts restore logic, but currently introduces a missing API usage/import (see comments).
ddtrace/contrib/internal/logging/patch.py Suppresses Python 3.15+ DeprecationWarning when reading logging.__version__.
ddtrace/appsec/sca/_instrumenter.py Refactors first-instruction-line detection to handle 3.13+/3.15 differences consistently.
Suppressed comments (1)

ddtrace/debugging/_function/store.py:103

  • This Python 3.15+ branch calls eject_all_hooks(function), but bytecode_injection does not provide that API, so this will fail at runtime if reached. Additionally, hook injection is already disabled for Python >= 3.15 (both inject_hook and inject_hooks raise NotImplementedError), so this cleanup block should be unnecessary when restoring functions.
        if PY >= (3, 15):
            functions: list[FunctionType] = list(self._code_map)
            for function in functions:
                eject_all_hooks(function)


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread ddtrace/debugging/_function/store.py
@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Aug 21, 2026

Copy link
Copy Markdown

Codeowners resolved as

Resolved from the full PR diff against main using the target branch CODEOWNERS file.
CODEOWNERS team requests not listed below are not required by the current file set.

ddtrace/appsec/sca/_instrumenter.py                                     @DataDog/asm-python
ddtrace/contrib/internal/logging/patch.py                               @DataDog/apm-core-python @DataDog/apm-idm-python
ddtrace/debugging/_function/store.py                                    @DataDog/debugger-python
ddtrace/internal/bytecode_injection/__init__.py                         @DataDog/apm-core-python
ddtrace/profiling/bootstrap/sitecustomize.py                            @DataDog/profiling-python

@cit-pr-commenter-54b7da

Copy link
Copy Markdown

Circular import analysis

⚠️ Existing circular imports

There are 3 circular imports that already exist on the base branch and have not been changed by this PR.

ddtrace.llmobs -> ddtrace.llmobs._evaluators -> ddtrace.llmobs._evaluators.format -> ddtrace.llmobs._experiment -> ddtrace.llmobs
ddtrace.errortracking._handled_exceptions.bytecode_injector -> ddtrace.errortracking._handled_exceptions.callbacks -> ddtrace.errortracking._handled_exceptions.collector -> ddtrace.errortracking._handled_exceptions.bytecode_reporting -> ddtrace.errortracking._handled_exceptions.bytecode_injector
ddtrace.appsec._asm_request_context -> ddtrace.appsec._iast._iast_request_context_base -> ddtrace.appsec._iast._iast_env -> ddtrace.appsec._iast.reporter -> ddtrace.appsec._exploit_prevention.stack_traces -> ddtrace.appsec._asm_request_context

@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Aug 21, 2026

Copy link
Copy Markdown

Dependency direction analysis

⚠️ Existing dependency direction violations

There are 250 dependency direction violations that already exist on the base branch and have not been changed by this PR.

Show existing violations (showing 5 of 250 highest severity)
ddtrace.internal.tracemethods -×-> ddtrace.trace  (internal-core -> product:tracing, score=135)
ddtrace.llmobs._integrations.bedrock_agents -×-> ddtrace.trace  (product:llmobs -> product:tracing, score=133)
ddtrace.llmobs._integrations.vertexai -×-> ddtrace.trace  (product:llmobs -> product:tracing, score=133)
ddtrace.llmobs._evaluators.runner -×-> ddtrace.trace  (product:llmobs -> product:tracing, score=133)
ddtrace.llmobs._integrations.llama_index -×-> ddtrace.trace  (product:llmobs -> product:tracing, score=133)

To see all violations, download the layers-base.json and layers-pr.json artifacts from this CI job and run:

uv run --script scripts/import-analysis/layers.py compare layers-base.json layers-pr.json

Wheel smoke tests fail on 3.15 because wrapping raises at import and
profiling.auto loads native extensions that are not built yet. Defer
the wrapping error until wrap is actually used, and disable the
profiler when those extensions are missing.
Part of the #17849 split (PR 6/6).

# Conflicts:
#	ddtrace/appsec/sca/_instrumenter.py
#	ddtrace/profiling/__init__.py
#	ddtrace/profiling/bootstrap/sitecustomize.py
# Conflicts:
#	ddtrace/profiling/__init__.py
Add the missing bytecode_injection helper so store.py imports succeed on
all Python versions, and use NEXT_PY_VERSION_INFO for the restore guard.
@vlad-scherbich
vlad-scherbich force-pushed the vlad/315-peripheral-compat branch from 29c8910 to 107d29b Compare August 21, 2026 08:42
vlad-scherbich added a commit that referenced this pull request Aug 21, 2026
Update pr-numbers, generate-pr-urls, MANUAL_EXISTING_PRS, and rebuild-stack
to reflect linear stack with peripheral/profiling before packaging (#19254).
Replacement PRs #19267#19275 supersede wrongly-merged #19255#19259.
@vlad-scherbich vlad-scherbich changed the title fix(py3.15): peripheral compat for profiling, logging, and appsec chore(py3.15): peripheral compat for profiling, logging, and appsec Aug 21, 2026
@vlad-scherbich vlad-scherbich added the changelog/no-changelog A changelog entry is not required for this PR. label Aug 21, 2026
@vlad-scherbich
vlad-scherbich requested a lite review from Copilot August 22, 2026 06:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Comment on lines +255 to +260
def eject_all_hooks(f: FunctionType) -> None:
"""Remove every line hook registered for *f*.

No-op while bytecode injection is unavailable on this Python version.
"""
return None
Comment thread ddtrace/appsec/sca/_instrumenter.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog/no-changelog A changelog entry is not required for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants