OpenTelemetry Flask Instrumentation
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.
Warnings
- 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.
- 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.
- 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.
- 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.
- 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.
Install
-
pip install opentelemetry-api opentelemetry-sdk opentelemetry-instrumentation-flask opentelemetry-exporter-otlp
Imports
- FlaskInstrumentor
from opentelemetry.instrumentation.flask import FlaskInstrumentor
Quickstart
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)