exception_handlers.py 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142
  1. from django.db.utils import OperationalError
  2. from rest_framework import status
  3. from rest_framework.response import Response
  4. from rest_framework.views import exception_handler as drf_exception_handler
  5. import logging
  6. def exception_handler(exc, context):
  7. """
  8. desecapi specific exception handling. If no special treatment is applied,
  9. we default to restframework's exception handling. See also
  10. https://www.django-rest-framework.org/api-guide/exceptions/#custom-exception-handling
  11. """
  12. def _perform_handling(name):
  13. logger = logging.getLogger('django.request')
  14. logger.error('{} Supplementary Information'.format(name),
  15. exc_info=exc, stack_info=False)
  16. # Gracefully let clients know that we cannot connect to the database
  17. return Response({'detail': 'Please try again later.'},
  18. status=status.HTTP_503_SERVICE_UNAVAILABLE)
  19. # Catch DB exception and log an extra error for additional context
  20. if isinstance(exc, OperationalError):
  21. if isinstance(exc.args, (list, dict, tuple)) and exc.args and \
  22. exc.args[0] in (
  23. 2002, # Connection refused (Socket)
  24. 2003, # Connection refused (TCP)
  25. 2005, # Unresolved host name
  26. 2007, # Server protocol mismatch
  27. 2009, # Wrong host info
  28. 2026, # SSL connection error
  29. ):
  30. return _perform_handling('OperationalError')
  31. # OSError happens on system-related errors, like full disk or getaddrinfo() failure.
  32. # Catch it and log an extra error for additional context.
  33. if isinstance(exc, OSError):
  34. return _perform_handling('OSError')
  35. return drf_exception_handler(exc, context)