diff --git a/src/objects/utils/tests/test_exception_handler.py b/src/objects/utils/tests/test_exception_handler.py new file mode 100644 index 00000000..c933cccb --- /dev/null +++ b/src/objects/utils/tests/test_exception_handler.py @@ -0,0 +1,53 @@ +import logging # noqa: TID251 +from unittest.mock import patch + +import sentry_sdk +from rest_framework.test import APITestCase +from sentry_sdk.integrations.logging import LoggingIntegration +from sentry_sdk.transport import Transport + +from ..views import exception_handler + + +class InMemoryTransport(Transport): + """ + Mock transport class to test if Sentry works + """ + + def __init__(self, options): + self.envelopes = [] + + def capture_envelope(self, envelope): + self.envelopes.append(envelope) + + +class ExceptionHandlerTests(APITestCase): + @patch.dict("os.environ", {"DEBUG": "no"}) + def test_error_is_forwarded_to_sentry(self): + transport = InMemoryTransport({}) + sentry_sdk.init( + dsn="https://12345@sentry.local/1234", + transport=transport, + integrations=[ + LoggingIntegration( + level=logging.INFO, + # Avoid sending logger.exception calls to Sentry + event_level=None, + ), + ], + ) + assert len(transport.envelopes) == 0 + + exc = Exception("Something went wrong") + + result = exception_handler(exc, context={}) + + self.assertIsNotNone(result) + + # Error should be forwarded to sentry + assert len(transport.envelopes) == 1 + + event = transport.envelopes[0] + assert event.items[0].payload.json["level"] == "error" + exception = event.items[0].payload.json["exception"]["values"][-1] + assert exception["value"] == "Something went wrong" diff --git a/src/objects/utils/views.py b/src/objects/utils/views.py index 7aacca5c..b65d3b10 100644 --- a/src/objects/utils/views.py +++ b/src/objects/utils/views.py @@ -1,6 +1,7 @@ from django.db.utils import DatabaseError from django.utils.translation import gettext_lazy as _ +import sentry_sdk import structlog from open_api_framework.conf.utils import config from rest_framework import status @@ -37,6 +38,9 @@ def exception_handler(exc, context): ) event = "api.database_exception" + # make sure the exception still ends up in Sentry + sentry_sdk.capture_exception(exc) + response = Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR, data=data) logger.exception(event, exc_info=exc)