Skip to content

fastapi: fix wrapping of middlewares#3012

Merged
xrmx merged 47 commits intoopen-telemetry:mainfrom
adriangb:fix-asgi-middleware
May 20, 2025
Merged

fastapi: fix wrapping of middlewares#3012
xrmx merged 47 commits intoopen-telemetry:mainfrom
adriangb:fix-asgi-middleware

Conversation

@adriangb
Copy link
Copy Markdown
Contributor

@adriangb adriangb commented Nov 15, 2024

MRE:

import anyio
import fastapi
import httpx
import uvicorn
from opentelemetry import trace
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter

resource = Resource(attributes={SERVICE_NAME: '🐛'})

traceProvider = TracerProvider(resource=resource)
processor = BatchSpanProcessor(ConsoleSpanExporter())
traceProvider.add_span_processor(processor)
trace.set_tracer_provider(traceProvider)

app = fastapi.FastAPI()

@app.get('/ok')
async def ok() -> int:
    return 123

@app.get('/error')
async def error() -> int:
    raise Exception('An error occurred!')

FastAPIInstrumentor.instrument_app(app)


async def main() -> None:
    config = uvicorn.Config(app=app, port=9999, log_config=None)
    server = uvicorn.Server(config)

    async with anyio.create_task_group() as tg:
        tg.start_soon(server.serve)
        await anyio.sleep(1)  # Wait for the server to start
        async with httpx.AsyncClient(base_url='http://localhost:9999') as client:
            response = await client.get('/ok')
            assert response.status_code == 200, f'{response.status_code}: {response.text}'
            response = await client.get('/error')
            assert response.status_code == 500,  f'{response.status_code}: {response.text}'
            tg.cancel_scope.cancel()


if __name__ == '__main__':
    anyio.run(main)

With this change it shows up properly

Run this and you'll see that there is no "http.status_code": 500 in the logs.

@adriangb adriangb requested a review from a team as a code owner November 15, 2024 15:35
Copy link
Copy Markdown
Contributor

@codefromthecrypt codefromthecrypt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice comment and test!

@xrmx
Copy link
Copy Markdown
Contributor

xrmx commented Nov 19, 2024

@adriangb Please take a look at the failing tests

@Kludex
Copy link
Copy Markdown
Member

Kludex commented Nov 20, 2024

fixes #795

@adriangb adriangb force-pushed the fix-asgi-middleware branch from e406be8 to 3d8dd4f Compare November 27, 2024 00:29
@adriangb adriangb requested a review from lzchen November 27, 2024 00:35
@adriangb
Copy link
Copy Markdown
Contributor Author

adriangb commented Nov 27, 2024

@adriangb Please take a look at the failing tests

@xrmx see #3012 (comment)

@adriangb
Copy link
Copy Markdown
Contributor Author

@Kludex could you update the Starlette instrumentations after we finish up this PR? I'm assuming they have the same bugs.

@Kludex
Copy link
Copy Markdown
Member

Kludex commented Nov 27, 2024

The pipeline has been running for some hours... 👀

@vanyae-cqc
Copy link
Copy Markdown

vanyae-cqc commented Nov 27, 2024

Hello! Just wondering if you'd expect this to enable getting the trace_id in a FastAPI exception_handler?

This has been discussed in more detail here: open-telemetry/opentelemetry-python#3477, but currently OpenTelemetryMiddleware's context seems to be removed by the time an exception gets to the ServerErrorMiddleware.

Would be great to enable users to report back a trace_id when they get an unexpected 500 status response. Have tried to verify this PR provides this by running it locally but haven't had any luck - could be something wrong in my setup though.

[Update]: Have now verified this achieves the above behaviour - this fix is greatly appreciated!

@adriangb
Copy link
Copy Markdown
Contributor Author

Fixed issue with test shutdown hanging. All checks passing now.

@adriangb adriangb requested a review from xrmx November 27, 2024 16:20
Copy link
Copy Markdown
Contributor

@xrmx xrmx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I trust you on the fastapi knowledge but would be nice to add a test to check that the change does what it's supposed to fix

@adriangb
Copy link
Copy Markdown
Contributor Author

adriangb commented Dec 3, 2024

Ups looks like that got lost, I had added it in 4220b09

@adriangb adriangb force-pushed the fix-asgi-middleware branch from 7497d32 to f825c76 Compare December 3, 2024 16:04
@adriangb
Copy link
Copy Markdown
Contributor Author

adriangb commented Dec 3, 2024

Added back and updated the branch

@xrmx
Copy link
Copy Markdown
Contributor

xrmx commented Dec 4, 2024

ICYMI the added test is red

@adriangb
Copy link
Copy Markdown
Contributor Author

adriangb commented Dec 4, 2024

Thanks. I hadn't understood how the tests are parametrized and that _create_app is overridden in a subclass.

@adriangb
Copy link
Copy Markdown
Contributor Author

adriangb commented Dec 13, 2024

@xrmx @lzchen can we get this merged please? I believe this is a major issue that deserves attention.

@adriangb adriangb requested review from lzchen and xrmx December 13, 2024 15:24
@lzchen
Copy link
Copy Markdown
Contributor

lzchen commented Jan 10, 2025

@adriangb

I believe I still have an outstanding question

@adriangb
Copy link
Copy Markdown
Contributor Author

@adriangb

I believe I still have an outstanding question

I've answered it. Please re-review.

@outergod
Copy link
Copy Markdown
Contributor

Anything else in the way of merging now?

Copy link
Copy Markdown
Member

@emdneto emdneto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adriangb I fixed the changelog conflict and added this note:
opentelemetry-instrumentation-fastapi: Drop support for FastAPI versions earlier than 0.92

Signed-off-by: emdneto <[email protected]>
Copy link
Copy Markdown
Member

@emdneto emdneto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@outergod @adriangb can you please fix the conflict?

@adriangb
Copy link
Copy Markdown
Contributor Author

I gave it a shot, lets see what CI says

@xrmx
Copy link
Copy Markdown
Contributor

xrmx commented May 19, 2025

@adriangb we merged a PR stopping using SpanAttributes in favor of semconv._incubating.attributes.*

@adriangb
Copy link
Copy Markdown
Contributor Author

adriangb commented May 19, 2025

Ok sounds like this 2 year old PR now needs another round of adjusting for upstream changes 😢. Any chance you can make the change here since you're familiar with the implications?

@xrmx xrmx enabled auto-merge (squash) May 20, 2025 13:17
@alexmojaki
Copy link
Copy Markdown
Contributor

Does @codefromthecrypt need to approve?

@xrmx xrmx merged commit 4d6893e into open-telemetry:main May 20, 2025
720 checks passed
@github-project-automation github-project-automation Bot moved this from Approved PRs to Done in Python PR digest May 20, 2025
@xrmx
Copy link
Copy Markdown
Contributor

xrmx commented May 20, 2025

@alexmojaki github was saying so but your approval was good enough 😅

@alexmojaki
Copy link
Copy Markdown
Contributor

Thanks everyone for getting this across!

@adriangb
Copy link
Copy Markdown
Contributor Author

Amazing folks thanks so much!!

@outergod
Copy link
Copy Markdown
Contributor

Finally! Thanks to everyone involved, especially @adriangb!

Comment on lines +320 to +331
if isinstance(
inner_server_error_middleware, ServerErrorMiddleware
): # usually true
outer_server_error_middleware = ServerErrorMiddleware(
app=otel_middleware,
)
else:
# Something else seems to have patched things, or maybe Starlette changed.
# Just create a default ServerErrorMiddleware.
outer_server_error_middleware = ServerErrorMiddleware(
app=otel_middleware
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these branches are the same now

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel stupid for not realizing this when I changed the code

sightseeker added a commit to sightseeker/opentelemetry-python-contrib that referenced this pull request Mar 11, 2026
* fastapi: fix wrapping of middlewares

* fix import, super

* add test

* changelog

* lint

* lint

* fix

* ci

* fix wip

* fix

* fix

* lint

* lint

* Exit?

* Update test_fastapi_instrumentation.py

Co-authored-by: Riccardo Magliocchetti <[email protected]>

* remove break

* fix

* remove dunders

* add test

* lint

* add endpoint to class

* fmt

* pr feedback

* move type ignores

* fix sphinx?

* Update CHANGELOG.md

* update fastapi versions

* fix?

* generate

* stop passing on user-supplied error handler

This prevents potential side effects, such as logging, to be executed
more than once per request handler exception.

* fix ci

Signed-off-by: emdneto <[email protected]>

* fix ruff

Signed-off-by: emdneto <[email protected]>

* remove unused funcs

Co-authored-by: Emídio Neto <[email protected]>

* fix lint,ruff

Signed-off-by: emdneto <[email protected]>

* fix changelog

Signed-off-by: emdneto <[email protected]>

* add changelog note

Signed-off-by: emdneto <[email protected]>

* fix conflicts with main

Signed-off-by: emdneto <[email protected]>

---------

Signed-off-by: emdneto <[email protected]>
Co-authored-by: Riccardo Magliocchetti <[email protected]>
Co-authored-by: Alexander Dorn <[email protected]>
Co-authored-by: Emídio Neto <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

10 participants