Skip to content

FastAPI/Starlette - Inconsistent placement of the OpenTelemetryMiddlewareΒ #795

@phillipuniverse

Description

@phillipuniverse

The Starlette application class (which is the parent of the FastAPI application class) hardcodes the ServerErrorMiddleware to appear as the very first middleware. This means that if there is an error in some downstream middleware, handling the request with ServerErrorMiddleware will not have an active trace.

Also, if you happen to do something like this:

app = FastAPI(...)

app.add_middleware(...)
app.add_middlware(....)

The additional middleware added after the first __init__ of FastAPI will also not have an active trace established.

There is a relatively easy way around this to ensure that the OpenTelemetry middleware is always first:

class _InstrumentedFastAPI(fastapi.FastAPI):
    _tracer_provider = None
    _excluded_urls = None
    _server_request_hook: _ServerRequestHookT = None
    _client_request_hook: _ClientRequestHookT = None
    _client_response_hook: _ClientResponseHookT = None

    def build_middleware_stack(self) -> ASGIApp:
        original_mw_app = super().build_middleware_stack()
        return OpenTelemetryMiddleware(
            original_mw_app,
            excluded_urls=_InstrumentedFastAPI._excluded_urls,
            default_span_details=_get_route_details,
            server_request_hook=_InstrumentedFastAPI._server_request_hook,
            client_request_hook=_InstrumentedFastAPI._client_request_hook,
            client_response_hook=_InstrumentedFastAPI._client_response_hook,
            tracer_provider=_InstrumentedFastAPI._tracer_provider,
        )

FastAPI version - 0.70.0
Starlette version - 0.16.0
Python version - 3.9

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions