Python applications have strong Datadog APM support via the ddtrace library, which auto-instruments Django, FastAPI, Flask, Celery, SQLAlchemy, Redis, and dozens of other libraries with minimal configuration. The problem is that ddtrace is tightly coupled to the Datadog platform. Every trace and metric it generates flows to Datadog and contributes to your per-host bill. Switching backends means replacing the instrumentation library, re-deploying, and verifying coverage.
OpenTelemetry solves this at the instrumentation layer. The opentelemetry-instrument command is the direct replacement for ddtrace-run. It auto-instruments the same libraries, produces the same signals, and exports to any OTLP-compatible backend. Migrating from ddtrace to OTel takes one dependency change and one startup command change, with no modifications to application code.
Key Takeaways
- Datadog’s Python agent (ddtrace) uses ddtrace-run to wrap your application at startup. The OTel equivalent is opentelemetry-instrument, provided by opentelemetry-distro. Both use monkey patching. The startup command replacement is one-to-one
- Latest OTel Python packages as of May 21, 2026: opentelemetry-api==1.42.1, opentelemetry-sdk==1.42.1, opentelemetry-distro==0.63b1. All require Python 3.10 or above. opentelemetry-bootstrap -a install auto-detects your installed packages and installs matching instrumentation libraries
- Django, Flask, FastAPI, Falcon, and Celery are all supported by OTel auto-instrumentation out of the box. Always use –noreload with Django when running under opentelemetry-instrument. The Django auto-reload mechanism spawns child processes that break OTel instrumentation
- From OTel Python 1.40.0 onward, log auto-instrumentation is enabled by default. No separate configuration is needed to get log-trace correlation
- Datadog supports OTel instrumentation via DD_TRACE_OTEL_ENABLED=true, which uses ddtrace as the OTel trace provider. This enables gradual migration without abandoning Datadog immediately
- CubeAPM provides Python APM covering Django, FastAPI, Flask, and Celery with a dedicated instrumentation page at $0.15/GB ingestion, no per-host fees, self-hosted inside your own cloud
Why Python Teams Look Beyond Datadog
Python applications on Datadog encounter two specific friction points beyond the general per-host pricing problem.
ddtrace creates vendor lock-in at the instrumentation layer. ddtrace is not an OTel-compatible library. Traces it generates use Datadog’s internal propagation format and are routed to Datadog’s intake endpoint. Moving to a different backend requires replacing ddtrace entirely, re-instrumenting custom spans written against the ddtrace API, and redeploying. In a microservices environment with many Python services, that is a significant migration project.
Custom metrics from Python code count against Datadog’s custom metric allotment. The Pro plan includes 100 custom metrics per host. Instrumenting business-level events from Python (order counts, payment values, user actions) uses these slots. High-cardinality labels (per-user, per-request, per-session) create exponential custom metric counts that silently drive overage charges.
Per-host billing does not reflect Python’s deployment patterns. Python services commonly run on serverless platforms (Lambda, Cloud Run), ephemeral containers, and autoscaling groups. Datadog’s 99th percentile per-host billing means ephemeral infrastructure created during peak periods sets the month’s bill, even if those instances ran for only hours.
Migrating from ddtrace to OpenTelemetry
The migration path from Datadog’s ddtrace to OTel instrumentation preserves auto-instrumentation coverage while making your Python code vendor-neutral.
Step 1: Replace ddtrace with OTel packages
# Remove Datadog instrumentation
pip uninstall ddtrace
# Install OTel core and auto-instrumentation runner
pip install opentelemetry-api==1.42.1 \
opentelemetry-sdk==1.42.1 \
opentelemetry-distro==0.63b1 \
opentelemetry-exporter-otlp-proto-http==1.42.1
# Auto-detect installed packages and install matching instrumentation
# Installs Flask, Django, FastAPI, Celery, SQLAlchemy, Redis, psycopg2
# instrumentation libraries matching what is in your environment
opentelemetry-bootstrap -a installopentelemetry-bootstrap -a install reads through your active site-packages and installs the corresponding OTel instrumentation library for each supported package it finds. If you have Django installed, it installs opentelemetry-instrumentation-django. If you have requests installed, it installs opentelemetry-instrumentation-requests. You do not need to enumerate instrumentation packages manually.
Step 2: Replace the startup command
The ddtrace-run command wrapper is replaced by opentelemetry-instrument:
# Before (Datadog)
ddtrace-run python manage.py runserver --noreload
# After (OpenTelemetry)
OTEL_SERVICE_NAME=my-django-app \
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318 \
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
opentelemetry-instrument python manage.py runserver --noreloadFor Gunicorn in production:
OTEL_SERVICE_NAME=my-django-app \
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318 \
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
opentelemetry-instrument gunicorn myproject.wsgi:application \
--bind 0.0.0.0:8000 \
--workers 4For FastAPI with Uvicorn:
OTEL_SERVICE_NAME=my-fastapi-app \
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318 \
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
opentelemetry-instrument uvicorn main:app --host 0.0.0.0 --port 8000For Celery workers:
OTEL_SERVICE_NAME=my-celery-worker \
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318 \
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
opentelemetry-instrument celery -A myproject worker --loglevel=infoStep 3: Migrate custom instrumentation from ddtrace API to OTel API
If you have custom spans written against the ddtrace API, rewrite them against the OTel API:
# Before (ddtrace)
from ddtrace import tracer
with tracer.trace("payment.process", service="payment-api") as span:
span.set_tag("payment.currency", currency)
result = process_payment(amount, currency)
span.set_tag("payment.transaction_id", result.transaction_id)# After (OpenTelemetry)
from opentelemetry import trace
tracer = trace.get_tracer("payment-api")
with tracer.start_as_current_span("payment.process") as span:
span.set_attribute("payment.currency", currency)
result = process_payment(amount, currency)
span.set_attribute("payment.transaction_id", result.transaction_id)The concepts map directly: tracer.trace() becomes tracer.start_as_current_span(), set_tag() becomes set_attribute(). Custom spans written against the OTel API are vendor-neutral and work with any OTLP-compatible backend without modification.
Optional: Gradual migration via DD_TRACE_OTEL_ENABLED
If you want to start routing OTel data to Datadog while keeping ddtrace in place during a gradual migration, Datadog supports this via the DD_TRACE_OTEL_ENABLED=true environment variable. Setting it makes ddtrace act as the OTel trace provider. OTel spans are collected by ddtrace and sent to Datadog. This allows you to migrate application code to the OTel API incrementally without switching backends immediately.
DD_TRACE_OTEL_ENABLED=true \
DD_SERVICE=my-django-app \
ddtrace-run python manage.py runserver --noreloadFramework-Specific OTel Instrumentation Package Versions
Verified from PyPI as of May 2026:
| Framework | Package | Latest version | Python minimum |
| Django | opentelemetry-instrumentation-django | 0.62b1 (April 24, 2026) | Python 3.9 |
| FastAPI | opentelemetry-instrumentation-fastapi | 0.63b0 (May 19, 2026) | Python 3.10 |
| Flask | opentelemetry-instrumentation-flask | 0.63b0 (May 19, 2026) | Python 3.10 |
| Celery | opentelemetry-instrumentation-celery | 0.63b0 (May 19, 2026) | Python 3.10 |
| SQLAlchemy | opentelemetry-instrumentation-sqlalchemy | 0.63b0 (May 19, 2026) | Python 3.10 |
| psycopg2 | opentelemetry-instrumentation-psycopg2 | 0.63b0 (May 19, 2026) | Python 3.10 |
| Redis | opentelemetry-instrumentation-redis | 0.63b0 (May 19, 2026) | Python 3.10 |
| requests | opentelemetry-instrumentation-requests | 0.63b0 (May 19, 2026) | Python 3.10 |
| httpx | opentelemetry-instrumentation-httpx | 0.63b0 (May 19, 2026) | Python 3.10 |
| Falcon | opentelemetry-instrumentation-falcon | 0.63b0 (May 19, 2026) | Python 3.10 |
Top Datadog Alternatives
1. CubeAPM

