exception_handlers.py 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  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 _perform_handling(name):
  16. logger = logging.getLogger('django.request')
  17. logger.error('{} Supplementary Information'.format(name),
  18. exc_info=exc, stack_info=False)
  19. # Gracefully let clients know that we cannot connect to the database
  20. response = Response({'detail': 'Please try again later.'},
  21. status=status.HTTP_503_SERVICE_UNAVAILABLE)
  22. metrics.get('desecapi_database_unavailable').inc()
  23. return response
  24. # Catch DB exception and log an extra error for additional context
  25. if isinstance(exc, OperationalError):
  26. if isinstance(exc.args, (list, dict, tuple)) and exc.args and \
  27. exc.args[0] in (
  28. 2002, # Connection refused (Socket)
  29. 2003, # Connection refused (TCP)
  30. 2005, # Unresolved host name
  31. 2007, # Server protocol mismatch
  32. 2009, # Wrong host info
  33. 2026, # SSL connection error
  34. ):
  35. return _perform_handling('OperationalError')
  36. # OSError happens on system-related errors, like full disk or getaddrinfo() failure.
  37. # Catch it and log an extra error for additional context.
  38. if isinstance(exc, OSError):
  39. return _perform_handling('OSError')
  40. if isinstance(exc, UnsupportedRule):
  41. return _perform_handling('UnsupportedRule')
  42. if isinstance(exc, PDNSException):
  43. return _perform_handling('PDNSException')
  44. return drf_exception_handler(exc, context)