diff --git a/AUTHORS b/AUTHORS index 7a04f1f243..43406da7d7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -588,6 +588,7 @@ answer newbie questions, and generally made Django that much better: Gasper Zejn Jarek Zgoda Cheng Zhang + Hannes Struß A big THANK YOU goes to: diff --git a/django/utils/log.py b/django/utils/log.py index 4806527e84..736154a178 100644 --- a/django/utils/log.py +++ b/django/utils/log.py @@ -3,6 +3,7 @@ import traceback from django.conf import settings from django.core import mail +from django.core.mail import get_connection from django.views.debug import ExceptionReporter, get_exception_reporter_filter @@ -76,9 +77,10 @@ class AdminEmailHandler(logging.Handler): request data will be provided in the email report. """ - def __init__(self, include_html=False): + def __init__(self, include_html=False, email_backend=None): logging.Handler.__init__(self) self.include_html = include_html + self.email_backend = email_backend def emit(self, record): try: @@ -110,7 +112,12 @@ class AdminEmailHandler(logging.Handler): message = "%s\n\n%s" % (stack_trace, request_repr) reporter = ExceptionReporter(request, is_email=True, *exc_info) html_message = self.include_html and reporter.get_traceback_html() or None - mail.mail_admins(subject, message, fail_silently=True, html_message=html_message) + mail.mail_admins(subject, message, fail_silently=True, + html_message=html_message, + connection=self.connection()) + + def connection(self): + return get_connection(backend=self.email_backend) def format_subject(self, subject): """ diff --git a/docs/topics/logging.txt b/docs/topics/logging.txt index d016b59969..c2503bbde4 100644 --- a/docs/topics/logging.txt +++ b/docs/topics/logging.txt @@ -440,7 +440,7 @@ Handlers Django provides one log handler in addition to those provided by the Python logging module. -.. class:: AdminEmailHandler([include_html=False]) +.. class:: AdminEmailHandler(include_html=False, email_backend=None) This handler sends an email to the site admins for each log message it receives. @@ -476,6 +476,23 @@ Python logging module. sensitive information to be filtered out of error reports -- learn more on :ref:`Filtering error reports`. + .. versionadded:: 1.5 + + By setting the ``email_backend`` argument of ``AdminEmailHandler``, the + :ref:`email backend ` that is being used by the + handler can be overridden, like this:: + + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'class': 'django.utils.log.AdminEmailHandler', + 'email_backend': 'django.core.mail.backends.filebased.EmailBackend', + } + }, + + By default, an instance of the email backend specified in + :setting:`EMAIL_BACKEND` will be used. + .. _Sentry: http://pypi.python.org/pypi/sentry diff --git a/tests/regressiontests/logging_tests/logconfig.py b/tests/regressiontests/logging_tests/logconfig.py index fc5ea1a0bd..b068103eb9 100644 --- a/tests/regressiontests/logging_tests/logconfig.py +++ b/tests/regressiontests/logging_tests/logconfig.py @@ -1,8 +1,15 @@ import logging from django.conf import settings +from django.core.mail.backends.base import BaseEmailBackend + class MyHandler(logging.Handler): def __init__(self): logging.Handler.__init__(self) self.config = settings.LOGGING + + +class MyEmailBackend(BaseEmailBackend): + def send_messages(self, email_messages): + pass diff --git a/tests/regressiontests/logging_tests/tests.py b/tests/regressiontests/logging_tests/tests.py index 0e56195c41..19ee06eccc 100644 --- a/tests/regressiontests/logging_tests/tests.py +++ b/tests/regressiontests/logging_tests/tests.py @@ -15,6 +15,8 @@ from django.utils.unittest import skipUnless from ..admin_scripts.tests import AdminScriptTestCase +from .logconfig import MyEmailBackend + PYVERS = sys.version_info[:2] # logging config prior to using filter with mail_admins @@ -305,6 +307,38 @@ class AdminEmailHandlerTest(TestCase): self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].subject, expected_subject) + @override_settings( + ADMINS=(('admin', 'admin@example.com'),), + DEBUG=False, + ) + def test_uses_custom_email_backend(self): + """ + Refs #19325 + """ + message = 'All work and no play makes Jack a dull boy' + admin_email_handler = self.get_admin_email_handler(self.logger) + mail_admins_called = {'called': False} + + def my_mail_admins(*args, **kwargs): + connection = kwargs['connection'] + self.assertTrue(isinstance(connection, MyEmailBackend)) + mail_admins_called['called'] = True + + # Monkeypatches + orig_mail_admins = mail.mail_admins + orig_email_backend = admin_email_handler.email_backend + mail.mail_admins = my_mail_admins + admin_email_handler.email_backend = ( + 'regressiontests.logging_tests.logconfig.MyEmailBackend') + + try: + self.logger.error(message) + self.assertTrue(mail_admins_called['called']) + finally: + # Revert Monkeypatches + mail.mail_admins = orig_mail_admins + admin_email_handler.email_backend = orig_email_backend + class SettingsConfigTest(AdminScriptTestCase): """