OpenTelemetry Flask Instrumentation

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

The OpenTelemetry Flask Instrumentation library provides automatic tracing for Flask applications, building upon the OpenTelemetry WSGI middleware to track web requests. It captures Flask-specific features like using URL rule patterns as span names and setting the `http.route` attribute. This package is part of the `opentelemetry-python-contrib` project, which generally maintains a monthly release cadence, and its individual packages are typically in beta status.

pip install opentelemetry-api opentelemetry-sdk opentelemetry-instrumentation-flask opentelemetry-exporter-otlp
error ModuleNotFoundError: No module named 'opentelemetry.instrumentation.flask'
cause This error occurs when the `opentelemetry-instrumentation-flask` package is not installed in your Python environment or is not accessible.
fix
Install the package using pip: pip install opentelemetry-instrumentation-flask
error Flask debug mode reloader breaks instrumentation
cause Flask's debug mode reloader spawns a child process which can lead to OpenTelemetry being initialized twice or not at all in the child process, resulting in duplicate or missing traces/spans.
fix
Disable the Flask reloader during development by setting debug=True, use_reloader=False in app.run(), or guard OpenTelemetry initialization with if os.environ.get("WERKZEUG_RUN_MAIN") == "true":.
error opentelemetry-instrument fails to load flask instrumentation if werkzeug==3.0.0
cause This problem arises from version incompatibility where `opentelemetry-instrumentation-flask` (especially older versions) might expect `Werkzeug<3.0.0` while a newer Flask version pulls in `Werkzeug==3.0.0`, causing the instrumentation to silently fail or not load.
fix
Ensure compatible versions of Flask and Werkzeug are installed, typically by pinning Flask to a version below 3.0.0 if the instrumentation package has not yet officially added support for Flask 3.0.0 and its Werkzeug dependency. Check the opentelemetry-instrumentation-flask documentation for supported versions.
error application not sending any traces
cause Traces might not appear due to incorrect OpenTelemetry SDK initialization, missing or misconfigured environment variables (e.g., `OTEL_EXPORTER_OTLP_ENDPOINT`, `OTEL_SERVICE_NAME`), or network connectivity issues preventing the exporter from reaching the telemetry backend.
fix
Verify that the OpenTelemetry SDK, tracer provider, and exporters are properly initialized before your application code runs. Double-check all relevant environment variables for correct values and ensure network connectivity to your observability backend. Add a ConsoleSpanExporter during debugging to confirm spans are being generated locally.
breaking This instrumentation package is currently in beta (`0.x.x`), indicating that its API and behavior may change in future releases without strictly adhering to semantic versioning until a stable `1.0` release.
fix Review changelogs carefully when upgrading. Be prepared for potential API changes and adjust your code accordingly.
gotcha Flask's debug mode, which uses a reloader, can conflict with OpenTelemetry's instrumentation process, leading to duplicate spans or no instrumentation. This often occurs when `app.run(debug=True)` is used directly.
fix For development with tracing, run Flask using `flask run --no-debugger --no-reloader` or explicitly set `debug=False` in `app.run()`. In production, use WSGI servers like Gunicorn or uWSGI, which typically don't use the reloader.
gotcha When manually instrumenting, `FlaskInstrumentor().instrument_app(app)` must be called *after* the Flask application object (`app`) has been created and typically after configuring all blueprints, but *before* the application starts serving requests. Also, the global `TracerProvider` must be set up *before* instrumentation is applied.
fix Ensure `trace.set_tracer_provider(provider)` is called early in your application's lifecycle, and `FlaskInstrumentor().instrument_app(app)` is called after your `app` is initialized and configured but before `app.run()` or a WSGI server takes over.
gotcha When using `opentelemetry-instrument` CLI for auto-instrumentation, Flask's development server with the reloader enabled (`--debug` or `FLASK_DEBUG=1`) is not supported and will lead to broken instrumentation. The CLI relies on patching modules once.
fix Run your Flask application without the reloader when using `opentelemetry-instrument`, e.g., `opentelemetry-instrument flask run --no-debugger --no-reloader`.
deprecated Older versions of Flask instrumentation (`<0.45b0`) did not include the HTTP method in the span name. This was changed to `HTTP {method} {route}` for better semantic convention compliance.
fix Upgrade to `opentelemetry-instrumentation-flask` version `0.45b0` or newer to align with updated semantic conventions. Be aware of potential changes in how your observability backend groups or displays traces if you were relying on the older span naming.
breaking The `flask` package, which is a required dependency, is not installed. This prevents `opentelemetry-instrumentation-flask` from being used as it cannot find the Flask application to instrument.
fix Ensure that `flask` is installed in your environment, typically via `pip install flask`.
gotcha The `opentelemetry-instrumentation-flask` library requires the `flask` package to be installed in your environment. Failure to install Flask will result in a `ModuleNotFoundError` when attempting to import Flask components.
fix Ensure `flask` is included in your project's dependencies and installed (e.g., `pip install flask`).
python os / libc status wheel install import disk mem side effects
3.10 alpine (musl) wheel - - 52.2M - broken
3.10 alpine (musl) - - - - - -
3.10 slim (glibc) wheel 5.7s - 50M - broken
3.10 slim (glibc) - - - - - -
3.11 alpine (musl) wheel - - 55.7M - broken
3.11 alpine (musl) - - - - - -
3.11 slim (glibc) wheel 4.9s - 54M - broken
3.11 slim (glibc) - - - - - -
3.12 alpine (musl) wheel - - 47.3M - broken
3.12 alpine (musl) - - - - - -
3.12 slim (glibc) wheel 4.0s - 45M - broken
3.12 slim (glibc) - - - - - -
3.13 alpine (musl) wheel - - 47.0M - broken
3.13 alpine (musl) - - - - - -
3.13 slim (glibc) wheel 4.0s - 45M - broken
3.13 slim (glibc) - - - - - -
3.9 alpine (musl) wheel - - 51.4M - broken
3.9 alpine (musl) - - - - - -
3.9 slim (glibc) wheel 6.4s - 49M - broken
3.9 slim (glibc) - - - - - -