CubeAPM is a full-stack observability platform that runs inside your own infrastructure with a dedicated Python APM instrumentation page covering Django, FastAPI, Flask, and Celery. Because it accepts OTLP natively, migrating from ddtrace to CubeAPM means replacing ddtrace-run with opentelemetry-instrument and pointing OTEL_EXPORTER_OTLP_ENDPOINT at your CubeAPM instance. No other changes.
Pricing: $0.15/GB ingestion. No per-host fees. No per-user fees. No custom metric overages.
Custom metrics from your Python application (business events, counters, histograms created via the OTel metrics API) are not a separate billing category. They are ingested at the same flat rate as traces and logs. A Python application instrumented with dozens of custom metrics pays the same per-GB rate as one with no custom metrics.
Django setup (verified from cubeapm.com/instrumentation):
# Install packages
pip install opentelemetry-api==1.42.1 \
opentelemetry-sdk==1.42.1 \
opentelemetry-distro==0.63b1 \
opentelemetry-exporter-otlp-proto-http==1.42.1
opentelemetry-bootstrap -a install# Run Django (always use --noreload)
OTEL_SERVICE_NAME=my-django-app \
OTEL_EXPORTER_OTLP_ENDPOINT=http://your-cubeapm-instance:4318 \
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
opentelemetry-instrument python manage.py runserver --noreloadBest for: Python teams that want a full Datadog replacement with no per-host fees, data that stays inside their own cloud, and straightforward Django/FastAPI/Flask/Celery instrumentation via OTel.
Limitations: Self-hosted deployment required. Not a fit for teams that want a fully managed SaaS with no infrastructure responsibilities.
2. New Relic

New Relic’s Python agent (newrelic) auto-instruments Django, Flask, FastAPI, Celery, SQLAlchemy, Redis, and other common Python libraries. It collects APM traces, error traces, transaction traces, slow SQL queries, and custom metrics. Unlike Datadog’s ddtrace, New Relic also supports OpenTelemetry instrumentation natively via its OTLP endpoint, so teams can use opentelemetry-instrument with OTEL_EXPORTER_OTLP_ENDPOINT pointing at New Relic’s OTLP ingest URL.
Pricing: Free tier: 100GB/month, one full platform user, unlimited basic users, all capabilities. Paid: $0.40/GB beyond free ($0.60/GB for Data Plus). No per-host fees. No custom metric overages.
Python setup via OTel (vendor-neutral approach):
pip install opentelemetry-api==1.42.1 \
opentelemetry-sdk==1.42.1 \
opentelemetry-distro==0.63b1 \
opentelemetry-exporter-otlp-proto-http==1.42.1
opentelemetry-bootstrap -a install
OTEL_SERVICE_NAME=my-python-app \
OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net:4318 \
OTEL_EXPORTER_OTLP_HEADERS="api-key=YOUR_LICENSE_KEY" \
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
opentelemetry-instrument gunicorn myproject.wsgi:applicationBest for: Python teams that want a full-stack SaaS alternative to Datadog with the most generous free tier in the market. Teams that can stay within 100GB/month with a small team get the complete platform for free.
Limitations: Data leaves your infrastructure. Free tier retention is 8 days for most data types.
Grafana Cloud

Grafana Cloud accepts OTLP directly from Python applications. Route telemetry from opentelemetry-instrument through the OTel Collector to Grafana Cloud’s OTLP endpoint, or configure the OTLP exporter to push directly to Grafana Cloud without a Collector.
Python setup (direct to Grafana Cloud):
pip install opentelemetry-api==1.42.1 \
opentelemetry-sdk==1.42.1 \
opentelemetry-distro==0.63b1 \
opentelemetry-exporter-otlp-proto-http==1.42.1
opentelemetry-bootstrap -a install
OTEL_SERVICE_NAME=my-python-app \
OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp-gateway-prod-us-central-0.grafana.net/otlp \
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic BASE64_ENCODED_CREDENTIALS" \
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
opentelemetry-instrument gunicorn myproject.wsgi:applicationPricing: Free tier: 2,232 host hours/month, 14-day retention. Paid: usage-based on active series, GB ingested, and host hours. No per-host license fees.
Best for: Teams already using Prometheus and Grafana who want traces and logs from their Python applications to join the same dashboards. Teams that want PromQL for alerting on Python application metrics.
Limitations: Free tier 14-day retention is insufficient for trend analysis. Active series billing grows with high-cardinality metric labels.
4. SigNoz

SigNoz is an OTel-native, open-source observability platform. Python auto-instrumentation via opentelemetry-instrument works identically with SigNoz as with any other OTLP backend. The SigNoz documentation confirms Django, Flask, FastAPI, Falcon, and Celery all work out of the box via opentelemetry-bootstrap.
Python setup (SigNoz Cloud):
pip install opentelemetry-api==1.42.1 \
opentelemetry-sdk==1.42.1 \
opentelemetry-distro==0.63b1 \
opentelemetry-exporter-otlp-proto-http==1.42.1
opentelemetry-bootstrap -a install
OTEL_SERVICE_NAME=my-python-app \
OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.{region}.signoz.cloud:443 \
OTEL_EXPORTER_OTLP_HEADERS="signoz-ingestion-key=YOUR_KEY" \
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
opentelemetry-instrument gunicorn myproject.wsgi:applicationPricing:
Teams Cloud: $49/month (currently reduced from $199/month), includes $49 worth of usage (163GB logs/traces or 490M metric samples). Beyond that: $0.30/GB logs and traces, $0.10/million metric samples. Community edition free to self-host. No per-host fees.
Best for: Python teams that want an OTel-native platform with open-source roots and the option to self-host at zero licensing cost.
Limitations: Community edition has capped dashboard panel counts for traces and logs. Enterprise self-hosted requires procurement engagement.
Comparison at a Glance
| Tool | Python instrumentation | Per-host fee | Free tier | Self-hosted | Starting cost |
| CubeAPM | OTel auto-instrumentation via opentelemetry-instrument | No | None | Yes (required) | $0.15/GB |
| New Relic | OTel or native newrelic agent | No | 100GB/month | No | Free tier |
| Grafana Cloud | OTel via Collector or direct OTLP | No | 14-day retention | Partial | Free tier |
| SigNoz | OTel auto-instrumentation via opentelemetry-instrument | No | Community edition | Yes | $49/month (Cloud) |
| Datadog | ddtrace-run wrapper (vendor-specific) | Yes ($15/host/month Pro) | 5 hosts, 1-day | No | $15/host/month |
Common Migration Problems
| Problem | Likely cause | Fix |
| Django development server breaks after adding opentelemetry-instrument | Django auto-reload spawning child processes that break OTel instrumentation | Always use –noreload with Django under opentelemetry-instrument: opentelemetry-instrument python manage.py runserver –noreload |
| opentelemetry-instrument command not found | opentelemetry-distro not installed | Run pip install opentelemetry-distro==0.63b1 |
| No database query spans after migration | opentelemetry-bootstrap -a install not run, or psycopg2/SQLAlchemy instrumentation not installed | Run opentelemetry-bootstrap -a install after installing all application dependencies so it detects and installs matching instrumentation |
| Custom ddtrace spans producing no data after migration | Custom spans still written against the ddtrace API | Rewrite custom spans using from opentelemetry import trace and tracer.start_as_current_span() |
| Celery tasks not producing spans | Celery worker not started under opentelemetry-instrument | Start Celery workers with the opentelemetry-instrument prefix, the same way you start the web process |
| Logs not correlated with traces | OTel Python version below 1.40.0 | Upgrade to opentelemetry-sdk==1.42.1. Log auto-instrumentation is enabled by default from 1.40.0 onward |
From ddtrace to Full Observability: Where CubeAPM Fits
The migration from ddtrace to opentelemetry-instrument takes one afternoon. The instrumentation swap is the easy part. What takes longer is deciding where the telemetry flows after you remove Datadog from the picture.
The question for most Python teams is: do you want a managed SaaS backend where data leaves your infrastructure, or a self-hosted backend where data stays inside your cloud and the bill does not scale with your host count?
CubeAPM is built for the second case. Point OTEL_EXPORTER_OTLP_ENDPOINT at your CubeAPM instance during the migration and your Django, FastAPI, Flask, and Celery services send traces, metrics, and logs to CubeAPM the moment they restart. No additional SDK changes. No per-host billing. No custom metric overages. Smart sampling preserves slow, error-prone, and unusual traces while reducing ingestion volume by up to 80%, keeping the bill predictable as request volume grows. It runs self-hosted inside your own infrastructure at $0.15/GB with no per-user fees.
Summary
Migrating Python applications from Datadog to an alternative comes down to two steps: replacing ddtrace-run with opentelemetry-instrument and replacing OTEL_EXPORTER_OTLP_ENDPOINT with your new backend’s endpoint. The application code does not change for auto-instrumented libraries. Custom ddtrace spans need rewriting against the OTel API, which maps one-to-one. All four backends in this guide (CubeAPM, New Relic, Grafana Cloud, SigNoz) accept OTLP and work with the same opentelemetry-instrument startup command.
| Step | Command | Key detail |
| Install OTel packages | pip install opentelemetry-api==1.42.1 opentelemetry-sdk==1.42.1 opentelemetry-distro==0.63b1 | Python 3.10 minimum |
| Auto-detect instrumentation | opentelemetry-bootstrap -a install | Scans site-packages and installs matching OTel instrumentation libraries |
| Replace startup command | opentelemetry-instrument python manage.py runserver –noreload | –noreload required for Django |
| Point at new backend | OTEL_EXPORTER_OTLP_ENDPOINT=http://your-backend:4318 | Same command works for CubeAPM, New Relic, Grafana Cloud, SigNoz |
| Migrate custom spans | Replace ddtrace.tracer.trace() with tracer.start_as_current_span() | OTel API is vendor-neutral |
| Celery workers | opentelemetry-instrument celery -A myproject worker | Same wrapper, same env vars |
Disclaimer: OTel Python package versions (opentelemetry-api 1.42.1 and opentelemetry-sdk 1.42.1, May 21, 2026; opentelemetry-distro 0.63b1, May 21, 2026; framework instrumentation package versions) verified directly from PyPI as of May 2026. opentelemetry-bootstrap -a install behavior and –noreload requirement for Django verified from official OpenTelemetry Python docs (opentelemetry.io/docs/zero-code/python, last modified May 28, 2026) and SigNoz Python instrumentation docs (signoz.io/docs/instrumentation/opentelemetry-python, last updated March 5, 2026). DD_TRACE_OTEL_ENABLED=true verified from official Datadog documentation (docs.datadoghq.com/opentelemetry/instrument/api_support/python). Log auto-instrumentation enabled by default from 1.40.0 confirmed from official OTel Python configuration docs (opentelemetry.io/docs/zero-code/python/configuration, last modified March 4, 2026). SigNoz pricing verified from signoz.io/pricing as of May 2026. New Relic pricing ($0.40/GB) verified from newrelic.com/pricing as of May 2026. CubeAPM Python instrumentation verified from cubeapm.com/instrumentation as of May 2026.
Also read:
What Are the Best Datadog Alternatives With No Per-Host Pricing?
What Is the Best Datadog Alternatives for Kubernetes Monitoring?





