fix: queue=True no longer strips exc_info before JsonLinesFormatter sees it
QueueHandler.prepare() formatted the record with its own default formatter and nulled exc_info/exc_text/stack_info before the listener's real formatter ran, so queue=True + output="json" produced a JSON line with no exc_info key and the traceback folded into message instead. _PreservingQueueHandler skips that premature format-and-strip (safe here - the queue is in-process only, nothing needs to stay picklable) so the listener's handler formats the untouched record exactly once, matching the non-queued path. Signed-off-by: disqualifier <dev@disqualifier.me>
This commit is contained in:
+17
-1
@@ -29,6 +29,22 @@ _listener = None
|
|||||||
_atexit_registered = False
|
_atexit_registered = False
|
||||||
|
|
||||||
|
|
||||||
|
class _PreservingQueueHandler(logging.handlers.QueueHandler):
|
||||||
|
"""QueueHandler that hands the record to the listener untouched
|
||||||
|
|
||||||
|
stdlib's QueueHandler.prepare() calls self.format(record) with the queue
|
||||||
|
handler's OWN (default) formatter, then nulls exc_info/exc_text/stack_info -
|
||||||
|
losing structured fields (e.g. JsonLinesFormatter's exc_info key) before the
|
||||||
|
listener's real formatter ever sees the record. that behavior exists to keep a
|
||||||
|
record picklable across a multiprocessing.Queue; this lib only ever uses an
|
||||||
|
in-process queue.Queue, so there is nothing to pickle and nothing to strip -
|
||||||
|
the listener's handler formats the untouched record exactly once.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def prepare(self, record: logging.LogRecord) -> logging.LogRecord:
|
||||||
|
return record
|
||||||
|
|
||||||
|
|
||||||
def _exc_text() -> str:
|
def _exc_text() -> str:
|
||||||
"""render sys.exc_info() as text, for capturing a traceback into a buffered warning"""
|
"""render sys.exc_info() as text, for capturing a traceback into a buffered warning"""
|
||||||
return "".join(traceback.format_exception(*sys.exc_info())).strip()
|
return "".join(traceback.format_exception(*sys.exc_info())).strip()
|
||||||
@@ -284,7 +300,7 @@ def setup_logging(
|
|||||||
|
|
||||||
if queue:
|
if queue:
|
||||||
record_queue: "_queue.Queue" = _make_queue()
|
record_queue: "_queue.Queue" = _make_queue()
|
||||||
qh = _tag(logging.handlers.QueueHandler(record_queue))
|
qh = _tag(_PreservingQueueHandler(record_queue))
|
||||||
root.addHandler(qh)
|
root.addHandler(qh)
|
||||||
_listener = logging.handlers.QueueListener(record_queue, *handlers, respect_handler_level=True)
|
_listener = logging.handlers.QueueListener(record_queue, *handlers, respect_handler_level=True)
|
||||||
_listener.start()
|
_listener.start()
|
||||||
|
|||||||
Reference in New Issue
Block a user