OpenTelemetry Asyncio Instrumentation
The `opentelemetry-instrumentation-asyncio` package provides OpenTelemetry tracing and metrics for applications built with Python's `asyncio` library. It enables the collection of duration and counts for coroutines and futures, even if no explicit tracing is configured. This library is part of the `opentelemetry-python-contrib` project, with the current version being `0.62b0`, indicating it is actively developed and in a pre-release (beta) stage.
Warnings
- beta As a beta release (`0.62b0`), the API and behavior of `opentelemetry-instrumentation-asyncio` are subject to change without strict adherence to semantic versioning. Breaking changes may occur in future minor or patch releases until a stable `1.0.0` version is reached.
- gotcha Granular control over which `asyncio` components are instrumented often relies on environment variables. Forgetting to set these or misconfiguring them can lead to unexpected tracing behavior or a lack of telemetry.
- gotcha OpenTelemetry's context propagation in Python relies on `contextvars`, which works seamlessly with `asyncio`'s task-local context across `await` boundaries. However, improper use of `asyncio` features or manually managing contexts can break trace relationships.
- gotcha When deploying `asyncio` applications with pre-forking servers (e.g., Gunicorn with multiple worker processes), OpenTelemetry's SDK components, particularly those involving background threads (like `PeriodicExportingMetricReader`), can experience inconsistencies or deadlocks after forking. This is a general OpenTelemetry Python SDK issue.
Install
-
pip install opentelemetry-instrumentation-asyncio opentelemetry-sdk opentelemetry-exporter-otlp
Imports
- AsyncioInstrumentor
from opentelemetry.instrumentation.asyncio import AsyncioInstrumentor
Quickstart
import asyncio
import os
from opentelemetry import trace
from opentelemetry.sdk.resources import Resource
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.instrumentation.asyncio import AsyncioInstrumentor
# Configure OpenTelemetry TracerProvider
resource = Resource.create({"service.name": "asyncio-example"})
provider = TracerProvider(resource=resource)
# Use os.environ.get for OTLP endpoint in quickstart
otlp_exporter = OTLPSpanExporter(
endpoint=os.environ.get('OTEL_EXPORTER_OTLP_ENDPOINT_GRPC', 'http://localhost:4317'),
insecure=True # Set to False for production with HTTPS
)
span_processor = BatchSpanProcessor(otlp_exporter)
provider.add_span_processor(span_processor)
trace.set_tracer_provider(provider)
# Instrument asyncio
AsyncioInstrumentor().instrument()
tracer = trace.get_tracer(__name__)
async def some_async_task(task_id: int):
with tracer.start_as_current_span(f"some_async_task-{task_id}"):
print(f"Task {task_id}: Starting...")
await asyncio.sleep(0.05) # Simulated async I/O
print(f"Task {task_id}: Done.")
async def main():
print("Main application starting...")
await asyncio.gather(
some_async_task(1),
some_async_task(2),
some_async_task(3)
)
print("Main application finished.")
if __name__ == "__main__":
# Example of configuring tracing for specific coroutines via environment variable
# os.environ['OTEL_PYTHON_ASYNCIO_COROUTINE_NAMES_TO_TRACE'] = 'some_async_task'
asyncio.run(main())
# Ensure all spans are exported before exiting
provider.shutdown()