Logging oddity: handlers mandatory in every single logger?

Jean-Michel Pichavant jeanmichel at sequans.com
Tue Feb 2 13:26:32 CET 2010

Masklinn wrote:
> When trying to load the following config file, I get an error ``ConfigParser.NoOptionError: No option 'handlers' in section: 'logger_0'`` (in both Python 2.6.4 and  Python 3.1.1 on OSX, obviously ConfigParser is spelled configparser in 3.1):
>     [loggers]
>     keys=root,0
>     [handlers]
>     keys=console
>     [formatters]
>     keys=simple
>     [logger_root]
>     handlers=console
>     [logger_0]
>     level=DEBUG
>     qualname=0
>     [handler_console]
>     class=StreamHandler
>     formatter=simple
>     args=()
>     [formatter_simple]
>     format=%(asctime)s:%(levelname)-8s:%(name)s::%(message)s
> the goal is simply to have a logging level different on ``0`` than it is on ``root``, but to get it I have to include a handler on ``0`` and stop propagation (or messages are displayed on both root and 0).
> Do note that this behavior (of mandating handlers) does *not* happen when loggers are configured programmatically.
> Should this be considered a bug? Worthy of opening a request on the tracker?
> And while I'm at it, a few other oddities/annoyances I noticed in logging:
> * have to specify the `root` logger in loggers/keys, even though it's mandatory to configure the root logger, or I get the following error::
>     Traceback (most recent call last):
>       File "test.py", line 6, in <module>
>         logging.config.fileConfig('logging.conf')
>       File "/opt/local/Library/Frameworks/Python.framework/Versions/3.1/lib/python3.1/logging/config.py", line 82, in fileConfig
>         _install_loggers(cp, handlers, disable_existing_loggers)
>       File "/opt/local/Library/Frameworks/Python.framework/Versions/3.1/lib/python3.1/logging/config.py", line 183, in _install_loggers
>         llist.remove("root")
>     ValueError: list.remove(x): x not in list
> * the ``args`` option is required when defining a handler, even in the example above where the handler doesn't take any argument (mandatory ones, anyway)
> * Logger.log() doesn't take level names, only numerical levels, even after having called ``addLevelName``. This makes logging with custom levels much less clear as one has to write something along the lines of ``logging.log(100, 'Houston, we have a problem')`` instead of the clearer ``logging.log('PANTS_ON_FIRE', 'Houston, we have a problem')``. Note that since the introduction of _checkLevel fixing that is trivial:
To add a custom level, I would proceed that way:

logging.ALERT = 45
logging.addLevelName(logging.ALERT, 'ALERT !!')
logging.getLogger().log(logging.ALERT, 'test')

Passing a string to the log method as you did is incorrect.

Regarding your first point, I guess it's anti pattern. One way to do it:
1/ Configure the root logger with the lowest value 0, so the root logger 
does not filter any level.
2/ Configure each of your logger with the correct level

That way you can configure your '0' logger as you (badly :o)) named it 
with one level, and configure a potential '1' logger with another level. 
Don't bother with propagation. That way you won't need to duplicate your 
handlers on every logger.


More information about the Python-list mailing list