sentry-python
sentry-python copied to clipboard
Integration for FastAPI
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.
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 you're running into #860, fixed in 0.19.1. I'm collapsing your comment because it's unrelated.
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."
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 .
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?
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 .
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?
Run this in your view: https://docs.sentry.io/platforms/python/enriching-events/transaction-name/
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 🥀
The setup for ASGI in the documentation didn't work for me, but this worked: https://issueexplorer.com/issue/getsentry/sentry-python/1215
@aimfeld, the same behaviour
it seems as a reason for another issue :)
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 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 thank you! I will try it :)
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?
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
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.
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.
perfect timing @ruslaniv! We want to start work on the FastAPI integration next quarter. And have some project kickoff planning this afternoon.
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
@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
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!
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.
initial release will be with manual integration, so we can do some testing in the wild before auto-enabling for all users
This has now been released!