Instrument Django with OpenTelemetry
Send traces, logs and metrics from a Django app to Telemetry Machine with OpenTelemetry's zero-code Python instrumentation. No code changes.
OpenTelemetry's zero-code Python instrumentation traces every request and database query, sends your logging records as logs, and records HTTP metrics. Your code doesn't change.
Create the datasets
Each signal goes to its own dataset. Create three, and an ingest key that can write to all of them, with tm-cli or the MCP server:
$ tm-cli datasets create --name shop-prod-traces --type traces
$ tm-cli datasets create --name shop-prod-logs --type logs
$ tm-cli datasets create --name shop-prod-metrics --type metrics
$ tm-cli api-keys create --name shop-api --dataset shop-prod-traces --dataset shop-prod-logs --dataset shop-prod-metricscreate_dataset { "name": "shop-prod-traces", "signal_type": "traces" }
create_dataset { "name": "shop-prod-logs", "signal_type": "logs" }
create_dataset { "name": "shop-prod-metrics", "signal_type": "metrics" }
create_ingest_key {
"name": "shop-api",
"datasets": ["shop-prod-traces", "shop-prod-logs", "shop-prod-metrics"]
}tm-cli shows the key once, in api_key.api_key. Over MCP, your agent gets it once and saves it in your app's configuration. In the app, create each dataset, then a key for all three under API keys in your organization's settings.
Install
In your app's virtual environment, after your app's own packages:
$ pip install opentelemetry-distro opentelemetry-exporter-otlp-proto-http
$ opentelemetry-bootstrap -a installopentelemetry-bootstrap installs the instrumentation for each library it finds, such as Django, logging and sqlite3.
Configure
Set DJANGO_SETTINGS_MODULE to your project's settings, as well as the exporter:
export DJANGO_SETTINGS_MODULE=mysite.settings
export TM_INGEST_KEY='<ingest-key>'
export OTEL_SERVICE_NAME=shop-api
export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.telemetrymachine.com
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_TRACES_HEADERS="X-API-Key=$TM_INGEST_KEY,X-Dataset-Name=shop-prod-traces"
export OTEL_EXPORTER_OTLP_LOGS_HEADERS="X-API-Key=$TM_INGEST_KEY,X-Dataset-Name=shop-prod-logs"
export OTEL_EXPORTER_OTLP_METRICS_HEADERS="X-API-Key=$TM_INGEST_KEY,X-Dataset-Name=shop-prod-metrics"Run
Put opentelemetry-instrument in front of the command that starts your app:
$ opentelemetry-instrument python manage.py runserverIn production, the same with Gunicorn:
$ opentelemetry-instrument gunicorn mysite.wsgiCheck it arrived
Send your app a few requests, then open each explorer and choose the dataset:
- Traces,
shop-prod-traces: one server span per request, named after its URL pattern, such asGET items/<int:item_id>, with a span for each query. - Logs,
shop-prod-logs: yourloggingrecords, each with its request'strace.trace_id. - Metrics,
shop-prod-metrics:http.server.duration, sent once a minute.
Or count spans by name with tm-cli or the MCP server:
$ tm-cli query shop-prod-traces --since 15m --select "name, count(*)" --group-by namerun_query {
"dataset": "shop-prod-traces",
"description": "Spans by name",
"since": "15m",
"select": "name, count(*)",
"group_by": "name"
}Troubleshooting
-
You must set settings.ALLOWED_HOSTS if DEBUG is False, orno attribute 'ROOT_URLCONF': exportDJANGO_SETTINGS_MODULE. The instrumentation reads your settings beforemanage.pysets it, and falls back to empty ones. -
Requested component 'otlp_proto_grpc' not found: setOTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf. The Python distro defaults to gRPC, which Telemetry Machine doesn't accept. -
No
INFOlogs from your code: the root logger drops records belowWARNING. Raise it in your settings:PythonLOGGING = {"version": 1, "disable_existing_loggers": False, "root": {"level": "INFO"}}