dd-trace-py APM Integrations
dd-trace-py provides automatic tracing for 90+ third-party libraries. Each integration uses monkey-patching via wrapt to intercept library calls and create spans.
Architecture
Patch Module (ddtrace/contrib/internal/) --> Spans + Tags
Wraps library methods, creates events or spans through the integration's current pattern
Standard integrations use one of these patterns:
context_with_data() + trace_handlers.py (preferred for existing): Wrappers emit events via core.context_with_data(), listeners in trace_handlers.py create spans (e.g., botocore, flask, django).
context_with_event() + TracingEvent (NEW — preferred for new integrations): Typed event-driven pattern using core.context_with_event() with TracingEvent subclasses and TracingSubscriber. Read concrete examples such as ddtrace/contrib/internal/httpx/patch.py and ddtrace/contrib/internal/aiohttp/patch.py, plus infrastructure in ddtrace/_trace/events.py and ddtrace/_trace/subscribers/.
Pin + tracer.trace() (DEPRECATED — do not use in new integrations): Many existing integrations use Pin.get_from() + tracer.trace() (e.g., redis, kafka, grpc). Do NOT use Pin in new code.
LLM integrations still use the APM integration workflow for contrib module layout, patch registration, and APM span tests, but LLMObs-specific span lifecycle and extraction belong in the llmobs-integrations skill.
Key Concepts
_datadog_patch guard -- prevents double-patching on repeated patch() calls
- Pin is DEPRECATED -- many existing integrations still use
Pin.get_from() and Pin().onto(), but do NOT use Pin in new integrations. Prefer context_with_event (new) or context_with_data (existing)
config._add() -- registers integration config at module level, before patch() runs
get_version() / _supported_versions() -- required exports for version detection
PATCH_MODULES -- registration dict in ddtrace/_monkey.py for patch_all() discovery
INTEGRATION_CONFIGS -- frozenset in ddtrace/internal/settings/_config.py, required for config to work
registry.yaml -- dependency names and tested version range in scripts/integration_registry/registry.yaml
Type Annotations
dd-trace-py uses mypy for type checking. All new integration code must pass the lint skill typing check (scripts/lint typing).
Rules:
- Every function and method must have full type annotations (parameters + return type)
patch() -> None, unpatch() -> None, get_version() -> str
- Wrapper functions use the wrapt signature:
def traced_func(wrapped: Callable[..., Any], instance: Any, args: tuple[Any, ...], kwargs: dict[str, Any]) -> Any:
- Use
Optional[X] for nullable parameters and return values
- Use parameterized generics:
dict[str, Any], list[str], tuple[Any, ...] — not bare dict, list, tuple
- Avoid
# type: ignore unless absolutely necessary (document the reason inline, e.g. # type: ignore[attr-defined] # wrapt proxy lacks stubs)
- Import types from
typing where needed: Any, Callable, Optional
- Read reference integrations for correct type patterns — match their style
Reference Integrations
Always read 1-2 references of the same type before writing or modifying code.
All patch modules live in ddtrace/contrib/internal/{name}/. See
Reference Integrations for canonical
examples, secondary references, and pattern notes.
LLM Integrations (LLMObs)
Use this APM skill for the shared integration work: contrib package layout,
patch() / unpatch(), registration in PATCH_MODULES,
scripts/integration_registry/registry.yaml, config registration, APM span
tests, suitespec plumbing, and release-note/documentation expectations.
Use the llmobs-integrations skill for LLM-specific patch patterns,
LlmRequestEvent, stream handlers, message/tool/token extraction, metadata
sanitization, LLMObs assertions, and VCR cassette setup.
Implementation Workflow
- Investigate -- Read 1-2 reference integrations of the same type (see tables above)
- Create patch module --
ddtrace/contrib/internal/{name}/patch.py with patch(), unpatch(), get_version()
- Register -- Add to
PATCH_MODULES, scripts/integration_registry/registry.yaml, and INTEGRATION_CONFIGS
- LLM only: Create integration class -- Subclass
BaseLLMIntegration in ddtrace/llmobs/_integrations/. See the llmobs-integrations skill's Implementation Guide for full patterns.
- Write tests -- Add a
Venv() to riotfile.py, suitespec entries, and test files
- Run tests -- Use the run-tests skill
- Lint -- Use the lint skill
See Implementation Guide for detailed step-by-step.
Debugging
DD_TRACE_DEBUG=true to see patching activity and span creation
- Missing spans -- verify
_datadog_patch guard, check PATCH_MODULES entry exists
- Wrong service name -- verify
config._add() at module level
- LLM-specific: see the llmobs-integrations skill for failure modes and debugging
Native Extension Build Issues
If pip install -e . fails with Rust compilation errors, target3.1* path errors, or stale cached artifacts causing builds to break, refer to
Troubleshooting
This clears the Rust target directory and pip's download/build caches. Run this before retrying any pip install that fails with native extension errors.
Reference Files
- Implementation Guide -- Step-by-step new integration (all types)
- Reference Integrations -- All 13 categories with canonical examples
- Design Decisions -- Why integrations are structured this way
- Anti-Patterns -- Silent failures and common gotchas
1---2name: apm-integrations3description: dd-trace-py integration development guide. Use when creating, modifying, or debugging contrib integrations in the Python tracer. Covers the patch module system, context_with_data, context_with_event (new), registration, testing through the repository test runner, and common anti-patterns. LLM/AI integrations should use this skill for APM-side workflow only; use llmobs-integrations for LLMObs-specific lifecycle, extraction, streaming, and VCR guidance. Pin is DEPRECATED. Triggers: "dd-trace-py", "ddtrace", "contrib", "integration", "patch.py", "trace_handlers", "PATCH_MODULES", "context_with_data", "context_with_event", "TracingEvent", "VCR", "cassette", "generative-ai", "LLM integration", "run-tests", "suitespec", "new integration", "wrap", "unwrap".4---56# dd-trace-py APM Integrations78dd-trace-py provides automatic tracing for 90+ third-party libraries. Each integration uses monkey-patching via `wrapt` to intercept library calls and create spans.910## Architecture1112```13Patch Module (ddtrace/contrib/internal/) --> Spans + Tags14 Wraps library methods, creates events or spans through the integration's current pattern15```1617**Standard integrations** use one of these patterns:18- **`context_with_data()` + `trace_handlers.py`** (preferred for existing): Wrappers emit events via `core.context_with_data()`, listeners in `trace_handlers.py` create spans (e.g., botocore, flask, django).19- **`context_with_event()` + `TracingEvent`** (NEW — preferred for new integrations): Typed event-driven pattern using `core.context_with_event()` with `TracingEvent` subclasses and `TracingSubscriber`. Read concrete examples such as `ddtrace/contrib/internal/httpx/patch.py` and `ddtrace/contrib/internal/aiohttp/patch.py`, plus infrastructure in `ddtrace/_trace/events.py` and `ddtrace/_trace/subscribers/`.20- **`Pin` + `tracer.trace()`** (DEPRECATED — do not use in new integrations): Many existing integrations use `Pin.get_from()` + `tracer.trace()` (e.g., redis, kafka, grpc). Do NOT use Pin in new code.2122**LLM integrations** still use the APM integration workflow for contrib module layout, patch registration, and APM span tests, but LLMObs-specific span lifecycle and extraction belong in the `llmobs-integrations` skill.2324## Key Concepts2526- **`_datadog_patch` guard** -- prevents double-patching on repeated `patch()` calls27- **Pin is DEPRECATED** -- many existing integrations still use `Pin.get_from()` and `Pin().onto()`, but do NOT use Pin in new integrations. Prefer `context_with_event` (new) or `context_with_data` (existing)28- **`config._add()`** -- registers integration config at module level, before `patch()` runs29- **`get_version()` / `_supported_versions()`** -- required exports for version detection30- **`PATCH_MODULES`** -- registration dict in `ddtrace/_monkey.py` for `patch_all()` discovery31- **`INTEGRATION_CONFIGS`** -- frozenset in `ddtrace/internal/settings/_config.py`, required for config to work32- **`registry.yaml`** -- dependency names and tested version range in `scripts/integration_registry/registry.yaml`3334## Type Annotations3536dd-trace-py uses mypy for type checking. All new integration code must pass the **lint** skill typing check (`scripts/lint typing`).3738**Rules:**39- Every function and method must have full type annotations (parameters + return type)40- `patch() -> None`, `unpatch() -> None`, `get_version() -> str`41- Wrapper functions use the wrapt signature: `def traced_func(wrapped: Callable[..., Any], instance: Any, args: tuple[Any, ...], kwargs: dict[str, Any]) -> Any:`42- Use `Optional[X]` for nullable parameters and return values43- Use parameterized generics: `dict[str, Any]`, `list[str]`, `tuple[Any, ...]` — not bare `dict`, `list`, `tuple`44- Avoid `# type: ignore` unless absolutely necessary (document the reason inline, e.g. `# type: ignore[attr-defined] # wrapt proxy lacks stubs`)45- Import types from `typing` where needed: `Any`, `Callable`, `Optional`46- Read reference integrations for correct type patterns — match their style4748## Reference Integrations4950**Always read 1-2 references of the same type before writing or modifying code.**5152All patch modules live in `ddtrace/contrib/internal/{name}/`. See53[Reference Integrations](references/reference-integrations.md) for canonical54examples, secondary references, and pattern notes.5556---5758## LLM Integrations (LLMObs)5960Use this APM skill for the shared integration work: contrib package layout,61`patch()` / `unpatch()`, registration in `PATCH_MODULES`,62`scripts/integration_registry/registry.yaml`, config registration, APM span63tests, suitespec plumbing, and release-note/documentation expectations.6465Use the **llmobs-integrations** skill for LLM-specific patch patterns,66`LlmRequestEvent`, stream handlers, message/tool/token extraction, metadata67sanitization, LLMObs assertions, and VCR cassette setup.6869---7071## Implementation Workflow72731. **Investigate** -- Read 1-2 reference integrations of the same type (see tables above)742. **Create patch module** -- `ddtrace/contrib/internal/{name}/patch.py` with `patch()`, `unpatch()`, `get_version()`753. **Register** -- Add to `PATCH_MODULES`, `scripts/integration_registry/registry.yaml`, and `INTEGRATION_CONFIGS`764. **LLM only: Create integration class** -- Subclass `BaseLLMIntegration` in `ddtrace/llmobs/_integrations/`. See the **llmobs-integrations** skill's [Implementation Guide](../llmobs-integrations/references/implementation-guide.md) for full patterns.775. **Write tests** -- Add a `Venv()` to `riotfile.py`, suitespec entries, and test files786. **Run tests** -- Use the **run-tests** skill797. **Lint** -- Use the **lint** skill8081See [Implementation Guide](references/implementation-guide.md) for detailed step-by-step.8283## Debugging8485- `DD_TRACE_DEBUG=true` to see patching activity and span creation86- Missing spans -- verify `_datadog_patch` guard, check `PATCH_MODULES` entry exists87- Wrong service name -- verify `config._add()` at module level88- **LLM-specific**: see the **llmobs-integrations** skill for failure modes and debugging8990### Native Extension Build Issues9192If `pip install -e .` fails with Rust compilation errors, `target3.1*` path errors, or stale cached artifacts causing builds to break, refer to93[Troubleshooting](../../../docs/troubleshooting.rst)9495This clears the Rust target directory and pip's download/build caches. Run this before retrying any `pip install` that fails with native extension errors.9697## Reference Files9899- [Implementation Guide](references/implementation-guide.md) -- Step-by-step new integration (all types)100- [Reference Integrations](references/reference-integrations.md) -- All 13 categories with canonical examples101- [Design Decisions](references/design-decisions.md) -- Why integrations are structured this way102- [Anti-Patterns](references/anti-patterns.md) -- Silent failures and common gotchas