Index: Doc/library/logging.rst =================================================================== --- Doc/library/logging.rst (revision 65034) +++ Doc/library/logging.rst (working copy) @@ -2348,8 +2348,13 @@ args=(sys.stdout,) The ``class`` entry indicates the handler's class (as determined by :func:`eval` -in the ``logging`` package's namespace). The ``level`` is interpreted as for -loggers, and ``NOTSET`` is taken to mean "log everything". +in the ``logging`` package's namespace, or resolved as a dotted module and class +name if the :func:`eval` failed). The ``level`` is interpreted as for loggers, +and ``NOTSET`` is taken to mean "log everything". + +.. versionchanged:: 2.6 + Added support for resolving the handler's class as a dotted module and class + name. The ``formatter`` entry indicates the key name of the formatter for this handler. If blank, a default formatter (``logging._defaultFormatter``) is used. Index: Lib/logging/config.py =================================================================== --- Lib/logging/config.py (revision 65034) +++ Lib/logging/config.py (working copy) @@ -146,7 +146,10 @@ fmt = cp.get(sectname, "formatter") else: fmt = "" - klass = eval(klass, vars(logging)) + try: + klass = eval(klass, vars(logging)) + except (AttributeError, NameError): + klass = _resolve(klass) args = cp.get(sectname, "args") args = eval(args, vars(logging)) h = apply(klass, args) Index: Lib/test/test_logging.py =================================================================== --- Lib/test/test_logging.py (revision 65034) +++ Lib/test/test_logging.py (working copy) @@ -584,6 +584,9 @@ datefmt= """ + # config5 specifies a custom handler class to be loaded + config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler') + def apply_config(self, conf): try: fn = tempfile.mktemp(".ini") @@ -609,10 +612,10 @@ # Original logger output is empty. self.assert_log_lines([]) - def test_config1_ok(self): + def test_config1_ok(self, config=config1): # A config file defining a sub-parser as well. with captured_stdout() as output: - self.apply_config(self.config1) + self.apply_config(config) logger = logging.getLogger("compiler.parser") # Both will output a message logger.info(self.next_message()) @@ -647,6 +650,9 @@ # Original logger output is empty self.assert_log_lines([]) + def test_config5_ok(self): + self.test_config1_ok(config=self.config5) + class LogRecordStreamHandler(StreamRequestHandler):