sentry-python icon indicating copy to clipboard operation
sentry-python copied to clipboard

Integration for FastAPI

Open untitaker opened this issue 3 years ago • 24 comments

FastAPI is just Starlette which is just ASGI. We have an ASGI integration that should work fine. However, it would be nice to have deeper integration than we currently provide, particularly around Performance monitoring.

Please vote with 👍 on this post if you're interested in this. I would also like to hear what currently doesn't work out well with the ASGI middleware applied to your FastAPI app.

untitaker avatar Sep 22 '20 09:09 untitaker

So when I use the following with FastAPI, I get this error on Azure.

sentry_sdk.init(
    dsn=settings.SENTRY_DSN,
    integrations=[SqlalchemyIntegration(), CeleryIntegration()],
    debug=True,
    environment=os.environ.get("ENVIRONMENT"),
    send_default_pii=True,
)
2020-10-15T17:41:52.216444242Z  [sentry] DEBUG: Setting up previously not enabled integration logging
2020-10-15T17:41:52.217021159Z  [sentry] DEBUG: Setting up previously not enabled integration stdlib
2020-10-15T17:41:52.217673279Z  [sentry] DEBUG: Setting up previously not enabled integration excepthook
2020-10-15T17:41:52.218227395Z  [sentry] DEBUG: Setting up previously not enabled integration dedupe
2020-10-15T17:41:52.218834813Z  [sentry] DEBUG: Setting up previously not enabled integration atexit
2020-10-15T17:41:52.220147152Z  [sentry] DEBUG: Setting up previously not enabled integration modules
2020-10-15T17:41:52.220648067Z  [sentry] DEBUG: Setting up previously not enabled integration argv
2020-10-15T17:41:52.221144581Z  [sentry] DEBUG: Setting up previously not enabled integration threading
2020-10-15T17:41:52.221644596Z  [sentry] DEBUG: Setting up previously not enabled integration flask
2020-10-15T17:41:52.275128278Z [2020-10-15 17:41:52 +0000] [42] [ERROR] Exception in worker process
2020-10-15T17:41:52.275217381Z Traceback (most recent call last):
2020-10-15T17:41:52.275233581Z   File "/antenv/lib/python3.8/site-packages/gunicorn/arbiter.py", line 583, in spawn_worker
2020-10-15T17:41:52.275241982Z     worker.init_process()
2020-10-15T17:41:52.275249082Z   File "/antenv/lib/python3.8/site-packages/uvicorn/workers.py", line 61, in init_process
2020-10-15T17:41:52.275256582Z     super(UvicornWorker, self).init_process()
2020-10-15T17:41:52.275263782Z   File "/antenv/lib/python3.8/site-packages/gunicorn/workers/base.py", line 119, in init_process
2020-10-15T17:41:52.275271583Z     self.load_wsgi()
2020-10-15T17:41:52.275278383Z   File "/antenv/lib/python3.8/site-packages/gunicorn/workers/base.py", line 144, in load_wsgi
2020-10-15T17:41:52.275299283Z     self.wsgi = self.app.wsgi()
2020-10-15T17:41:52.275306684Z   File "/antenv/lib/python3.8/site-packages/gunicorn/app/base.py", line 67, in wsgi
2020-10-15T17:41:52.275314484Z     self.callable = self.load()
2020-10-15T17:41:52.275321584Z   File "/antenv/lib/python3.8/site-packages/gunicorn/app/wsgiapp.py", line 49, in load
2020-10-15T17:41:52.275328884Z     return self.load_wsgiapp()
2020-10-15T17:41:52.275335584Z   File "/antenv/lib/python3.8/site-packages/gunicorn/app/wsgiapp.py", line 39, in load_wsgiapp
2020-10-15T17:41:52.275343085Z     return util.import_app(self.app_uri)
2020-10-15T17:41:52.275350285Z   File "/antenv/lib/python3.8/site-packages/gunicorn/util.py", line 358, in import_app
2020-10-15T17:41:52.275357685Z     mod = importlib.import_module(module)
2020-10-15T17:41:52.275364885Z   File "/opt/python/3.8.3/lib/python3.8/importlib/__init__.py", line 127, in import_module
2020-10-15T17:41:52.275372186Z     return _bootstrap._gcd_import(name[level:], package, level)
2020-10-15T17:41:52.275379486Z   File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
2020-10-15T17:41:52.275387086Z   File "<frozen importlib._bootstrap>", line 991, in _find_and_load
2020-10-15T17:41:52.275394186Z   File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
2020-10-15T17:41:52.275401586Z   File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
2020-10-15T17:41:52.275408987Z   File "<frozen importlib._bootstrap_external>", line 783, in exec_module
2020-10-15T17:41:52.275432787Z   File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
2020-10-15T17:41:52.275441188Z   File "/home/site/wwwroot/app/main.py", line 24, in <module>
2020-10-15T17:41:52.275448688Z     sentry_sdk.init(
2020-10-15T17:41:52.275455688Z   File "/antenv/lib/python3.8/site-packages/sentry_sdk/hub.py", line 106, in _init
2020-10-15T17:41:52.275462988Z     client = Client(*args, **kwargs)  # type: ignore
2020-10-15T17:41:52.275469688Z   File "/antenv/lib/python3.8/site-packages/sentry_sdk/client.py", line 86, in __init__
2020-10-15T17:41:52.275477089Z     self._init_impl()
2020-10-15T17:41:52.275486289Z   File "/antenv/lib/python3.8/site-packages/sentry_sdk/client.py", line 128, in _init_impl
2020-10-15T17:41:52.275493789Z     self.integrations = setup_integrations(
2020-10-15T17:41:52.275500789Z   File "/antenv/lib/python3.8/site-packages/sentry_sdk/integrations/__init__.py", line 119, in setup_integrations
2020-10-15T17:41:52.275508290Z     type(integration).setup_once()
2020-10-15T17:41:52.275515290Z   File "/antenv/lib/python3.8/site-packages/sentry_sdk/integrations/flask.py", line 75, in setup_once
2020-10-15T17:41:52.275522590Z     request_started.connect(_request_started)
2020-10-15T17:41:52.275529490Z   File "/opt/python/3.8.3/lib/python3.8/site-packages/flask/signals.py", line 38, in _fail
2020-10-15T17:41:52.275536490Z     raise RuntimeError(
2020-10-15T17:41:52.275543191Z RuntimeError: Signalling support is unavailable because the blinker library is not installed.
2020-10-15T17:41:52.278788387Z [2020-10-15 17:41:52 +0000] [42] [INFO] Worker exiting (pid: 42)
2020-10-15T17:41:54.044951158Z [2020-10-15 17:41:54 +0000] [40] [INFO] Shutting down: Master
2020-10-15T17:41:54.045803879Z [2020-10-15 17:41:54 +0000] [40] [INFO] Reason: Worker failed to boot.

KrunchMuffin avatar Oct 15 '20 17:10 KrunchMuffin

@KrunchMuffin you're running into #860, fixed in 0.19.1. I'm collapsing your comment because it's unrelated.

untitaker avatar Oct 19 '20 09:10 untitaker

RE: what doesn't work well. I'm trying to work out how to best attach some additional context (user information, from a session) to a sentry event. The user information is per request. Can the middleware accommodate this use case currently?

Edit: As @untitaker pointed out, this should already work as expected. I missed in the docs here the part which reads "Each request has a separate scope. Changes to the scope within a view, for example setting a tag, will only apply to events sent as part of the request being handled."

adg-mh avatar May 28 '21 20:05 adg-mh

The Middleware should make sure that the data you set within a request handler does not persist between requests.

On Fri, May 28, 2021, 22:43 adg-mh @.***> wrote:

I'm trying to work out how to best attach some additional context (user information, from a session) to a sentry event. The user information is per request. Can the middleware accommodate this use case currently?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/getsentry/sentry-python/issues/829#issuecomment-850660502, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAGMPRPWDJ2TXSTE7MDCEOLTP76AHANCNFSM4RVQVJNA .

untitaker avatar May 28 '21 21:05 untitaker

particularly around Performance monitoring

What aspect of performance monitoring is missing with the SentryAsgiMiddleware() class? I see that it's tracking transactions, that should give us full performance monitoring, right?

Is there an example of the "gold standard"? For example, is the Django integration more feature-filled?

ricky-sb avatar May 29 '21 12:05 ricky-sb

The Django integration is feature-complete and our gold standard for sure. The main feature that is missing from the ASGI and WSGI Middleware is that the transaction name is not set automatically because the Middleware cannot have knowledge of request routing. But having this information is critical for the product. So you need to set it manually for now.

On Sat, May 29, 2021, 14:13 Ricky @.***> wrote:

particularly around Performance monitoring

What aspect of performance monitoring is missing with the SentryAsgiMiddleware() class? I see that it's tracking transactions, that should give us full performance monitoring, right?

Is there an example of the "gold standard"? For example, is the Django integration more feature-filled?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/getsentry/sentry-python/issues/829#issuecomment-850822744, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAGMPRKGDSWGVGBLCWZTA5TTQDK7DANCNFSM4RVQVJNA .

untitaker avatar May 29 '21 16:05 untitaker

The Django integration is feature-complete and our gold standard for sure. The main feature that is missing from the ASGI and WSGI Middleware is that the transaction name is not set automatically because the Middleware cannot have knowledge of request routing. But having this information is critical for the product. So you need to set it manually for now. On Sat, May 29, 2021, 14:13 Ricky @.***> wrote: particularly around Performance monitoring What aspect of performance monitoring is missing with the SentryAsgiMiddleware() class? I see that it's tracking transactions, that should give us full performance monitoring, right? Is there an example of the "gold standard"? For example, is the Django integration more feature-filled? — You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <#829 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAGMPRKGDSWGVGBLCWZTA5TTQDK7DANCNFSM4RVQVJNA .

@untitaker can you expand on what we need to do to set this manually?

lsmith77 avatar Oct 04 '21 10:10 lsmith77

Run this in your view: https://docs.sentry.io/platforms/python/enriching-events/transaction-name/

untitaker avatar Oct 05 '21 10:10 untitaker

This issue has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you label it Status: Backlog or Status: In Progress, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

github-actions[bot] avatar Dec 23 '21 15:12 github-actions[bot]

The setup for ASGI in the documentation didn't work for me, but this worked: https://issueexplorer.com/issue/getsentry/sentry-python/1215

aimfeld avatar Dec 28 '21 15:12 aimfeld

@aimfeld, the same behaviour

it seems as a reason for another issue :)

Olegt0rr avatar Dec 30 '21 16:12 Olegt0rr

Another thing is not working as expected (at least for me) is the release health dashboard, the support team told me was because the autodetection of the transactions, is it already fixed? or this will be fixed with this integration?

juanbenitopr avatar Feb 14 '22 12:02 juanbenitopr

@juanbenitopr we added session tracking for ASGI only in 1.5.5, so maybe upgrade and try out the latest version and it should work.

sl0thentr0py avatar Feb 14 '22 12:02 sl0thentr0py

@sl0thentr0py thank you! I will try it :)

juanbenitopr avatar Feb 14 '22 12:02 juanbenitopr

The setup for ASGI in the documentation didn't work for me, but this worked: https://issueexplorer.com/issue/getsentry/sentry-python/1215

@aimfeld I am also not able to integrate Sentry into FastAPI using the ASGIMiddleware solution. Can you please share the other link(or code) which worked for you as the solution link you shared is broken?

rahulgupta92 avatar Apr 01 '22 15:04 rahulgupta92

for the record this works for me.

from sentry_sdk.integrations.asgi import SentryAsgiMiddleware

app = FastAPI()

# Uncaught exceptions (like `raise Exception`) should propagate correctly
# to Sentry's error handler
# Middleware will also enable Sentry performance monitoring to work as expected
try:
    sentry_sdk.init(
        dsn=settings.sentry_dsn,
        traces_sample_rate=settings.sentry_traces_sample_rate,
        sample_rate=settings.sentry_sample_rate,
        release=version,
        environment=settings.platform_environment,
    )

    app.add_middleware(SentryAsgiMiddleware)
except Exception:
    # pass silently if the Sentry integration failed
    pass

lsmith77 avatar Apr 01 '22 15:04 lsmith77

For me, when I added the SentryAsgiMiddleware to my fastapi app it resulted in exceptions being thrown on app shutdown. Transaction status was also not set properly due the generalist nature of the middleware (there's a comment in there about how it'd be hard to support)

I ended up using the code from it and a now abandoned open source project to write a custom middleware for Starlette that's based on starlette.middleware.base.BaseHTTPMiddleware. While doing this I was also able to update the associated event processor to work atop starlette.requests.Request instead of the raw ASGI scope. In most cases this allowed reuse of framework code to capture things like the url and headers versus needing custom helpers.

In addition there are two custom error types that FastAPI uses HTTPException and RequestValidationError that would need custom handlers added to the application to capture those issues in sentry. These have been previously mentioned, but it is important to note them since they get swallowed by the framework and do not propagate up to the middleware.

Kaelten avatar Apr 12 '22 19:04 Kaelten

This issue was created almost two years ago, is there any progress or even a desire for building native Sentry / FastAPI integration?

FastAPI arguably is in top 3 of python web frameworks (based on Github stars, 44K stars just behind Django and Flask) so I think it would be quite popular.

ruslaniv avatar Apr 23 '22 06:04 ruslaniv

perfect timing @ruslaniv! We want to start work on the FastAPI integration next quarter. And have some project kickoff planning this afternoon.

smeubank avatar Apr 25 '22 13:04 smeubank

Just a quick update, @sl0thentr0py has started working on this. As FastAPI is a wrapper around Starlette he started doing a Startlette Integration that will be the foundation of the FastAPI integration. Have a look here: https://github.com/getsentry/sentry-python/pull/1441

antonpirker avatar May 25 '22 08:05 antonpirker

@sl0thentr0py Note that the SentryASGI Middleware seems to be swallowing Starlette ServerErrors. Had some trouble figuring this out myself, since I was using Streaming Responses and was only seeing RuntimeErrors. Turns out it was because of Sentry's middlware. Check this thread out for more information: https://github.com/encode/starlette/discussions/1739

RamiAwar avatar Jul 07 '22 07:07 RamiAwar

Hey @RamiAwar ! Thanks for the pointer, I will take this into account when I am testing our new Starlette (the base of FastAPI) Integration next week!

antonpirker avatar Jul 07 '22 10:07 antonpirker

Hey @RamiAwar ! Thanks for the pointer, I will take this into account when I am testing our new Starlette (the base of FastAPI) Integration next week!

Just to clarify even further for the sake of completeness:

Sentry DOES log the error that happens as part of the StreamingResponse, but the server log does not: Server log only logs a Runtime error and uncaught exception, without specifying what it was.

It's pretty weird to replicate. Happened only with Pydantic validation errors that happened inside the generator passed into the streaming response. Did not happen with generic exceptions.

RamiAwar avatar Jul 11 '22 12:07 RamiAwar

initial release will be with manual integration, so we can do some testing in the wild before auto-enabling for all users

smeubank avatar Jul 18 '22 11:07 smeubank

This has now been released!

antonpirker avatar Sep 28 '22 14:09 antonpirker