7

Django has an awesome debug page that shows up whenever there's an exception in the code. That page shows all levels in the stack compactly, and you can expand any level you're interested in. It shows only in debug mode.

Django also has an awesome feature for sending email reports when errors are encountered on the production server by actual users. These reports have a stacktrace with much less information than the styled debug page.

There's an awesome optional setting 'include_html': True that makes the email include all the information of the debug page, which is really useful. The problem with this setting is that the HTML comes apparently unstyled, so all those levels of the stack are expanded to show all the data they contain.

This results in such a long email that GMail usually can't even display it without sending you to a dedicated view. But the real problem is that it's too big to navigate in and find the stack level you want.

What I want: I want Django to send that detailed stacktrace, but I want the levels of the stack to be collapsable just like in the debug page. How can I do that?

(And no, I don't want to use Sentry.)

Ram Rachum
  • 84,019
  • 84
  • 236
  • 374

3 Answers3

3

We use a middleware to process any exceptions that happen in production. The basic idea is save the debug html to a location on the file system that can be served via a password protected view and then send a link to the generated view to whoever needs it.

Here is a basic implementation:

from django.conf import settings
from django.core.mail import send_mail
from django.views import debug
import traceback
import hashlib
import sys

class ExceptionMiddleware(object):

    def process_exception(self, request, exception):
        if isinstance(exception, Http404):
            return
        traceback = traceback.format_exc()
        traceback_hash = hashlib.md5(traceback).hexdigest()
        traceback_name = '%s.html' % traceback_hash
        traceback_path = os.path.join(settings.EXCEPTIONS_DIR, traceback_name)
        reporter = debug.ExceptionReporter(request, *sys.exc_info())
        with open(traceback_path, 'w') as f:
            f.write(reporter.get_traceback_html().encode("utf-8"))
        send_mail(
            'Error at %s' % request.path,
            request.build_absolute_uri(reverse('exception', args=(traceback_name, ))),
            FROM_EMAIL,
            TO_EMAIL,
        )

And the view

from django.conf import settings
from django.http import HttpResponse

def exception(request, traceback_name):
    traceback_path = os.path.join(settings.EXCEPTIONS_DIR, traceback_name)
    with open(traceback_path, 'r') as f:
        response = HttpResponse(f.read())
    return response

The full middleware is tailored to our needs but the basics are there. You should probably password protect the view somehow. Unless you return a response Django's own error handling will kick in and still send you an email but I'll leave that to you.

Iain Shelvington
  • 31,030
  • 3
  • 31
  • 50
1

The tracebacks in the debug page are stackable because they are done in javascript. I doubt you can have what you want since HTML emails should not accept javascript.

Community
  • 1
  • 1
Jorge Leitao
  • 19,085
  • 19
  • 85
  • 121
1

As J. C. Leitão pointed out, the django error debug page has javascript and css(most css doesn't work in email). But all these css and js code are inline. The debug page is a single html file that has no external resources.

In my company, we include the html as a attachment in the report email. When we feel the plain text traceback is not clear enough, we download the html page and open it. The user experience is not as good as Sentry, but much better than the plain-text only version.

Leonardo.Z
  • 9,425
  • 3
  • 35
  • 38
  • How do I get the HTML of the file with the javascript to include as an attachment? I want to do the same but I don't know how to get the HTML. – Ram Rachum May 31 '14 at 18:27