Prominently display the user in Django 500 emails.

As a side-effect of customizing the e-mail, this also makes the host
on which the error happened a part of the subject line.

(imported from commit 7d5e9ad108b48fd34528512c5955567119935d4e)
This commit is contained in:
Jessica McKellar 2013-01-16 14:45:07 -05:00
parent e3b852b79e
commit 8d1ccad29b
2 changed files with 52 additions and 12 deletions

View File

@ -237,7 +237,7 @@ LOGGING = {
}, },
'mail_admins': { 'mail_admins': {
'level': 'ERROR', 'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler', 'class': 'zephyr.handlers.HumbugAdminEmailHandler',
'filters': ['EmailLimiter', 'require_debug_false'], 'filters': ['EmailLimiter', 'require_debug_false'],
}, },
}, },

View File

@ -1,11 +1,31 @@
import sys
import logging import logging
import traceback import traceback
import platform import platform
from django.utils.timezone import now from django.core import mail
from django.views.debug import get_exception_reporter_filter from django.utils.log import AdminEmailHandler
from django.views.debug import ExceptionReporter, get_exception_reporter_filter
def format_record(record):
"""
Given a Django error LogRecord, format and return the interesting details,
for use by notification mechanisms like Humbug and e-mail.
"""
subject = '%s: %s' % (platform.node(), record.getMessage())
if record.exc_info:
stack_trace = ''.join(traceback.format_exception(*record.exc_info))
else:
stack_trace = 'No stack trace available'
try:
user = record.request.user
user_info = "%s (%s)" % (user.userprofile.full_name, user.email)
except Exception:
# Error was triggered by an anonymous user.
user_info = "Anonymous user (not logged in)"
return (subject, stack_trace, user_info)
class AdminHumbugHandler(logging.Handler): class AdminHumbugHandler(logging.Handler):
"""An exception log handler that Humbugs log entries to the Humbug realm. """An exception log handler that Humbugs log entries to the Humbug realm.
@ -24,7 +44,7 @@ class AdminHumbugHandler(logging.Handler):
from zephyr.models import Recipient from zephyr.models import Recipient
from zephyr.lib.actions import internal_send_message from zephyr.lib.actions import internal_send_message
subject = '%s: %s' % (platform.node(), record.getMessage())
try: try:
request = record.request request = record.request
@ -40,16 +60,13 @@ class AdminHumbugHandler(logging.Handler):
request_repr += "~~~~" request_repr += "~~~~"
except Exception: except Exception:
request_repr = "Request repr() unavailable." request_repr = "Request repr() unavailable."
subject = self.format_subject(subject)
if record.exc_info: subject, stack_trace, user_info = format_record(record)
stack_trace = ''.join(traceback.format_exception(*record.exc_info))
else:
stack_trace = 'No stack trace available'
internal_send_message("humbug+errors@humbughq.com", internal_send_message("humbug+errors@humbughq.com",
Recipient.STREAM, "devel", subject, Recipient.STREAM, "devel", self.format_subject(subject),
"~~~~ pytb\n%s\n\n~~~~\n%s" % (stack_trace, request_repr)) "Error generated by %s\n\n~~~~ pytb\n%s\n\n~~~~\n%s" % (
user_info, stack_trace, request_repr))
def format_subject(self, subject): def format_subject(self, subject):
""" """
@ -59,3 +76,26 @@ class AdminHumbugHandler(logging.Handler):
formatted_subject = subject.replace('\n', '\\n').replace('\r', '\\r') formatted_subject = subject.replace('\n', '\\n').replace('\r', '\\r')
return formatted_subject[:MAX_SUBJECT_LENGTH] return formatted_subject[:MAX_SUBJECT_LENGTH]
class HumbugAdminEmailHandler(AdminEmailHandler):
"""An exception log handler that emails log entries to site admins.
If the request is passed as the first argument to the log record,
request data will be provided in the email report.
"""
def emit(self, record):
try:
request = record.request
filter = get_exception_reporter_filter(request)
request_repr = filter.get_request_repr(request)
except Exception:
request = None
request_repr = "Request repr() unavailable."
subject, stack_trace, user_info = format_record(record)
message = "Error generated by %s\n\n%s\n\n%s" % (user_info, stack_trace,
request_repr)
reporter = ExceptionReporter(request, is_email=True, *record.exc_info)
html_message = self.include_html and reporter.get_traceback_html() or None
mail.mail_admins(self.format_subject(subject), message, fail_silently=True,
html_message=html_message)