method is enqueued.
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.
+ arguments, exception and stack information, if present. It also removes
+ unpickleable items from the record in-place. Specifically, it overwrites
+ the record's :attr:`msg` and :attr:`message` attributes with the merged
+ message (obtained by calling the handler's :meth:`format` method), and
+ sets the :attr:`args`, :attr:`exc_info` and :attr:`exc_text` attributes
+ to ``None``.
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
want to override this if you want to use blocking behaviour, or a
timeout, or a customized queue implementation.
+ .. attribute:: listener
+ When created via configuration using :func:`~logging.config.dictConfig`, this
+ attribute will contain a :class:`QueueListener` instance for use with this
+ handler. Otherwise, it will be ``None``.
+
+ .. versionadded:: 3.12
.. _queue-listener:
# (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 and exc_text attributes, as they are no longer
+ # exc_info, exc_text and stack_info attributes, as they are no longer
# needed and, if not None, will typically not be pickleable.
msg = self.format(record)
# bpo-35726: make copy of record to avoid affecting other handlers in the chain.
record.args = None
record.exc_info = None
record.exc_text = None
+ record.stack_info = None
return record
def emit(self, record):
@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).
+ # Test that traceback and stack-info only appends once (bpo-34334, bpo-46755).
listener = logging.handlers.QueueListener(self.queue, self.root_hdlr)
listener.start()
try:
except ZeroDivisionError as e:
exc = e
self.que_logger.exception(self.next_message(), exc_info=exc)
+ self.que_logger.error(self.next_message(), stack_info=True)
listener.stop()
self.assertEqual(self.stream.getvalue().strip().count('Traceback'), 1)
+ self.assertEqual(self.stream.getvalue().strip().count('Stack'), 1)
@unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
'logging.handlers.QueueListener required for this test')
--- /dev/null
+In :class:`QueueHandler`, clear ``stack_info`` from :class:`LogRecord` to
+prevent stack trace from being written twice.