exception_handlers.py 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. import logging
  2. from django.db.utils import OperationalError
  3. from psl_dns.exceptions import UnsupportedRule
  4. from rest_framework import status
  5. from rest_framework.response import Response
  6. from rest_framework.views import exception_handler as drf_exception_handler
  7. from desecapi import metrics
  8. from desecapi.exceptions import PDNSException
  9. def exception_handler(exc, context):
  10. """
  11. desecapi specific exception handling. If no special treatment is applied,
  12. we default to restframework's exception handling. See also
  13. https://www.django-rest-framework.org/api-guide/exceptions/#custom-exception-handling
  14. """
  15. def _log():
  16. logger = logging.getLogger('django.request')
  17. logger.error('{} Supplementary Information'.format(exc.__class__),
  18. exc_info=exc, stack_info=False)
  19. def _500():
  20. _log()
  21. # Let clients know that there is a problem
  22. response = Response({'detail': 'Internal Server Error. We\'re on it!'},
  23. status=status.HTTP_500_INTERNAL_SERVER_ERROR)
  24. return response
  25. def _503():
  26. _log()
  27. # Let clients know that there is a temporary problem
  28. response = Response({'detail': 'Please try again later.'},
  29. status=status.HTTP_503_SERVICE_UNAVAILABLE)
  30. return response
  31. # Catch DB exception and log an extra error for additional context
  32. if (
  33. isinstance(exc, OperationalError) and
  34. isinstance(exc.args, (list, dict, tuple)) and
  35. exc.args and
  36. exc.args[0] in (
  37. 2002, # Connection refused (Socket)
  38. 2003, # Connection refused (TCP)
  39. 2005, # Unresolved host name
  40. 2007, # Server protocol mismatch
  41. 2009, # Wrong host info
  42. 2026, # SSL connection error
  43. )
  44. ):
  45. metrics.get('desecapi_database_unavailable').inc()
  46. return _503()
  47. # OSError happens on system-related errors, like full disk or getaddrinfo() failure.
  48. if isinstance(exc, OSError):
  49. # TODO add metrics
  50. return _500()
  51. # The PSL encountered an unsupported rule
  52. if isinstance(exc, UnsupportedRule):
  53. # TODO add metrics
  54. return _500()
  55. # nslord/nsmaster returned an error
  56. if isinstance(exc, PDNSException):
  57. # TODO add metrics
  58. return _500()
  59. return drf_exception_handler(exc, context)