{"id":911,"library":"opentelemetry-instrumentation-wsgi","title":"OpenTelemetry WSGI Instrumentation","description":"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.","status":"active","version":"0.61b0","language":"python","source_language":"en","source_url":"https://github.com/open-telemetry/opentelemetry-python-contrib","tags":["opentelemetry","wsgi","instrumentation","tracing","observability","flask","django"],"install":[{"cmd":"pip install opentelemetry-instrumentation-wsgi opentelemetry-sdk opentelemetry-exporter-otlp","lang":"bash","label":"Install with OTLP exporter"}],"dependencies":[{"reason":"Core OpenTelemetry API for tracing context and objects.","package":"opentelemetry-api"},{"reason":"Core OpenTelemetry SDK for configuring and processing telemetry data.","package":"opentelemetry-sdk"},{"reason":"Provides standard attribute names and values for HTTP spans.","package":"opentelemetry-semantic-conventions"}],"imports":[{"symbol":"OpenTelemetryMiddleware","correct":"from opentelemetry.instrumentation.wsgi import OpenTelemetryMiddleware"}],"quickstart":{"code":"import os\nfrom flask import Flask\nfrom opentelemetry import trace\nfrom opentelemetry.sdk.resources import Resource\nfrom opentelemetry.sdk.trace import TracerProvider\nfrom opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor\nfrom opentelemetry.instrumentation.wsgi import OpenTelemetryMiddleware\n\n# Configure OpenTelemetry SDK\nresource = Resource.create({\"service.name\": os.environ.get('OTEL_SERVICE_NAME', 'my-wsgi-app')})\ntracer_provider = TracerProvider(resource=resource)\nspan_processor = SimpleSpanProcessor(ConsoleSpanExporter())\ntracer_provider.add_span_processor(span_processor)\ntrace.set_tracer_provider(tracer_provider)\n\n# Your WSGI application (example using Flask)\napp = Flask(__name__)\n\n@app.route(\"/\")\ndef hello():\n    return \"Hello, world!\"\n\n# Wrap your WSGI application with the OpenTelemetry middleware\napp.wsgi_app = OpenTelemetryMiddleware(app.wsgi_app)\n\nif __name__ == \"__main__\":\n    # Run with a production WSGI server like Gunicorn in a real scenario\n    # For this example, running Flask's development server directly\n    app.run(debug=True)","lang":"python","description":"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`."},"warnings":[{"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`).","message":"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.","severity":"breaking","affected_versions":"< 0.30b0"},{"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.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"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.","message":"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.","severity":"gotcha","affected_versions":"All `0.x.y.bZ` versions"},{"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.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"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.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"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).","message":"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.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-05-12T21:14:39.821Z","next_check":"2026-06-27T00:00:00.000Z","problems":[{"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`.","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.","error":"ModuleNotFoundError: No module named 'opentelemetry.metrics'"},{"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.","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.","error":"KeyError: 'wsgi.url_scheme'"},{"fix":"Install the required instrumentation package(s) using pip; for WSGI, run `pip install opentelemetry-instrumentation-wsgi`.","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.","error":"ModuleNotFoundError: No module named 'opentelemetry.instrumentation'"},{"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.","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.","error":"Flask instrumentation not working / No traces appearing for Flask app with opentelemetry (often silent failure)"},{"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.","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.","error":"Django OpenTelemetry no traces / Django instrumentation silently failing"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":null,"quickstart_tag":null,"pypi_latest":"0.62b1","cli_name":"opentelemetry-instrument","install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.28,"mem_mb":8.8,"disk_size":"52.1M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.31,"mem_mb":8.8,"disk_size":"51.9M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":5.7,"import_time_s":0.24,"mem_mb":8.8,"disk_size":"50M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.2,"mem_mb":8.8,"disk_size":"50M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.41,"mem_mb":10,"disk_size":"55.6M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.47,"mem_mb":10,"disk_size":"55.4M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":5.3,"import_time_s":0.36,"mem_mb":10,"disk_size":"53M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.35,"mem_mb":10,"disk_size":"53M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.58,"mem_mb":12.5,"disk_size":"47.1M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.65,"mem_mb":12.5,"disk_size":"46.9M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":4.5,"import_time_s":0.6,"mem_mb":12.5,"disk_size":"45M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.6,"mem_mb":12.5,"disk_size":"45M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.24,"mem_mb":6.9,"disk_size":"46.9M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.25,"mem_mb":6.9,"disk_size":"46.5M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":4.2,"import_time_s":0.23,"mem_mb":6.9,"disk_size":"45M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.24,"mem_mb":6.9,"disk_size":"44M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.22,"mem_mb":7.9,"disk_size":"51.3M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.26,"mem_mb":7.9,"disk_size":"51.2M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":6.4,"import_time_s":0.22,"mem_mb":7.9,"disk_size":"49M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.22,"mem_mb":7.9,"disk_size":"49M"}]},"quickstart_checks":{"last_tested":"2026-04-24","tag":null,"tag_description":null,"results":[{"runtime":"python:3.10-alpine","exit_code":1},{"runtime":"python:3.10-slim","exit_code":1},{"runtime":"python:3.11-alpine","exit_code":1},{"runtime":"python:3.11-slim","exit_code":1},{"runtime":"python:3.12-alpine","exit_code":1},{"runtime":"python:3.12-slim","exit_code":1},{"runtime":"python:3.13-alpine","exit_code":1},{"runtime":"python:3.13-slim","exit_code":1},{"runtime":"python:3.9-alpine","exit_code":1},{"runtime":"python:3.9-slim","exit_code":1}]}}