Skip to content

feat(litestar): Add failed_request_status_codes #4021

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

Merged
merged 5 commits into from
Feb 6, 2025
Merged
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
22 changes: 21 additions & 1 deletion sentry_sdk/integrations/litestar.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
from collections.abc import Set
import sentry_sdk
from sentry_sdk.consts import OP
from sentry_sdk.integrations import DidNotEnable, Integration
from sentry_sdk.integrations import (
_DEFAULT_FAILED_REQUEST_STATUS_CODES,
DidNotEnable,
Integration,
)
from sentry_sdk.integrations.asgi import SentryAsgiMiddleware
from sentry_sdk.integrations.logging import ignore_logger
from sentry_sdk.scope import should_send_default_pii
Expand All @@ -17,6 +22,7 @@
from litestar.middleware import DefineMiddleware # type: ignore
from litestar.routes.http import HTTPRoute # type: ignore
from litestar.data_extractors import ConnectionDataExtractor # type: ignore
from litestar.exceptions import HTTPException # type: ignore
except ImportError:
raise DidNotEnable("Litestar is not installed")

Expand Down Expand Up @@ -45,6 +51,12 @@ class LitestarIntegration(Integration):
identifier = "litestar"
origin = f"auto.http.{identifier}"

def __init__(
self,
failed_request_status_codes=_DEFAULT_FAILED_REQUEST_STATUS_CODES, # type: Set[int]
) -> None:
self.failed_request_status_codes = failed_request_status_codes

@staticmethod
def setup_once():
# type: () -> None
Expand Down Expand Up @@ -277,6 +289,14 @@ def exception_handler(exc, scope):
sentry_scope = sentry_sdk.get_isolation_scope()
sentry_scope.set_user(user_info)

if isinstance(exc, HTTPException):
integration = sentry_sdk.get_client().get_integration(LitestarIntegration)
if (
integration is not None
and exc.status_code not in integration.failed_request_status_codes
):
return

event, hint = event_from_exception(
exc,
client_options=sentry_sdk.get_client().options,
Expand Down
21 changes: 21 additions & 0 deletions tests/integrations/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,24 @@ def capture_event_scope(self, event, hint=None, scope=None):
return errors

return inner


parametrize_test_configurable_status_codes = pytest.mark.parametrize(
("failed_request_status_codes", "status_code", "expected_error"),
(
(None, 500, True),
(None, 400, False),
({500, 501}, 500, True),
({500, 501}, 401, False),
({*range(400, 500)}, 401, True),
({*range(400, 500)}, 500, False),
({*range(400, 600)}, 300, False),
({*range(400, 600)}, 403, True),
({*range(400, 600)}, 503, True),
({*range(400, 403), 500, 501}, 401, True),
({*range(400, 403), 500, 501}, 405, False),
({*range(400, 403), 500, 501}, 501, True),
({*range(400, 403), 500, 501}, 503, False),
(set(), 500, False),
),
)
3 changes: 2 additions & 1 deletion tests/integrations/fastapi/test_fastapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

FASTAPI_VERSION = parse_version(fastapi.__version__)

from tests.integrations.conftest import parametrize_test_configurable_status_codes
from tests.integrations.starlette import test_starlette


Expand Down Expand Up @@ -650,7 +651,7 @@ def test_transaction_http_method_custom(sentry_init, capture_events):
assert event2["request"]["method"] == "HEAD"


@test_starlette.parametrize_test_configurable_status_codes
@parametrize_test_configurable_status_codes
def test_configurable_status_codes(
sentry_init,
capture_events,
Expand Down
31 changes: 31 additions & 0 deletions tests/integrations/litestar/test_litestar.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations
import functools

from litestar.exceptions import HTTPException
import pytest

from sentry_sdk import capture_message
Expand All @@ -16,6 +17,8 @@
from litestar.middleware.session.server_side import ServerSideSessionConfig
from litestar.testing import TestClient

from tests.integrations.conftest import parametrize_test_configurable_status_codes


def litestar_app_factory(middleware=None, debug=True, exception_handlers=None):
class MyController(Controller):
Expand Down Expand Up @@ -396,3 +399,31 @@ async def __call__(self, scope, receive, send):
}
else:
assert "user" not in event


@parametrize_test_configurable_status_codes
def test_configurable_status_codes(
sentry_init,
capture_events,
failed_request_status_codes,
status_code,
expected_error,
):
integration_kwargs = (
{"failed_request_status_codes": failed_request_status_codes}
if failed_request_status_codes is not None
else {}
)
sentry_init(integrations=[LitestarIntegration(**integration_kwargs)])

events = capture_events()

@get("/error")
async def error() -> None:
raise HTTPException(status_code=status_code)

app = Litestar([error])
client = TestClient(app)
client.get("/error")

assert len(events) == int(expected_error)
23 changes: 2 additions & 21 deletions tests/integrations/starlette/test_starlette.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
from starlette.middleware.trustedhost import TrustedHostMiddleware
from starlette.testclient import TestClient

from tests.integrations.conftest import parametrize_test_configurable_status_codes


STARLETTE_VERSION = parse_version(starlette.__version__)

Expand Down Expand Up @@ -1298,27 +1300,6 @@ def test_transaction_http_method_custom(sentry_init, capture_events):
assert event2["request"]["method"] == "HEAD"


parametrize_test_configurable_status_codes = pytest.mark.parametrize(
("failed_request_status_codes", "status_code", "expected_error"),
(
(None, 500, True),
(None, 400, False),
({500, 501}, 500, True),
({500, 501}, 401, False),
({*range(400, 500)}, 401, True),
({*range(400, 500)}, 500, False),
({*range(400, 600)}, 300, False),
({*range(400, 600)}, 403, True),
({*range(400, 600)}, 503, True),
({*range(400, 403), 500, 501}, 401, True),
({*range(400, 403), 500, 501}, 405, False),
({*range(400, 403), 500, 501}, 501, True),
({*range(400, 403), 500, 501}, 503, False),
(set(), 500, False),
),
)


@parametrize_test_configurable_status_codes
def test_configurable_status_codes(
sentry_init,
Expand Down
Loading