Skip to content

Fix Falcon Integration #2346

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions sentry_sdk/integrations/_falcon_async_py3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""
This file was created so we could have a process_request_async method on our
SentryFalconMiddleware class, so we could properly support ASGI with Falcon.
However, since process_request_async needs to be an async function, we cannot
define it in Python 2.7, as this produces a syntax error.

So, we have split the process_request_async implementation into this separate
file, which can only be loaded in Python 3 and above.

TODO: If we ever remove Python 2.7 support, we should delete this file and move
the process_request_async implementation to the SentryFalconMiddleware class
in the falcon.py file.
"""

from typing import Any


class _SentryFalconMiddlewareBase:
"""
The SentryFalconMiddleware should inherit from this class in Python 3. The only
purpose of this class is to provide an implementation of process_request_async which
simply calls process_request.
"""

def process_request(self, req: Any, resp: Any, *args: Any, **kwargs: Any) -> None:
Copy link
Member Author

Choose a reason for hiding this comment

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

Is it okay that I used Python 3-style type hints here? This file should never get loaded in Python 2

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should be fine 👀

"""
SentryFalconMiddleware will override this method and provide the actual implementation.
"""
pass

async def process_request_async(
self, req: Any, resp: Any, *args: Any, **kwargs: Any
) -> None:
self.process_request(req, resp, *args, **kwargs)
19 changes: 13 additions & 6 deletions sentry_sdk/integrations/falcon.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@

from sentry_sdk._types import TYPE_CHECKING

from sentry_sdk._compat import PY2

if PY2:
_SentryFalconMiddlewareBase = object
else:
# Support ASGI with a process_request_async method, which can only be loaded in Python 3,
# since async methods are invalid syntax in Python 2.7.
from sentry_sdk.integrations._falcon_async_py3 import _SentryFalconMiddlewareBase

if TYPE_CHECKING:
from typing import Any
from typing import Dict
Expand Down Expand Up @@ -97,7 +106,7 @@ def json(self):
return self.request._media


class SentryFalconMiddleware(object):
class SentryFalconMiddleware(_SentryFalconMiddlewareBase):
"""Captures exceptions in Falcon requests and send to Sentry"""

def process_request(self, req, resp, *args, **kwargs):
Expand Down Expand Up @@ -205,15 +214,13 @@ def _patch_prepare_middleware():
# type: () -> None
original_prepare_middleware = falcon_helpers.prepare_middleware

def sentry_patched_prepare_middleware(
middleware=None, independent_middleware=False
):
# type: (Any, Any) -> Any
def sentry_patched_prepare_middleware(middleware=None, *args, **kwargs):
# type: (Any, *Any, **Any) -> Any
hub = Hub.current
integration = hub.get_integration(FalconIntegration)
if integration is not None:
middleware = [SentryFalconMiddleware()] + (middleware or [])
return original_prepare_middleware(middleware, independent_middleware)
return original_prepare_middleware(middleware, *args, **kwargs)

falcon_helpers.prepare_middleware = sentry_patched_prepare_middleware

Expand Down
17 changes: 14 additions & 3 deletions tests/integrations/falcon/test_falcon.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,20 @@
from sentry_sdk.integrations.falcon import FalconIntegration
from sentry_sdk.integrations.logging import LoggingIntegration

try:
import falcon.asgi
except ImportError:
# Only test WSGI app
APP_CONSTRUCTORS = [falcon.API]
else:
# Test ASGI and WSGI apps
APP_CONSTRUCTORS = [falcon.App, falcon.asgi.App]


@pytest.fixture(params=APP_CONSTRUCTORS)
def make_app(request, sentry_init):
app_constructor = request.param

@pytest.fixture
def make_app(sentry_init):
def inner():
class MessageResource:
def on_get(self, req, resp):
Expand All @@ -26,7 +37,7 @@ def on_get(self, req, resp, message_id):
sentry_sdk.capture_message("hi")
resp.media = "hi"

app = falcon.API()
app = app_constructor()
app.add_route("/message", MessageResource())
app.add_route("/message/{message_id:int}", MessageByIdResource())

Expand Down