From 015000165373f8db263ef5bc682f02d74e5782ac Mon Sep 17 00:00:00 2001 From: Vinay Sajip Date: Wed, 19 Jun 2019 11:46:53 +0100 Subject: bpo-37258: Not a bug, but added a unit test and updated documentation. (GH-14229) --- Doc/library/logging.rst | 8 +++++--- Lib/test/test_logging.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index 3e4d7de..cc611fc 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -50,8 +50,8 @@ listed below. Logger Objects -------------- -Loggers have the following attributes and methods. Note that Loggers are never -instantiated directly, but always through the module-level function +Loggers have the following attributes and methods. Note that Loggers should +*NEVER* be instantiated directly, but always through the module-level function ``logging.getLogger(name)``. Multiple calls to :func:`getLogger` with the same name will always return a reference to the same Logger object. @@ -1244,7 +1244,9 @@ functions. The class should define :meth:`__init__` such that only a name argument is required, and the :meth:`__init__` should call :meth:`Logger.__init__`. This function is typically called before any loggers are instantiated by applications - which need to use custom logger behavior. + which need to use custom logger behavior. After this call, as at any other + time, do not instantiate loggers directly using the subclass: continue to use + the :func:`logging.getLogger` API to get your loggers. .. function:: setLogRecordFactory(factory) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index ac8919d..6507d79 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4172,6 +4172,37 @@ class ModuleLevelMiscTest(BaseTest): logging.setLoggerClass(logging.Logger) self.assertEqual(logging.getLoggerClass(), logging.Logger) + def test_subclass_logger_cache(self): + # bpo-37258 + message = [] + + class MyLogger(logging.getLoggerClass()): + def __init__(self, name='MyLogger', level=logging.NOTSET): + super().__init__(name, level) + message.append('initialized') + + logging.setLoggerClass(MyLogger) + logger = logging.getLogger('just_some_logger') + self.assertEqual(message, ['initialized']) + stream = io.StringIO() + h = logging.StreamHandler(stream) + logger.addHandler(h) + try: + logger.setLevel(logging.DEBUG) + logger.debug("hello") + self.assertEqual(stream.getvalue().strip(), "hello") + + stream.truncate(0) + stream.seek(0) + + logger.setLevel(logging.INFO) + logger.debug("hello") + self.assertEqual(stream.getvalue(), "") + finally: + logger.removeHandler(h) + h.close() + logging.setLoggerClass(logging.Logger) + @support.requires_type_collecting def test_logging_at_shutdown(self): # Issue #20037 -- cgit v0.12