From b960e4ed722a04a9db0d35293f76e253eedf9126 Mon Sep 17 00:00:00 2001 From: Ayush Bansal Date: Sat, 12 Dec 2020 12:58:43 +0530 Subject: [PATCH] Fixed #32261 -- Added error logging to Signal.send_robust(). --- django/dispatch/dispatcher.py | 9 +++++++++ docs/releases/3.2.txt | 3 ++- tests/dispatch/tests.py | 29 ++++++++++++++++++++++------- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/django/dispatch/dispatcher.py b/django/dispatch/dispatcher.py index b7d9d26389..5ad0659f83 100644 --- a/django/dispatch/dispatcher.py +++ b/django/dispatch/dispatcher.py @@ -1,3 +1,4 @@ +import logging import threading import warnings import weakref @@ -5,6 +6,8 @@ import weakref from django.utils.deprecation import RemovedInDjango40Warning from django.utils.inspect import func_accepts_kwargs +logger = logging.getLogger('django.dispatch') + def _make_id(target): if hasattr(target, '__func__'): @@ -208,6 +211,12 @@ class Signal: try: response = receiver(signal=self, sender=sender, **named) except Exception as err: + logger.error( + 'Error calling %s in Signal.send_robust() (%s)', + receiver.__qualname__, + err, + exc_info=err, + ) responses.append((receiver, err)) else: responses.append((receiver, response)) diff --git a/docs/releases/3.2.txt b/docs/releases/3.2.txt index b155f37e00..93b60690b3 100644 --- a/docs/releases/3.2.txt +++ b/docs/releases/3.2.txt @@ -420,7 +420,8 @@ Serialization Signals ~~~~~~~ -* ... +* :meth:`Signal.send_robust() ` now logs + exceptions. Templates ~~~~~~~~~ diff --git a/tests/dispatch/tests.py b/tests/dispatch/tests.py index 9b5482ed58..30a9354bba 100644 --- a/tests/dispatch/tests.py +++ b/tests/dispatch/tests.py @@ -165,13 +165,28 @@ class DispatcherTests(SimpleTestCase): def fails(val, **kwargs): raise ValueError('this') a_signal.connect(fails) - result = a_signal.send_robust(sender=self, val="test") - err = result[0][1] - self.assertIsInstance(err, ValueError) - self.assertEqual(err.args, ('this',)) - self.assertTrue(hasattr(err, '__traceback__')) - self.assertIsInstance(err.__traceback__, TracebackType) - a_signal.disconnect(fails) + try: + with self.assertLogs('django.dispatch', 'ERROR') as cm: + result = a_signal.send_robust(sender=self, val='test') + err = result[0][1] + self.assertIsInstance(err, ValueError) + self.assertEqual(err.args, ('this',)) + self.assertIs(hasattr(err, '__traceback__'), True) + self.assertIsInstance(err.__traceback__, TracebackType) + + log_record = cm.records[0] + self.assertEqual( + log_record.getMessage(), + 'Error calling ' + 'DispatcherTests.test_send_robust_fail..fails in ' + 'Signal.send_robust() (this)', + ) + self.assertIsNotNone(log_record.exc_info) + _, exc_value, _ = log_record.exc_info + self.assertIsInstance(exc_value, ValueError) + self.assertEqual(str(exc_value), 'this') + finally: + a_signal.disconnect(fails) self.assertTestIsClean(a_signal) def test_disconnection(self):