From d345bb4d9b6e16c681cd8a4e1fff94ecd6b0bb09 Mon Sep 17 00:00:00 2001 From: Cheryl Sabella Date: Tue, 25 Sep 2018 19:00:08 -0400 Subject: [PATCH] bpo-34334: Don't log traceback twice in QueueHandler (GH-9537) --- Doc/library/logging.handlers.rst | 6 +++--- Lib/logging/handlers.py | 5 +++-- Lib/test/test_logging.py | 15 +++++++++++++++ .../2018-09-25-08-42-34.bpo-34334.rSPBW9.rst | 2 ++ 4 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2018-09-25-08-42-34.bpo-34334.rSPBW9.rst diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst index bdf16a8177e..dee9a84e333 100644 --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -973,9 +973,9 @@ possible, while any potentially slow operations (such as sending an email via Prepares a record for queuing. The object returned by this method is enqueued. - The base implementation formats the record to merge the message - and arguments, and removes unpickleable items from the record - in-place. + The base implementation formats the record to merge the message, + arguments, and exception information, if present. It also + removes unpickleable items from the record in-place. You might want to override this method if you want to convert the record to a dict or JSON string, or send a modified copy diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index 974c089d40e..e213e438c31 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -1374,13 +1374,14 @@ class QueueHandler(logging.Handler): # (if there's exception data), and also returns the formatted # message. We can then use this to replace the original # msg + args, as these might be unpickleable. We also zap the - # exc_info attribute, as it's no longer needed and, if not None, - # will typically not be pickleable. + # exc_info and exc_text attributes, as they are no longer + # needed and, if not None, will typically not be pickleable. msg = self.format(record) record.message = msg record.msg = msg record.args = None record.exc_info = None + record.exc_text = None return record def emit(self, record): diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index b9dad64a594..d352e5fa3f3 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3345,6 +3345,21 @@ class QueueHandlerTest(BaseTest): self.assertFalse(handler.matches(levelno=logging.WARNING, message='4')) self.assertFalse(handler.matches(levelno=logging.ERROR, message='5')) self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6')) + handler.close() + + @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'), + 'logging.handlers.QueueListener required for this test') + def test_queue_listener_with_StreamHandler(self): + # Test that traceback only appends once (bpo-34334). + listener = logging.handlers.QueueListener(self.queue, self.root_hdlr) + listener.start() + try: + 1 / 0 + except ZeroDivisionError as e: + exc = e + self.que_logger.exception(self.next_message(), exc_info=exc) + listener.stop() + self.assertEqual(self.stream.getvalue().strip().count('Traceback'), 1) if hasattr(logging.handlers, 'QueueListener'): import multiprocessing diff --git a/Misc/NEWS.d/next/Library/2018-09-25-08-42-34.bpo-34334.rSPBW9.rst b/Misc/NEWS.d/next/Library/2018-09-25-08-42-34.bpo-34334.rSPBW9.rst new file mode 100644 index 00000000000..137a4f78f42 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-09-25-08-42-34.bpo-34334.rSPBW9.rst @@ -0,0 +1,2 @@ +In :class:`QueueHandler`, clear `exc_text` from :class:`LogRecord` to +prevent traceback from being written twice.