# ddtrace for Python: wrap the entry point, dont rewrite the app

The Python tracer needs zero code changes for basic APM. Agents overcomplicate this by editing source files first.

## Setup

```sh
pip install ddtrace
```

Then start the app with the wrapper:

```sh
ddtrace-run python app.py
```

That is it for traces. The wrapper auto-instruments supported frameworks (Django, Flask, FastAPI, Celery, requests, and friends) and ships spans to the agent.

## Config via environment

The tracer reads the usual suspects:

- `DD_SERVICE` : your service name. Set it or the tracer guesses from the module name and your APM becomes a mess of wrong names.
- `DD_ENV` : e.g. prod, staging. Part of unified service tagging.
- `DD_VERSION` : your deploy version. Makes deploy tracking work.
- `DD_AGENT_HOST` / `DD_TRACE_AGENT_URL` : where the trace agent lives. Default assumes the Datadog agent on the same host. In Docker/K8s, point it at the agent.
- `DD_SITE` : set for non-US1 orgs, same trap as the agent.

## Verify

```sh
ddtrace-run --info
```

This prints the effective tracer configuration. The docs warn it does not reflect config changed at runtime in code, so treat it as the startup truth. Then generate traffic and check APM, Services in the app. No service after a minute: the tracer cannot reach the agent (see the trace-agent connection skill) or the site is wrong.

## Traps

- Running the app without the wrapper and wondering why there are no traces. `python app.py` vs `ddtrace-run python app.py` is the whole difference.
- Forgetting `DD_SERVICE` in a repo with many entry points: each gets a guessed name and your service list fills with junk.
- Version pinning: `ddtrace` moves fast. Pin it in requirements like any other dependency or a minor bump changes sampling behavior under you.