This guide shows you how to instrument your Python application with OpenTelemetry and send traces to SigNoz. The auto-instrumentation approach works with Django, Flask, FastAPI, Falcon, Celery, and most Python libraries out of the box.
Prerequisites
- Python 3.8 or newer
- A SigNoz Cloud account or self-hosted SigNoz instance
- Your application code
Tested with Python 3.11 and OpenTelemetry Python SDK v1.27.0.
Send traces to SigNoz
Step 1. Install OpenTelemetry packages
pip install opentelemetry-distro opentelemetry-exporter-otlp
Step 2. Install instrumentation for your dependencies
This command detects your installed packages and adds the corresponding instrumentation libraries:
opentelemetry-bootstrap --action=install
Run this after installing all your application dependencies. It will only instrument packages that are already installed.
Step 3. Set environment variables
export OTEL_RESOURCE_ATTRIBUTES="service.name=<service-name>"
export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.<region>.signoz.cloud:443"
export OTEL_EXPORTER_OTLP_HEADERS="signoz-ingestion-key=<your-ingestion-key>"
export OTEL_EXPORTER_OTLP_PROTOCOL="grpc"
Replace the following:
<region>: Your SigNoz Cloud region (us,eu, orin). See endpoints.<your-ingestion-key>: Your SigNoz ingestion key.<service-name>: A descriptive name for your service (e.g.,payment-service).
Step 4. Run your application
opentelemetry-instrument <your_run_command>
See Framework instrumentation below for framework-specific commands.
For Python applications on Kubernetes, you can use:
- K8s OTel Operator (recommended) — Auto-injects instrumentation without code changes
- OTel Collector Agent — Manual instrumentation with collector handling forwarding
The OpenTelemetry Operator manages collectors and auto-instrumentation in Kubernetes.
Step 1. Install cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.16.1/cert-manager.yaml
kubectl wait --for=condition=Available deployments/cert-manager -n cert-manager
Step 2. Install OpenTelemetry Operator
kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/download/v0.116.0/opentelemetry-operator.yaml
Step 3. Create the OpenTelemetry Collector instance
Create otel-collector.yaml:
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
name: otel-collector
spec:
mode: deployment
config: |
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch: {}
exporters:
otlp:
endpoint: "ingest.<region>.signoz.cloud:443"
tls:
insecure: false
headers:
"signoz-ingestion-key": "<your-ingestion-key>"
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
Replace <region> and <your-ingestion-key> with your SigNoz Cloud values.
kubectl apply -f otel-collector.yaml
Step 4. Create the Instrumentation instance
Create instrumentation.yaml:
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: python-instrumentation
spec:
exporter:
endpoint: http://otel-collector-collector:4318
propagators:
- tracecontext
- baggage
python:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-python:latest
kubectl apply -f instrumentation.yaml
Step 5. Add annotations to your deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: python-app
spec:
selector:
matchLabels:
app: python-app
template:
metadata:
labels:
app: python-app
annotations:
instrumentation.opentelemetry.io/inject-python: "true"
instrumentation.opentelemetry.io/otel-python-platform: "glibc" # or "musl" for Alpine
resource.opentelemetry.io/service.name: "python-app"
spec:
containers:
- name: app
image: python-app:latest
ports:
- containerPort: 8080
kubectl apply -f deployment.yaml
Install the OTel Collector agent in your cluster first. See Kubernetes infrastructure metrics. The collector handles forwarding to SigNoz, so your app doesn't need the ingestion key.
Step 1. Add OpenTelemetry to requirements.txt
opentelemetry-distro
opentelemetry-exporter-otlp
Step 2. Update your Dockerfile
RUN pip install --no-cache-dir -r requirements.txt
RUN opentelemetry-bootstrap --action=install
ENV OTEL_RESOURCE_ATTRIBUTES=service.name=<service-name>
ENV OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
ENV OTEL_EXPORTER_OTLP_PROTOCOL=grpc
# See Framework instrumentation section for the correct CMD
CMD ["opentelemetry-instrument", "python", "app.py"]
Step 1. Install OpenTelemetry packages
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap --action=install
Step 2. Set environment variables
$env:OTEL_RESOURCE_ATTRIBUTES = "service.name=<service-name>"
$env:OTEL_EXPORTER_OTLP_ENDPOINT = "https://ingest.<region>.signoz.cloud:443"
$env:OTEL_EXPORTER_OTLP_HEADERS = "signoz-ingestion-key=<your-ingestion-key>"
$env:OTEL_EXPORTER_OTLP_PROTOCOL = "grpc"
Step 3. Run your application
opentelemetry-instrument <your_run_command>
See Framework instrumentation below for framework-specific commands.
Step 1. Update your Dockerfile
RUN pip install opentelemetry-distro opentelemetry-exporter-otlp
RUN opentelemetry-bootstrap --action=install
ENV OTEL_RESOURCE_ATTRIBUTES=service.name=<service-name>
ENV OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.<region>.signoz.cloud:443
ENV OTEL_EXPORTER_OTLP_HEADERS=signoz-ingestion-key=<your-ingestion-key>
ENV OTEL_EXPORTER_OTLP_PROTOCOL=grpc
# See Framework instrumentation section for the correct CMD
CMD ["opentelemetry-instrument", "python", "app.py"]
Replace <region>, <your-ingestion-key>, and <service-name> with your values.
Step 2. Build and run
docker build -t <image-name> .
docker run -d -p <host-port>:<container-port> <image-name>
Framework instrumentation
Choose your framework below to see the specific run command. The setup steps above are the same for all frameworks.
Web Frameworks
Django
Prerequisites
Set the DJANGO_SETTINGS_MODULE environment variable:
export DJANGO_SETTINGS_MODULE=myproject.settings
Run command
opentelemetry-instrument python manage.py runserver --noreload
Always use --noreload with Django. The auto-reload mechanism spawns child processes that break OpenTelemetry instrumentation.
Running with Gunicorn or uWSGI
Gunicorn works out of the box. No extra setup needed unless you use the --preload flag. If you do use --preload, see the post_fork hook example.
uWSGI requires one of these options:
- Add
lazy-apps = trueto your uWSGI config (recommended, simplest fix) - Or implement a post_fork hook (see example)
Validate
With your application running, verify traces are being sent to SigNoz:
- Trigger an action in your app that generates a web request. Hit the endpoint a few times.
- In SigNoz, open the Services tab and click Refresh. Your application should appear.
- Go to the Traces tab to see your application's traces.
Troubleshooting
Why don't traces appear in SigNoz?
Check environment variables are set:
echo $OTEL_EXPORTER_OTLP_ENDPOINT
echo $OTEL_RESOURCE_ATTRIBUTES
Verify network connectivity:
# For SigNoz Cloud
curl -v https://ingest.<region>.signoz.cloud:443/v1/traces
Enable console exporter to verify spans are being created:
OTEL_TRACES_EXPORTER=console opentelemetry-instrument <your_run_command>
If you see JSON span output in your terminal but traces don't appear in SigNoz, the issue is with export configuration (endpoint, auth, or network). If no output appears, the instrumentation isn't capturing your requests.
Why do multi-worker servers (Uvicorn, Gunicorn) drop spans?
Application servers that spawn multiple worker processes require special handling because the OpenTelemetry SDK isn't fork-safe.
- Uvicorn with
--workersflag is not supported. Use Gunicorn with Uvicorn workers instead:opentelemetry-instrument gunicorn -k uvicorn.workers.UvicornWorker main:app - Hypercorn/Unicorn are not supported due to fork-safety issues. See the Hypercorn/Unicorn tab for details and workarounds.
- Gunicorn with
--preloador uWSGI need extra config. See Running with Gunicorn or uWSGI.
Hot reload breaks instrumentation
Don't run your app in reloader/hot-reload mode. For Flask, avoid FLASK_ENV=development. For Django, use --noreload. For Uvicorn/FastAPI, don't use --reload.
gRPC installation issues
If grpcio installation fails, use the HTTP exporter instead:
pip install opentelemetry-exporter-otlp-proto-http
Then set OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf.
Database calls not showing in traces
Auto-instrumentation detects and instruments common database libraries. Ensure you've run opentelemetry-bootstrap --action=install after installing your database drivers.
PostgreSQL note: psycopg2 is preferred over psycopg2-binary for auto-instrumentation. If you must use psycopg2-binary, you may need to use manual instrumentation with Psycopg2Instrumentor().instrument(skip_dep_check=True).
Common database instrumentations installed by bootstrap:
- PostgreSQL:
opentelemetry-instrumentation-psycopg2 - MySQL:
opentelemetry-instrumentation-pymysqloropentelemetry-instrumentation-mysql - MongoDB:
opentelemetry-instrumentation-pymongo - Redis:
opentelemetry-instrumentation-redis - SQLAlchemy:
opentelemetry-instrumentation-sqlalchemy
Check supported versions for compatibility with your library versions.
Setup OpenTelemetry Collector (Optional)
What is the OpenTelemetry Collector?
Think of the OTel Collector as a middleman between your app and SigNoz. Instead of your application sending data directly to SigNoz, it sends everything to the Collector first, which then forwards it along.
Why use it?
- Cleaning up data — Filter out noisy traces you don't care about, or remove sensitive info before it leaves your servers.
- Keeping your app lightweight — Let the Collector handle batching, retries, and compression instead of your application code.
- Adding context automatically — The Collector can tag your data with useful info like which Kubernetes pod or cloud region it came from.
- Future flexibility — Want to send data to multiple backends later? The Collector makes that easy without changing your app.
See Switch from direct export to Collector for step-by-step instructions to convert your setup.
For more details, see Why use the OpenTelemetry Collector? and the Collector configuration guide.
Next steps
- Add manual instrumentation for custom spans and attributes
- Send logs from Python using auto-instrumentation
- Set up alerts for your Python application
- Create dashboards to visualize metrics
Sample applications: