OpenTelemetry instrumentation for Python. Use when adding observability with distributed tracing, metrics, logging, automatic instrumentation, context propagation, and exporters (OTLP, Jaeger, Prometheus). Triggers on OpenTelemetry Python, OTel Python, tracing Python, instrumentation Python, observability Python, or when debugging distributed Python systems.
OpenTelemetry (OTel) is the observability framework for generating and collecting traces, metrics, and logs from distributed systems.
| Signal | Status |
|---|---|
| Traces | Stable |
| Metrics | Stable |
| Logs | Stable |
# Core packages
pip install opentelemetry-api opentelemetry-sdk
# Automatic instrumentation
pip install opentelemetry-distro
opentelemetry-bootstrap -a install
# OTLP exporters
pip install opentelemetry-exporter-otlp-proto-grpc
from opentelemetry import trace, metrics
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.sdk.resources import Resource, SERVICE_NAME, SERVICE_VERSION
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
from opentelemetry.propagate import set_global_textmap
from opentelemetry.propagators.composite import CompositePropagator
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
from opentelemetry.baggage.propagation import W3CBaggagePropagator
def setup_otel():
resource = Resource.create({
SERVICE_NAME: "my-service",
SERVICE_VERSION: "1.0.0",
"deployment.environment": "production",
})
set_global_textmap(CompositePropagator([
TraceContextTextMapPropagator(),
W3CBaggagePropagator(),
]))
# TracerProvider
trace_exporter = OTLPSpanExporter(endpoint="localhost:4317", insecure=True)
trace_provider = TracerProvider(resource=resource)
trace_provider.add_span_processor(BatchSpanProcessor(trace_exporter))
trace.set_tracer_provider(trace_provider)
# MeterProvider
metric_exporter = OTLPMetricExporter(endpoint="localhost:4317", insecure=True)
metric_reader = PeriodicExportingMetricReader(metric_exporter, export_interval_millis=30000)
meter_provider = MeterProvider(resource=resource, metric_readers=[metric_reader])
metrics.set_meter_provider(meter_provider)
return trace_provider, meter_provider
def shutdown_otel(trace_provider, meter_provider):
trace_provider.shutdown()
meter_provider.shutdown()
opentelemetry-instrument \
--traces_exporter otlp \
--metrics_exporter otlp \
--logs_exporter otlp \
--service_name my-service \
python app.py
# Console export (development)
opentelemetry-instrument \
--traces_exporter console \
--service_name my-service \
flask run -p 8080
from opentelemetry import trace
tracer = trace.get_tracer("my.app.tracer")
# Context manager
def process_request(request):
with tracer.start_as_current_span("process-request") as span:
span.set_attribute("request.id", request.id)
return do_work(request)
# Decorator
@tracer.start_as_current_span("do_work")
def do_work(request):
return "result"
def parent_operation():
with tracer.start_as_current_span("parent") as parent_span:
child_operation() # Automatically linked to parent
def child_operation():
with tracer.start_as_current_span("child") as child_span:
pass
from opentelemetry.semconv.trace import SpanAttributes
span = trace.get_current_span()
# Custom attributes
span.set_attribute("user.id", "12345")
span.set_attribute("order.total", 99.99)
# Semantic conventions
span.set_attribute(SpanAttributes.HTTP_METHOD, "GET")
span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, 200)
span.set_attribute(SpanAttributes.DB_SYSTEM, "postgresql")
span = trace.get_current_span()
span.add_event("Cache lookup started")
span.add_event("Cache miss", {"cache.key": "user:123", "cache.type": "redis"})
from opentelemetry.trace import Status, StatusCode
span = trace.get_current_span()