I work on a high-traffic Django site at work, and desipite the rigorous testing and near-mathematical-perfection of my code, I occasionally receive exception notices. Usually the default Django exception email is enough to quickly track down the problem, but sometimes things are less clear. I find the Django 'debug mode' error pages extremely useful, given that they show context around the offending line and local variable values for every frame in the traceback. The standard exception email sent to site admins when running in production mode, however, is far, far less useful.
Fortunately, Django is pretty simple. There's not a lot of magic under the hood (unlike other frameworks), so with just a little bit of poking around you can understand what it's doing and how.
I was pleased to discover that the exception notification in django.core.handlers.base was as easy as "get sys.exc_info() and render the nice template if DEBUG is True, and email this other thing if it is False". After this quick-and-dirty patch, I was getting beautiful, detailed exception notices in my email.
# Index: handlers/base.py
--- handlers/base.py (revision 6633)
+++ handlers/base.py (working copy)
-1,3 +1,5 @@
+from django.conf import settings
+from django.core.mail import EmailMessage
from django.core import signals
from django.dispatch import dispatcher
from django import http
-123,8 +125,19 @@
request_repr = repr(request)
except:
request_repr = "Request repr() unavailable"
- message = "%s\n\n%s" % (self._get_traceback(exc_info), request_repr)
- mail_admins(subject, message, fail_silently=True)
+# message = "%s\n\n%s" % (self._get_traceback(exc_info), request_repr)
+# mail_admins(subject, message, fail_silently=True)
+ from django.views import debug
+ err_for_msg = debug.technical_500_response(request, *exc_info)
+ msg = EmailMessage(
+ settings.EMAIL_SUBJECT_PREFIX + subject,
+ err_for_msg.content,
+ settings.SERVER_EMAIL,
+ [a[1] for a in settings.ADMINS])
+ msg.content_subtype='html'
+ msg.send(fail_silently=True)
+
+
# Return an HttpResponse that displays a friendly error message.
callback, param_dict = resolver.resolve500()
return callback(request, **param_dict)
Would other Djangonauts (is there a cute name for Django users?) find this useful as well? I'm not sure - if it's just a handful, there's the patch, if it's a plurality, maybe there's a place for settings.FANCY_PANTS_EXCEPTION_NOTICES in Django?
mads commented, on January 4, 2008 at 8:49 p.m.:
This can also be handled with a signal without the need to patch django. An exeption sends out a signal, which one can add a listener for, and then do the above.
the daniel commented, on January 4, 2008 at 9:32 p.m.:
thanks for the tip, mads - I'll definitely reimplement this using the signal framework. I think I am a pragmatic programmer, but I do of course prefer 'the right way' to 'quick and dirty' :)
the daniel commented, on December 5, 2007 at 6:23 a.m.:
mattmcc in #django mentioned that this should probably be sent multipart - i leave this trivial excercise to the reader (or to me if i submit a patch to django ;) )