diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst index 4eaea09bad1..266a50084e0 100644 --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -806,12 +806,18 @@ should, then :meth:`flush` is expected to do the flushing. 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 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 - 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() diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index c0748a8853f..296d6cfa30f 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -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 # 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 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! """ @@ -1238,17 +1238,25 @@ class MemoryHandler(BufferingHandler): 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. """ - 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 flushing should occur and an optional target. Note that without a target being set either here or via setTarget(), 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) self.flushLevel = flushLevel self.target = target + # See Issue #26559 for why this has been added + self.flushOnClose = flushOnClose def shouldFlush(self, record): """ @@ -1282,10 +1290,12 @@ class MemoryHandler(BufferingHandler): 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: - self.flush() + if self.flushOnClose: + self.flush() finally: self.acquire() try: diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 062df0f7468..9e9a439eab5 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -958,7 +958,7 @@ class MemoryHandlerTest(BaseTest): def setUp(self): BaseTest.setUp(self) self.mem_hdlr = logging.handlers.MemoryHandler(10, logging.WARNING, - self.root_hdlr) + self.root_hdlr) self.mem_logger = logging.getLogger('mem') self.mem_logger.propagate = 0 self.mem_logger.addHandler(self.mem_hdlr) @@ -995,6 +995,36 @@ class MemoryHandlerTest(BaseTest): self.mem_logger.debug(self.next_message()) 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): """A special exception formatter."""