getsentry / sentry-python

The official Python SDK for Sentry.io
https://sentry.io/for/python/
MIT License
1.93k stars 510 forks source link

quart_flask_patch breaks asgi #2709

Open UrekD opened 9 months ago

UrekD commented 9 months ago

How do you use Sentry?

Self-hosted/on-premise

Version

1.40.0

Steps to Reproduce

  1. Install requirements
    quart==0.19.4
    quart-flask-patch==0.3.0
    Flask-Caching==2.1.0
    Jinja2==3.1.2
    MarkupSafe==2.1.2
    mysql-connector-python==8.0.32
    SQLAlchemy==2.0.0
    mysqlclient==2.1.1
    python-dotenv==0.20.0
    hypercorn==0.16.0
    uvicorn==0.27.0
    pymsteams[async]==0.2.2
    requests==2.28.2
    msal==1.21.0
    aiosmtplib==2.0.1
    Werkzeug==3.0.1
    sentry-sdk[quart]==1.40.0
  2. Run
from quart import Quart

import sentry_sdk
from sentry_sdk.integrations.quart import QuartIntegration

sentry_sdk.init(
    dsn="http://0fa88f9f4dcb4080b547a1b280bc4360@10.156.33.1:8000/1",
    enable_tracing=True,
    integrations=[
        QuartIntegration(),
    ],
)

app = Quart(__name__)

@app.route("/")
async def hello():
    1/0  # raises an error
    return {"hello": "world"}

app.run(host="0.0.0.0")
  1. Import Quart flask patch, add to l1 import quart_flask_patch

Expected Result

To not break.

Actual Result

2024-02-05 20:07:55 +0000] [8727] [INFO] Running on http://0.0.0.0:5000 (CTRL + C to quit)
 * Serving Quart app 'test'
 * Debug mode: False
 * Please use an ASGI server (e.g. Hypercorn) directly in production
 * Running on http://0.0.0.0:5000 (CTRL + C to quit)
[2024-02-05 20:12:51 +0000] [8727] [INFO] Running on http://0.0.0.0:5000 (CTRL + C to quit)
[2024-02-05 20:13:11 +0000] [8727] [ERROR] Error in ASGI Framework
Traceback (most recent call last):
  File "/home/durek/.local/lib/python3.10/site-packages/hypercorn/asyncio/task_group.py", line 27, in _handle
    await app(scope, receive, send, sync_spawn, call_soon)
  File "/home/durek/.local/lib/python3.10/site-packages/hypercorn/app_wrappers.py", line 51, in __call__
    await self.handle_http(scope, receive, send, sync_spawn, call_soon)
  File "/home/durek/.local/lib/python3.10/site-packages/hypercorn/app_wrappers.py", line 83, in handle_http
    await sync_spawn(self.run_app, environ, partial(call_soon, send))
  File "/usr/lib/python3.10/asyncio/futures.py", line 285, in __await__
    yield self  # This tells Task to wait for completion.
  File "/usr/lib/python3.10/asyncio/tasks.py", line 304, in __wakeup
    future.result()
  File "/usr/lib/python3.10/asyncio/futures.py", line 201, in result
    raise self._exception.with_traceback(self._exception_tb)
  File "/usr/lib/python3.10/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/home/durek/.local/lib/python3.10/site-packages/hypercorn/app_wrappers.py", line 107, in run_app
    response_body = self.app(environ, start_response)
  File "/home/durek/.local/lib/python3.10/site-packages/sentry_sdk/integrations/flask.py", line 85, in sentry_patched_wsgi_app
    return SentryWsgiMiddleware(lambda *a, **kw: old_app(self, *a, **kw))(
  File "/home/durek/.local/lib/python3.10/site-packages/sentry_sdk/integrations/wsgi.py", line 115, in __call__
    reraise(*_capture_exception(hub))
  File "/home/durek/.local/lib/python3.10/site-packages/sentry_sdk/_compat.py", line 127, in reraise
    raise value
  File "/home/durek/.local/lib/python3.10/site-packages/sentry_sdk/integrations/wsgi.py", line 108, in __call__
    rv = self.app(
  File "/home/durek/.local/lib/python3.10/site-packages/sentry_sdk/integrations/flask.py", line 85, in <lambda>
    return SentryWsgiMiddleware(lambda *a, **kw: old_app(self, *a, **kw))(
TypeError: patch_asgi_app.<locals>.sentry_patched_asgi_app() missing 1 required positional argument: 'send'
[2024-02-05 20:13:11 +0000] [8727] [INFO] 127.0.0.1:52442 GET / 1.1 500 - 52815
[2024-02-05 20:13:11 +0000] [8727] [INFO] 127.0.0.1:52442 GET / 1.1 - - 54168
saherneklawy commented 8 months ago

Is there a way to avoid this issue until it's queued for a fix please?

sentrivana commented 8 months ago

This seems to happen because due to how quart_flask_patch patches things, the SDK thinks this is now a Flask app and tries to wrap the async Quart requests in a sync WSGI wrapper.

This might work:

sentry_sdk.init(
   # your usual stuff
   auto_enabling_integrations=False,
)

This will tell the SDK to only enable integrations that you explicitly provide in the init. Without this option the default behavior is to auto-detect what is installed and enable the corresponding integrations if available (so in this case, it'd enable the incorrect Flask integration).

Caveat to this: You'll have to enable all library/framework integrations by hand after doing this. So e.g. if you're also using something like SQLAlchemy, you'll need to add the integration into the init's integrations list. You can find out which integrations might be enabled in the background by setting debug=True in the init; the SDK will then print out all enabled integrations at startup. This docs page also has a list of auto-enabled integrations.

szokeasaurusrex commented 2 months ago

We also have a new disabled_integrations option, which allows you to provide a list of integrations you wish to disable, while keeping all other auto-enabling integrations enabled