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': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
'class': 'zephyr.handlers.HumbugAdminEmailHandler',
'filters': ['EmailLimiter', 'require_debug_false'],
},
},

View File

@ -1,11 +1,31 @@
import sys
import logging
import traceback
import platform
from django.utils.timezone import now
from django.views.debug import get_exception_reporter_filter
from django.core import mail
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):
"""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.lib.actions import internal_send_message
subject = '%s: %s' % (platform.node(), record.getMessage())
try:
request = record.request
@ -40,16 +60,13 @@ class AdminHumbugHandler(logging.Handler):
request_repr += "~~~~"
except Exception:
request_repr = "Request repr() unavailable."
subject = self.format_subject(subject)
if record.exc_info:
stack_trace = ''.join(traceback.format_exception(*record.exc_info))
else:
stack_trace = 'No stack trace available'
subject, stack_trace, user_info = format_record(record)
internal_send_message("humbug+errors@humbughq.com",
Recipient.STREAM, "devel", subject,
"~~~~ pytb\n%s\n\n~~~~\n%s" % (stack_trace, request_repr))
Recipient.STREAM, "devel", self.format_subject(subject),
"Error generated by %s\n\n~~~~ pytb\n%s\n\n~~~~\n%s" % (
user_info, stack_trace, request_repr))
def format_subject(self, subject):
"""
@ -59,3 +76,26 @@ class AdminHumbugHandler(logging.Handler):
formatted_subject = subject.replace('\n', '\\n').replace('\r', '\\r')
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)