This quickstart demonstrates how to instrument a basic Flask application using `FlaskInstrumentor`. It sets up a `TracerProvider` with a `BatchSpanProcessor` and `OTLPSpanExporter` to send traces. Run this script, then access `http://localhost:5000/` or `http://localhost:5000/data` to generate traces. Ensure an OpenTelemetry Collector is running and configured to receive OTLP/HTTP traces at the specified endpoint.

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 BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.flask import FlaskInstrumentor

# Configure OpenTelemetry SDK
# Ensure these environment variables are set for your OTLP collector
otlp_endpoint = os.environ.get('OTEL_EXPORTER_OTLP_ENDPOINT', 'http://localhost:4318/v1/traces')
service_name = os.environ.get('OTEL_SERVICE_NAME', 'my-flask-app')

resource = Resource.create({
    "service.name": service_name,
    "service.version": "1.0.0"
})

provider = TracerProvider(resource=resource)
processor = BatchSpanProcessor(OTLPSpanExporter(endpoint=otlp_endpoint))
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)

app = Flask(__name__)

# Instrument the Flask application
FlaskInstrumentor().instrument_app(app)

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

@app.route("/data")
def get_data():
    # Example of manual span within an instrumented route
    with trace.get_current_span().tracer.start_as_current_span("get-data-logic"):
        return {"value": 123}

if __name__ == "__main__":
    # IMPORTANT: Do not run with debug=True in production or with auto-instrumentation
    # due to Flask reloader issues with OpenTelemetry. For development, use
    # `flask run --no-debugger --no-reloader` or set `debug=False` for basic testing.
    print(f"Flask app running on http://127.0.0.1:5000 with OTLP exporter to {otlp_endpoint}")
    app.run(host="0.0.0.0", port=5000, debug=False)