OpenTelemetry WSGI Instrumentation

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

This library provides a WSGI middleware that can be used on any WSGI framework (such as Django, Flask, or Web.py) to track requests timing through OpenTelemetry. It is part of the `opentelemetry-python-contrib` repository and is released frequently alongside the main OpenTelemetry Python SDK, often in beta versions.

pip install opentelemetry-instrumentation-wsgi opentelemetry-sdk opentelemetry-exporter-otlp
error ModuleNotFoundError: No module named 'opentelemetry.metrics'
cause This error often occurs because the core OpenTelemetry SDK, specifically the part providing metric functionalities, is either not installed or is an outdated version that lacks the 'opentelemetry.metrics' module.
fix
Ensure that the opentelemetry-sdk package is installed and up-to-date in your Python environment. You can install it using pip install opentelemetry-sdk.
error KeyError: 'wsgi.url_scheme'
cause This issue commonly arises in Django applications, especially when using ASGI servers or specific proxy configurations, because the 'wsgi.url_scheme' key, expected by the WSGI instrumentation, is missing from the WSGI environment dictionary.
fix
Update opentelemetry-instrumentation-django to the latest version that supports ASGI, or ensure your WSGI server (e.g., Gunicorn with Uvicorn worker) correctly populates the wsgi.url_scheme in the WSGI environment.
error ModuleNotFoundError: No module named 'opentelemetry.instrumentation'
cause This error indicates that the specific `opentelemetry-instrumentation-wsgi` package or other necessary instrumentation packages (e.g., `opentelemetry-instrumentation-flask`, `opentelemetry-instrumentation-django`) are not installed in the Python environment where your application is running.
fix
Install the required instrumentation package(s) using pip; for WSGI, run pip install opentelemetry-instrumentation-wsgi.
error Flask instrumentation not working / No traces appearing for Flask app with opentelemetry (often silent failure)
cause This frequently happens due to version incompatibilities between `opentelemetry-instrumentation-flask` and `Werkzeug` (Flask's underlying WSGI utility), particularly with `werkzeug==3.0.0`, or when Flask's debug mode reloader interferes with the instrumentation process.
fix
Ensure your opentelemetry-instrumentation-flask version is compatible with your Werkzeug version (update both if necessary), or disable Flask's debug reloader by running app.run(debug=False) in development.
error Django OpenTelemetry no traces / Django instrumentation silently failing
cause The OpenTelemetry Django instrumentation often fails silently to produce traces if the `DJANGO_SETTINGS_MODULE` environment variable is not set or is not accessible before the instrumentation is applied, preventing Django's core from being properly initialized for patching.
fix
Explicitly set os.environ['DJANGO_SETTINGS_MODULE'] to your project's settings module before calling DjangoInstrumentor().instrument() or applying the OpenTelemetryMiddleware, typically in your wsgi.py file or Gunicorn configuration.
breaking In earlier versions (e.g., prior to `0.30b0`), `opentelemetry-instrumentation-wsgi` added `http.method` to the `span.name`. If your observability dashboards or alerts rely on a specific span name format from older versions, this change might break them.
fix Review your monitoring and alerting configurations to ensure they are compatible with the current OpenTelemetry semantic conventions for HTTP span naming, which typically uses the route template for the span name (e.g., `HTTP GET /users/:id`).
gotcha Capturing custom HTTP request and response headers requires setting specific environment variables (e.g., `OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST` and `OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE`). For request headers, names are case-insensitive and hyphens (`-`) are replaced by underscores (`_`) when setting the environment variable (e.g., `Custom-Header` becomes `CUStom_Header`). For response headers, names are case-insensitive.
fix Set environment variables like `OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST=Content-Type,X-Request-ID` and `OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE=Content-Type,X-Response-ID` to capture desired headers. Pay close attention to the naming convention for request headers.
gotcha As indicated by the `0.x.y.bZ` versioning (e.g., `0.61b0`), this library is currently in beta. This means that its API and behavior might not be fully stable and could be subject to breaking changes in future releases without a major version bump.
fix Be prepared for potential API adjustments in future updates. Regularly consult the official `opentelemetry-python-contrib` changelog for details on specific changes when upgrading.
gotcha The `opentelemetry-instrumentation-wsgi` package provides middleware, but it does not automatically configure the OpenTelemetry SDK (TracerProvider, SpanProcessor, Exporter). You must manually configure the OpenTelemetry SDK in your application's entry point for traces to be collected and exported.
fix Ensure you explicitly set up a `TracerProvider`, add `SpanProcessor`(s), and register an `Exporter` (e.g., `OTLPSpanExporter` for the OpenTelemetry Collector) before your WSGI application starts handling requests. Refer to the OpenTelemetry Python SDK documentation for full configuration details.
gotcha The test script failed due to a `ModuleNotFoundError` for `flask`, indicating that required dependencies for the test environment were not installed. This prevents the library's instrumentation from being tested.
fix Ensure all necessary test dependencies (e.g., `flask`, `opentelemetry-instrumentation-wsgi` itself, and its dependencies) are correctly installed in the test environment before running the tests.
gotcha The `opentelemetry-instrumentation-wsgi` library instruments existing WSGI applications. To properly test or run your instrumented application, ensure all its core dependencies (e.g., web frameworks like Flask, Django, etc.) are installed in the environment.
fix Ensure all application-specific dependencies required by your WSGI application are installed in your environment (e.g., `pip install Flask` if your application is built with Flask, or `pip install Django` if it's Django).
python os / libc status wheel install import disk
3.10 alpine (musl) wheel - 0.28s 52.1M
3.10 alpine (musl) - - 0.31s 51.9M
3.10 slim (glibc) wheel 5.7s 0.24s 50M
3.10 slim (glibc) - - 0.20s 50M
3.11 alpine (musl) wheel - 0.41s 55.6M
3.11 alpine (musl) - - 0.47s 55.4M
3.11 slim (glibc) wheel 5.3s 0.36s 53M
3.11 slim (glibc) - - 0.35s 53M
3.12 alpine (musl) wheel - 0.58s 47.1M
3.12 alpine (musl) - - 0.65s 46.9M
3.12 slim (glibc) wheel 4.5s 0.60s 45M
3.12 slim (glibc) - - 0.60s 45M
3.13 alpine (musl) wheel - 0.24s 46.9M
3.13 alpine (musl) - - 0.25s 46.5M
3.13 slim (glibc) wheel 4.2s 0.23s 45M
3.13 slim (glibc) - - 0.24s 44M
3.9 alpine (musl) wheel - 0.22s 51.3M
3.9 alpine (musl) - - 0.26s 51.2M
3.9 slim (glibc) wheel 6.4s 0.22s 49M
3.9 slim (glibc) - - 0.22s 49M

This example demonstrates how to set up basic OpenTelemetry tracing for a Flask application using the `opentelemetry-instrumentation-wsgi` middleware. It configures a `TracerProvider` with a `ConsoleSpanExporter` to print traces to the console, then wraps the Flask app's WSGI application with `OpenTelemetryMiddleware`.

import os
from flask import Flask
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.wsgi import OpenTelemetryMiddleware

# Configure OpenTelemetry SDK
resource = Resource.create({"service.name": os.environ.get('OTEL_SERVICE_NAME', 'my-wsgi-app')})
tracer_provider = TracerProvider(resource=resource)
span_processor = SimpleSpanProcessor(ConsoleSpanExporter())
tracer_provider.add_span_processor(span_processor)
trace.set_tracer_provider(tracer_provider)

# Your WSGI application (example using Flask)
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello, world!"

# Wrap your WSGI application with the OpenTelemetry middleware
app.wsgi_app = OpenTelemetryMiddleware(app.wsgi_app)

if __name__ == "__main__":
    # Run with a production WSGI server like Gunicorn in a real scenario
    # For this example, running Flask's development server directly
    app.run(debug=True)