Closes #26559: Allow configuring flush-on-close behaviour of MemoryHandler.

This commit is contained in:
Vinay Sajip 2016-07-22 16:27:31 +01:00
parent d141531eb5
commit cccf6068fa
3 changed files with 54 additions and 8 deletions

View file

@ -806,12 +806,18 @@ should, then :meth:`flush` is expected to do the flushing.
overridden to implement custom flushing strategies. overridden to implement custom flushing strategies.
.. class:: MemoryHandler(capacity, flushLevel=ERROR, target=None) .. class:: MemoryHandler(capacity, flushLevel=ERROR, target=None, flushOnClose=True)
Returns a new instance of the :class:`MemoryHandler` class. The instance is Returns a new instance of the :class:`MemoryHandler` class. The instance is
initialized with a buffer size of *capacity*. If *flushLevel* is not specified, initialized with a buffer size of *capacity*. If *flushLevel* is not specified,
:const:`ERROR` is used. If no *target* is specified, the target will need to be :const:`ERROR` is used. If no *target* is specified, the target will need to be
set using :meth:`setTarget` before this handler does anything useful. set using :meth:`setTarget` before this handler does anything useful. If
*flushOnClose* is specified as ``False``, then the buffer is *not* flushed when
the handler is closed. If not specified or specified as ``True``, the previous
behaviour of flushing the buffer will occur when the handler is closed.
.. versionchanged:: 3.6
The *flushOnClose* parameter was added.
.. method:: close() .. method:: close()

View file

@ -1,4 +1,4 @@
# Copyright 2001-2015 by Vinay Sajip. All Rights Reserved. # Copyright 2001-2016 by Vinay Sajip. All Rights Reserved.
# #
# Permission to use, copy, modify, and distribute this software and its # Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted, # documentation for any purpose and without fee is hereby granted,
@ -18,7 +18,7 @@
Additional handlers for the logging package for Python. The core package is Additional handlers for the logging package for Python. The core package is
based on PEP 282 and comments thereto in comp.lang.python. based on PEP 282 and comments thereto in comp.lang.python.
Copyright (C) 2001-2015 Vinay Sajip. All Rights Reserved. Copyright (C) 2001-2016 Vinay Sajip. All Rights Reserved.
To use, simply 'import logging.handlers' and log away! To use, simply 'import logging.handlers' and log away!
""" """
@ -1238,17 +1238,25 @@ class MemoryHandler(BufferingHandler):
flushing them to a target handler. Flushing occurs whenever the buffer flushing them to a target handler. Flushing occurs whenever the buffer
is full, or when an event of a certain severity or greater is seen. is full, or when an event of a certain severity or greater is seen.
""" """
def __init__(self, capacity, flushLevel=logging.ERROR, target=None): def __init__(self, capacity, flushLevel=logging.ERROR, target=None,
flushOnClose=True):
""" """
Initialize the handler with the buffer size, the level at which Initialize the handler with the buffer size, the level at which
flushing should occur and an optional target. flushing should occur and an optional target.
Note that without a target being set either here or via setTarget(), Note that without a target being set either here or via setTarget(),
a MemoryHandler is no use to anyone! a MemoryHandler is no use to anyone!
The ``flushOnClose`` argument is ``True`` for backward compatibility
reasons - the old behaviour is that when the handler is closed, the
buffer is flushed, even if the flush level hasn't been exceeded nor the
capacity exceeded. To prevent this, set ``flushOnClose`` to ``False``.
""" """
BufferingHandler.__init__(self, capacity) BufferingHandler.__init__(self, capacity)
self.flushLevel = flushLevel self.flushLevel = flushLevel
self.target = target self.target = target
# See Issue #26559 for why this has been added
self.flushOnClose = flushOnClose
def shouldFlush(self, record): def shouldFlush(self, record):
""" """
@ -1282,10 +1290,12 @@ class MemoryHandler(BufferingHandler):
def close(self): def close(self):
""" """
Flush, set the target to None and lose the buffer. Flush, if appropriately configured, set the target to None and lose the
buffer.
""" """
try: try:
self.flush() if self.flushOnClose:
self.flush()
finally: finally:
self.acquire() self.acquire()
try: try:

View file

@ -958,7 +958,7 @@ class MemoryHandlerTest(BaseTest):
def setUp(self): def setUp(self):
BaseTest.setUp(self) BaseTest.setUp(self)
self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING, self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
self.root_hdlr) self.root_hdlr)
self.mem_logger = logging.getLogger('mem') self.mem_logger = logging.getLogger('mem')
self.mem_logger.propagate = 0 self.mem_logger.propagate = 0
self.mem_logger.addHandler(self.mem_hdlr) self.mem_logger.addHandler(self.mem_hdlr)
@ -995,6 +995,36 @@ class MemoryHandlerTest(BaseTest):
self.mem_logger.debug(self.next_message()) self.mem_logger.debug(self.next_message())
self.assert_log_lines(lines) self.assert_log_lines(lines)
def test_flush_on_close(self):
"""
Test that the flush-on-close configuration works as expected.
"""
self.mem_logger.debug(self.next_message())
self.assert_log_lines([])
self.mem_logger.info(self.next_message())
self.assert_log_lines([])
self.mem_logger.removeHandler(self.mem_hdlr)
# Default behaviour is to flush on close. Check that it happens.
self.mem_hdlr.close()
lines = [
('DEBUG', '1'),
('INFO', '2'),
]
self.assert_log_lines(lines)
# Now configure for flushing not to be done on close.
self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING,
self.root_hdlr,
False)
self.mem_logger.addHandler(self.mem_hdlr)
self.mem_logger.debug(self.next_message())
self.assert_log_lines(lines) # no change
self.mem_logger.info(self.next_message())
self.assert_log_lines(lines) # no change
self.mem_logger.removeHandler(self.mem_hdlr)
self.mem_hdlr.close()
# assert that no new lines have been added
self.assert_log_lines(lines) # no change
class ExceptionFormatter(logging.Formatter): class ExceptionFormatter(logging.Formatter):
"""A special exception formatter.""" """A special exception formatter."""