logging.config.fileConfig disables existing loggers
rcrida at gmail.com
Thu Aug 30 14:05:41 CEST 2007
I have been grappling today with some unexpected behaviour from
I am using the following config file:
format="%(asctime)s - %(name)s - %(filename)s:%(lineno)s - %
(levelname)s - %(message)s"
As you can see, it sets the root logger level to be DEBUG. I would
expect this to have the same effect as calling logger.basicConfig with
a level = DEBUG. What instead happens is that all my loggers become
disabled. One might argue that the loggers should only be created
after configuring the logger, but what about using the listening
method to configure again later...
While I can understand that the application of a new config file is
not incremental, ie should override any previous configuration
completely, it does not appear right that only loggers explicitly
named in the config file are enabled. I would expect that if I enabled
a particular logger then all child loggers should be enabled too.
Alternatively one needs to know the names of all loggers a-priori in
order to be able to monitor them.
So I took the liberty to try to discern what is going on. The culprit
(from my perspective) was the logging.config._install_loggers method,
particularly the last two lines which disable any logger not mentioned
in the config file. If those lines are deleted and a new loop is
created at the top of the function which resets all existing loggers
to their default status, then we see the desired behaviour. This seems
quite simple and sensible. Below is a patch file for applying the
change. What do people think?
--- config.py.old 2007-08-30 13:42:39.000000000 +0200
+++ config.py 2007-08-30 13:53:15.000000000 +0200
@@ -173,6 +173,14 @@
def _install_loggers(cp, handlers):
"""Create and install loggers"""
+ # reset all existing loggers so that they can inherit new
+ for log in logging.root.manager.loggerDict.keys():
+ logger = logging.root.manager.loggerDict[log]
+ logger.level = logging.NOTSET
+ logger.propagate = 1
+ logger.handlers = 
+ logger.disabled = 0
# configure the root first
llist = cp.get("loggers", "keys")
llist = string.split(llist, ",")
@@ -192,16 +200,6 @@
for hand in hlist:
- #and now the others...
- #we don't want to lose the existing loggers,
- #since other threads may have pointers to them.
- #existing is set to contain all existing loggers,
- #and as we go through the new configuration we
- #remove any which are configured. At the end,
- #what's left in existing is the set of loggers
- #which were in the previous configuration but
- #which are not in the new configuration.
- existing = root.manager.loggerDict.keys()
#now set up the new ones...
for log in llist:
sectname = "logger_%s" % log
@@ -212,8 +210,6 @@
propagate = 1
logger = logging.getLogger(qn)
- if qn in existing:
if "level" in opts:
level = cp.get(sectname, "level")
@@ -227,12 +223,6 @@
for hand in hlist:
- #Disable any old loggers. There's no point deleting
- #them as other threads may continue to hold references
- #and by disabling them, you stop them doing any logging.
- for log in existing:
- root.manager.loggerDict[log].disabled = 1
More information about the Python-list