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".
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.
Patch Module (ddtrace/contrib/internal/) --> Spans + Tags
Wraps library methods, creates events or spans through the integration's current patternStandard 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.
_datadog_patch guard -- prevents double-patching on repeated patch() callsPin.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() runsget_version() / _supported_versions() -- required exports for version detectionPATCH_MODULES -- registration dict in ddtrace/_monkey.py for patch_all() discoveryINTEGRATION_CONFIGS -- frozenset in ddtrace/internal/settings/_config.py, required for config to workregistry.yaml -- dependency names and tested version range in scripts/integration_registry/registry.yamldd-trace-py uses mypy for type checking. All new integration code must pass the lint skill typing check (scripts/lint typing).
Rules:
patch() -> None, unpatch() -> None, get_version() -> strdef traced_func(wrapped: Callable[..., Any], instance: Any, args: tuple[Any, ...], kwargs: dict[str, Any]) -> Any:Optional[X] for nullable parameters and return valuesdict[str, Any], list[str], tuple[Any, ...] — not bare dict, list, tuple# type: ignore unless absolutely necessary (document the reason inline, e.g. # type: ignore[attr-defined] # wrapt proxy lacks stubs)typing where needed: Any, Callable, OptionalAlways 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.
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.
ddtrace/contrib/internal/{name}/patch.py with patch(), unpatch(), get_version()PATCH_MODULES, scripts/integration_registry/registry.yaml, and INTEGRATION_CONFIGSBaseLLMIntegration in ddtrace/llmobs/_integrations/. See the llmobs-integrations skill's Implementation Guide for full patterns.See Implementation Guide for detailed step-by-step.
DD_TRACE_DEBUG=true to see patching activity and span creation_datadog_patch guard, check PATCH_MODULES entry existsconfig._add() at module levelIf 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.
57aff59
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.