Intercepting a Django 500 error for logging, without creating/serving a custom 500.html

Viewed 376

In order to log "some dependency, somewhere deep" errors that trigger a server error 500, without stack traces in the console log on production instances due to DEBUG=False, I implemented the standard custom 500 handler that a fair number of Stackoverflow questions about printing a stack trace for a 500 error recommend:

import sys
import traceback

def server_error_500_handler(request):
    type, value, tb = sys.exc_info()
    print('\n----intercepted 500 error stack trace----')
    print(value)
    print(type)
    print(traceback.format_exception(type, value, tb))
    print('----\n')

However, these then also all say to end with render(request, '500.html'), whereas I don't want to serve a custom 500 page, but want the code to go "back" (if there is such a thing) to just serving whatever Django itself does already. Is there some way to make it do that? Or, is there some way to listen for the 500 event without hijacking the 500 error return codepath?

1 Answers

Instead of making a custom 500 handler, make a custom middleware of your own and implement a process_exception method in it:

import traceback


class Log500ErrorsMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        return response
    
    def process_exception(self, request, exception):
        print('\n----intercepted 500 error stack trace----')
        print(exception)
        print(type(exception))
        tb = exception.__traceback__
        print(traceback.format_exception(type(exception), exception, tb))
        print('----\n')
        return None # Let other middlewares do further processing

Then add it to the MIDDLEWARE setting, all the way at the end, since the middlewares are run in bottom-up order during the response/exception phase, so if you put it last it will always get run (some middleware can decide to short circuit and return a response otherwise, so having anything after it might prevent it from running).

MIDDLEWARE = [
    ...
    'path.to.Log500ErrorsMiddleware',
]
Related