I've looked through much of the SO responses regarding implementing this but I can't seem to find something that isn't deprecated or one that actually works for my use case.
Basically, I have some API methods that return their own status codes. However, if for any reason there is a 500 Server Error or anything above 500 which indicates something strange happened (for example lets say the database connection got timeout), I want that to be logged to a file or e-mailed to an admin.
I have tried using a custom exception handler but not all 500 errors are exceptions.
So I resorted to writing custom middleware, which looked something like this
class CustomApiLoggingMiddleware(MiddlewareMixin):
def process_response(self, request, response):
if response.path.startswith('/api/'):
...do stuff here
The issue, however, is that there doesn't seem to be a status_code
. To be frank I don't really know which response I'm actually getting. There's the 500 response returned by my API intentionally as a result of the API method, and there's the 500 response generated by Django in the backend if some kind of condition isn't met (let's say they sent a request without a proper header)
I tried to generate a 500 response / error intentionally by returning Response(status=status.HTTP_500)
in some basic /500
route. Even though this triggers the middleware, there is no status_code
that I can use to check whether the response is actually a 500 or not.
I'm not even sure I'm doing this right, but hopefully you understand my intention. I would basically like to blanket catch all uncaught exceptions that can happen as a result of my API calls and log them or send them to an admin. Most calls that return some 40X or whatever are handled in the way that I want already.
I am not entirely familiar with MiddlewareMixin
, but the straightforward implementation with a callable class as described in the docs seems to work:
class ResponseStatusMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
print(f"Response has status {response.status_code}")
return response
This works fine when the view does return HttpResponse(status=500)
with the standard Django HttpResponse
. However, when the view raises an exception, the middleware might be bypassed due to Django Rest Framework's exception handling. If get_response
is raising an exception, you can handle it by implementing the process_exception
hook in your middleware:
class ResponseStatusMiddleware:
...
def process_exception(self, request, exception):
...log your exception...
You could also convert uncaught exceptions to response objects with a custom handler, or, if possible, convert them to DRF's APIException
, which is handled automatically.
Also, the status.HTTP_500
should probably be status.HTTP_500_INTERNAL_SERVER_ERROR
(see the DRF documentation).