OpenTelemetry Threading Instrumentation
This library provides instrumentation for Python's built-in `threading` module, ensuring that OpenTelemetry trace context is correctly propagated across threads. It does not produce telemetry data on its own but facilitates the linking of spans across different threads. Currently in beta (version 0.61b0), it is part of the `opentelemetry-python-contrib` project, which maintains a frequent release cadence.
Warnings
- gotcha This instrumentation only handles context propagation for `threading.Thread`. It does NOT automatically create spans or metrics. You must still configure a `TracerProvider` and create spans (either manually or via other instrumentations) to see any telemetry data. [5]
- breaking Directly calling `Thread.run()` instead of `Thread.start()` after instrumentation can lead to an `AttributeError` (e.g., `AttributeError: 'Thread' object has no attribute '_otel_context'`) and broken context propagation. [4]
- gotcha This library is currently in beta (`0.61b0`). Beta packages may have unstable APIs, and breaking changes can occur between minor versions. Always consult release notes when upgrading.
- gotcha While this instrumentation aims to solve context propagation, complex multi-threading patterns (especially with `concurrent.futures.ThreadPoolExecutor` in older Python versions or custom thread pool implementations) might still experience broken context. Python 3.12+ `contextvars` improve `threading.Thread` propagation, but explicit context management might still be needed in some edge cases. [1, 6]
Install
-
pip install opentelemetry-instrumentation-threading opentelemetry-sdk opentelemetry-exporter-console
Imports
- ThreadingInstrumentor
from opentelemetry.instrumentation.threading import ThreadingInstrumentor
Quickstart
import threading
from opentelemetry import trace
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor
from opentelemetry.instrumentation.threading import ThreadingInstrumentor
# 1. Set up OpenTelemetry TracerProvider
resource = Resource.create({"service.name": "my-threaded-app"})
provider = TracerProvider(resource=resource)
processor = SimpleSpanProcessor(ConsoleSpanExporter())
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
# 2. Instrument the threading module
ThreadingInstrumentor().instrument()
tracer = trace.get_tracer(__name__)
def threaded_task():
"A function to be run in a separate thread."
with tracer.start_as_current_span("child-thread-span") as child_span:
print(f"Inside threaded_task. Active span: {child_span.context.span_id:x}")
# Simulate work
import time
time.sleep(0.1)
if __name__ == "__main__":
with tracer.start_as_current_span("main-thread-span") as parent_span:
print(f"Main thread. Active span: {parent_span.context.span_id:x}")
my_thread = threading.Thread(target=threaded_task)
my_thread.start()
my_thread.join()
print("Application finished.")
# Ensure all spans are exported before exiting
provider.shutdown()