OpenTelemetry Threading Instrumentation

raw JSON →
0.61b0 verified Tue May 12 auth: no python install: stale

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.

pip install opentelemetry-instrumentation-threading opentelemetry-sdk opentelemetry-exporter-console
error AttributeError: 'Thread' object has no attribute '_otel_context'
cause This error occurs when a `threading.Thread`'s `run()` method is called directly instead of `start()` after `opentelemetry-instrumentation-threading` has instrumented the threading module. The instrumentation expects `start()` to be called to properly set up the OpenTelemetry context.
fix
Always call thread.start() to begin a thread's execution, which correctly invokes the instrumented run() method after context initialization. Do not call thread.run() directly.
error ModuleNotFoundError: No module named 'opentelemetry.instrumentation.threading'
cause This error indicates that the `opentelemetry-instrumentation-threading` package is either not installed, or Python cannot find it in the current environment's `PYTHONPATH`.
fix
Install the package using pip: pip install opentelemetry-instrumentation-threading. Ensure that your application is running in the same Python environment where the package was installed.
error ImportError: cannot import name 'instrument' from 'opentelemetry.instrumentation.threading'
cause Developers sometimes incorrectly try to import a function named `instrument` directly from the `opentelemetry.instrumentation.threading` module, when the correct approach is to instantiate `ThreadingInstrumentor` and then call its `instrument()` method.
fix
Import ThreadingInstrumentor and then call its instrument() method to apply the instrumentation: from opentelemetry.instrumentation.threading import ThreadingInstrumentor ThreadingInstrumentor().instrument()
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]
fix Ensure `opentelemetry.sdk.trace.TracerProvider` is configured and active, and use other instrumentations (e.g., `requests`, `flask`) or manual tracing to generate spans.
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]
fix Always use `my_thread.start()` to begin thread execution after creating a `threading.Thread` instance. Avoid calling the `run()` method directly.
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.
fix Pin your dependency to a specific beta version (e.g., `opentelemetry-instrumentation-threading==0.61b0`) and carefully review the `CHANGELOG` before upgrading to a new beta release.
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]
fix If traces appear broken, debug context propagation. Tools like `opentelemetry.context.get_current()` and `opentelemetry.context.attach()` can be used for manual context management in problematic areas, though this instrumentation aims to automate it for `threading.Thread`.
breaking Attempting to install a non-existent or incorrectly named OpenTelemetry package, such as `opentelemetry-exporter-console`, will result in `pip` installation errors (e.g., `No matching distribution found`). The console exporter is typically provided directly by the `opentelemetry-sdk` and is not a separate PyPI package.
fix Review your `pip` install commands and `requirements.txt` to ensure all OpenTelemetry packages are correctly named and available on PyPI. For console output, utilize the `ConsoleSpanExporter` class directly from `opentelemetry.sdk.trace.export` instead of trying to install a dedicated `opentelemetry-exporter-console` package.
gotcha The test environment failed to find or install `opentelemetry-exporter-console`. This package is frequently used for demonstrating or testing OpenTelemetry functionality, and its absence can prevent tests from executing or telemetry data from being exported and observed.
fix Ensure that `opentelemetry-exporter-console` is correctly specified in the test environment's `requirements.txt` or explicitly installed. Verify that the Python version and environment (e.g., Alpine Linux) are compatible with available distributions of the exporter, providing necessary build tools or using a Python version with pre-built wheels if applicable.
python os / libc status wheel install import disk
3.10 alpine (musl) build_error - - - -
3.10 alpine (musl) - - - -
3.10 slim (glibc) build_error - 1.7s - -
3.10 slim (glibc) - - - -
3.11 alpine (musl) build_error - - - -
3.11 alpine (musl) - - - -
3.11 slim (glibc) build_error - 1.5s - -
3.11 slim (glibc) - - - -
3.12 alpine (musl) build_error - - - -
3.12 alpine (musl) - - - -
3.12 slim (glibc) build_error - 1.4s - -
3.12 slim (glibc) - - - -
3.13 alpine (musl) build_error - - - -
3.13 alpine (musl) - - - -
3.13 slim (glibc) build_error - 1.4s - -
3.13 slim (glibc) - - - -
3.9 alpine (musl) build_error - - - -
3.9 alpine (musl) - - - -
3.9 slim (glibc) build_error - 1.8s - -
3.9 slim (glibc) - - - -

This quickstart demonstrates how to initialize OpenTelemetry with console export, then apply the `ThreadingInstrumentor`. A parent span is created in the main thread, and a child span is created within a function executed by `threading.Thread`. The instrumentation ensures that the child span correctly references the parent span, illustrating proper context propagation across thread boundaries.

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()