Python Instrumentation
Instrument a Python application with OpenTelemetry and send traces, logs, and metrics to Maple.
This guide covers instrumenting a Python application to send traces and logs to Maple using the OpenTelemetry SDK.
Run this with Claude Code:
maple-onboardwalks every service in the repo, installs OpenTelemetry, and verifies the bootstrap end-to-end. See the maple-onboard skill.
Prerequisites
- Python 3.8+
- A Maple project with an API key (or use the
MAPLE_TESTplaceholder while pairing — see below)
Install Dependencies
pip install opentelemetry-sdk \
opentelemetry-exporter-otlp-proto-http \
opentelemetry-instrumentation
Configure the SDK
Create a tracing.py module to initialize the SDK. Inline the endpoint and ingest key — the key is project-scoped and write-only (Sentry-DSN-shaped), so source-level configuration removes a class of “OTel didn’t start because env vars weren’t set” deploy failures.
# tracing.py
import os
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource
MAPLE_ENDPOINT = "https://ingest.maple.dev"
MAPLE_KEY = "MAPLE_TEST" # replace with your real key from Settings → API Keys
resource = Resource.create({
"service.name": "my-python-app",
"deployment.environment.name": os.getenv("DEPLOYMENT_ENV", "development"),
"vcs.repository.url.full": "https://github.com/acme/my-python-app",
"vcs.ref.head.revision": os.getenv("RAILWAY_GIT_COMMIT_SHA")
or os.getenv("GITHUB_SHA")
or os.getenv("GIT_COMMIT", ""),
})
provider = TracerProvider(resource=resource)
exporter = OTLPSpanExporter(
endpoint=f"{MAPLE_ENDPOINT}/v1/traces",
headers={"authorization": f"Bearer {MAPLE_KEY}"},
)
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)
MAPLE_TESTplaceholder: While you’re pairing your editor with Maple, the literal stringMAPLE_TESTis accepted by the ingest gateway and discarded — so the bootstrap can run end-to-end before you’ve created your first key. Once you have a real key, search-replaceMAPLE_TESTin the file above with it.
Import this module early in your application startup, before other modules that need tracing:
import tracing # Initialize OpenTelemetry first
from myapp import create_app
app = create_app()
Auto-Instrumentation
The easiest way to instrument common libraries is with the auto-instrumentation CLI.
First, install instrumentations for your installed packages:
opentelemetry-bootstrap -a install
Then run your application with the opentelemetry-instrument wrapper:
opentelemetry-instrument python app.py
This automatically instruments libraries like Flask, Django, requests, SQLAlchemy, psycopg2, redis, and many more.
Alternatively, install specific instrumentation packages for finer control:
pip install opentelemetry-instrumentation-flask \
opentelemetry-instrumentation-requests \
opentelemetry-instrumentation-sqlalchemy
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry.instrumentation.requests import RequestsInstrumentor
FlaskInstrumentor().instrument()
RequestsInstrumentor().instrument()
FastAPI
FastAPI has a dedicated instrumentation package that traces every route as a span:
pip install opentelemetry-instrumentation-fastapi
import tracing # Initialize OpenTelemetry first
from fastapi import FastAPI
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
app = FastAPI()
FastAPIInstrumentor.instrument_app(app)
If you also use httpx or requests for outgoing calls, install the matching instrumentation packages — they propagate trace context automatically so downstream services connect to the parent trace.
Django
pip install opentelemetry-instrumentation-django
# settings.py or top of wsgi.py
import tracing # Initialize OpenTelemetry first
from opentelemetry.instrumentation.django import DjangoInstrumentor
DjangoInstrumentor().instrument()
The Django instrumentation creates a span per HTTP request and integrates with the ORM through opentelemetry-instrumentation-dbapi-backed packages (opentelemetry-instrumentation-psycopg2, opentelemetry-instrumentation-sqlite3, etc.).
Custom Spans
Create custom spans to trace specific operations:
from opentelemetry import trace
from opentelemetry.trace import StatusCode
tracer = trace.get_tracer("my-app")
def process_order(order_id: str):
with tracer.start_as_current_span("process-order") as span:
span.set_attribute("order.id", order_id)
# Set peer.service when calling another service
span.set_attribute("peer.service", "payment-api")
try:
result = charge_payment(order_id)
return result
except Exception as e:
span.record_exception(e)
span.set_status(StatusCode.ERROR, str(e))
raise
Setting peer.service on outgoing calls makes them visible on Maple’s service map.
Log Correlation
Send logs to Maple with trace correlation by adding the OTel log exporter:
pip install opentelemetry-exporter-otlp-proto-http
from opentelemetry.sdk._logs import LoggerProvider
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
from opentelemetry.exporter.otlp.proto.http._log_exporter import OTLPLogExporter
from opentelemetry._logs import set_logger_provider
logger_provider = LoggerProvider(resource=resource)
logger_provider.add_log_record_processor(
BatchLogRecordProcessor(
OTLPLogExporter(
endpoint="https://ingest.maple.dev/v1/logs",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
)
)
set_logger_provider(logger_provider)
To bridge Python’s standard logging module to OTel:
import logging
from opentelemetry.sdk._logs import LoggingHandler
handler = LoggingHandler(logger_provider=logger_provider)
logging.getLogger().addHandler(handler)
# Now standard logging calls include trace context
logging.info("Order processed successfully")
Environment Variables
As an alternative to programmatic configuration, set standard OTel environment variables:
export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.maple.dev"
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer YOUR_API_KEY"
export OTEL_SERVICE_NAME="my-python-app"
export OTEL_RESOURCE_ATTRIBUTES="deployment.environment.name=production,vcs.repository.url.full=https://github.com/acme/my-python-app"
Then use opentelemetry-instrument to run your app with auto-instrumentation and these settings applied automatically.
Verify
- Start your application
- Generate some traffic (send a request, trigger an operation)
- Open the Maple dashboard and check that traces appear in the traces view
If traces aren’t appearing, verify:
- The ingest endpoint URL is correct
- Your API key is valid
- Your application can reach
ingest.maple.dev(or your self-hosted URL)