Python Instrumentation¶
Subscription required
This section describes functionality which requires an active IAPM subscription. Start your subscription by choosing the plan right for you.
Instrument your Python applications with OpenTelemetry to send traces, metrics, and logs to IAPM. This guide covers Django, Flask, FastAPI, auto-instrumentation, and manual SDK usage.
Install Packages¶
Install the core OpenTelemetry packages:
Then install auto-instrumentation libraries for your framework:
Auto-Instrumentation (Quickest Start)¶
The opentelemetry-instrument command wraps your application and automatically instruments supported libraries:
OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.iapm.app \
OTEL_EXPORTER_OTLP_HEADERS="API-Key=YOUR-API-KEY" \
OTEL_SERVICE_NAME=my-python-app \
opentelemetry-instrument python your_app.py
For framework-specific entry points:
Django Setup (Programmatic)¶
For more control, configure OpenTelemetry in your Django settings.py or a startup module:
# otel_setup.py
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource, SERVICE_NAME
from opentelemetry.instrumentation.django import DjangoInstrumentor
def configure_opentelemetry():
resource = Resource.create({
SERVICE_NAME: "my-django-app",
})
provider = TracerProvider(resource=resource)
exporter = OTLPSpanExporter(
endpoint="https://otlp.iapm.app",
headers={"API-Key": "YOUR-API-KEY"},
)
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)
# Instrument Django
DjangoInstrumentor().instrument()
Call configure_opentelemetry() early in your application startup - for example, in your wsgi.py or manage.py:
# wsgi.py
import os
from django.core.wsgi import get_wsgi_application
from otel_setup import configure_opentelemetry
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
configure_opentelemetry()
application = get_wsgi_application()
Flask Setup (Programmatic)¶
from flask import Flask
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource, SERVICE_NAME
from opentelemetry.instrumentation.flask import FlaskInstrumentor
# Configure OpenTelemetry
resource = Resource.create({SERVICE_NAME: "my-flask-app"})
provider = TracerProvider(resource=resource)
exporter = OTLPSpanExporter(
endpoint="https://otlp.iapm.app",
headers={"API-Key": "YOUR-API-KEY"},
)
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)
# Create and instrument the Flask app
app = Flask(__name__)
FlaskInstrumentor().instrument_app(app)
@app.route("/")
def hello():
return "Hello, World!"
if __name__ == "__main__":
app.run()
FastAPI Setup (Programmatic)¶
from fastapi import FastAPI
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource, SERVICE_NAME
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
# Configure OpenTelemetry
resource = Resource.create({SERVICE_NAME: "my-fastapi-app"})
provider = TracerProvider(resource=resource)
exporter = OTLPSpanExporter(
endpoint="https://otlp.iapm.app",
headers={"API-Key": "YOUR-API-KEY"},
)
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)
# Create and instrument the FastAPI app
app = FastAPI()
FastAPIInstrumentor.instrument_app(app)
@app.get("/")
async def root():
return {"message": "Hello, World!"}
Manual Instrumentation¶
Create custom spans to trace your own business logic:
from opentelemetry import trace
tracer = trace.get_tracer("myapp.orders")
def process_order(order_id: int):
with tracer.start_as_current_span("process_order") as span:
span.set_attribute("order.id", order_id)
order = get_order(order_id)
span.set_attribute("order.total", order.total)
try:
charge_payment(order)
span.add_event("payment.completed")
fulfill_order(order)
span.set_status(trace.StatusCode.OK)
return order
except Exception as e:
span.set_status(trace.StatusCode.ERROR, str(e))
span.record_exception(e)
raise
Custom Metrics¶
from opentelemetry import metrics
meter = metrics.get_meter("myapp.orders")
orders_counter = meter.create_counter(
"orders.processed",
unit="orders",
description="Number of orders processed",
)
order_duration = meter.create_histogram(
"orders.processing.duration",
unit="ms",
description="Order processing time",
)
def process_order(order):
import time
start = time.time()
do_processing(order)
duration_ms = (time.time() - start) * 1000
orders_counter.add(1, {"order.type": order.type})
order_duration.record(duration_ms)
Environment Variable Configuration¶
The OpenTelemetry Python SDK reads these variables automatically:
| Variable | Value | Description |
|---|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT | https://otlp.iapm.app | OTLP collector endpoint |
OTEL_EXPORTER_OTLP_HEADERS | API-Key=YOUR-API-KEY | Authentication header |
OTEL_SERVICE_NAME | your-service-name | Service name shown in IAPM |
OTEL_EXPORTER_OTLP_PROTOCOL | grpc | Protocol (grpc or http/protobuf) |
OTEL_TRACES_EXPORTER | otlp | Trace exporter type |
OTEL_METRICS_EXPORTER | otlp | Metrics exporter type |
OTEL_LOGS_EXPORTER | otlp | Logs exporter type |
OTEL_PYTHON_LOG_LEVEL | info | OpenTelemetry SDK log level |
Verify It's Working¶
- Run your instrumented application
- Send a few HTTP requests to generate traces
- Open portal.iapm.app and select your Grid
- Click Enter - you should see your service and traces within a few minutes
Quick verification with console exporter
Add the console exporter to see spans printed to stdout during development:
Troubleshooting¶
No data appearing in IAPM¶
- Verify the API key by copying a fresh one from portal.iapm.app under Administration > Grids > Instrument.
- Check network connectivity:
python -c "import urllib.request; urllib.request.urlopen('https://otlp.iapm.app')". - Ensure
grpciois installed:pip install grpcio. The gRPC exporter requires it.
Auto-instrumentation not working¶
- Ensure
opentelemetry-instrumentis on your PATH (it is installed byopentelemetry-distro). - Run
opentelemetry-bootstrap -a requirementsto see which instrumentation packages are available for your installed libraries. - Check that framework-specific instrumentation packages are installed (e.g.,
opentelemetry-instrumentation-flask).
Import errors or version conflicts¶
- Keep all
opentelemetry-*packages at compatible versions. Usepip install --upgrade opentelemetry-distro opentelemetry-exporter-otlpto get a consistent set. - Check for conflicts:
pip check.
Gunicorn workers not exporting¶
-
When using Gunicorn with multiple workers, configure OpenTelemetry in a
post_forkhook to ensure each worker has its own provider: