Python logging before you run logging.basicConfig?

You can remove the default handlers and reconfigure logging like this:

# if someone tried to log something before basicConfig is called, Python creates a default handler that
# goes to the console and will ignore further basicConfig calls. Remove the handler if there is one.
root = logging.getLogger()
if root.handlers:
    for handler in root.handlers:
        root.removeHandler(handler)
logging.basicConfig(format='%(asctime)s %(message)s',level=logging.DEBUG)

Yes.

You've asked to log something. Logging must, therefore, fabricate a default configuration. Once logging is configured... well... it's configured.

"With the logger object configured, the following methods create log messages:"

Further, you can read about creating handlers to prevent spurious logging. But that's more a hack for bad implementation than a useful technique.

There's a trick to this.

  1. No module can do anything except logging.getlogger() requests at a global level.

  2. Only the if __name__ == "__main__": can do a logging configuration.

If you do logging at a global level in a module, then you may force logging to fabricate it's default configuration.

Don't do logging.info globally in any module. If you absolutely think that you must have logging.info at a global level in a module, then you have to configure logging before doing imports. This leads to unpleasant-looking scripts.


This answer from Carlos A. Ibarra is in principle right, however that implementation might break since you are iterating over a list that might be changed by calling removeHandler(). This is unsafe. Two alternatives are:

while len(logging.root.handlers) > 0:
    logging.root.removeHandler(logging.root.handlers[-1])
logging.basicConfig(format='%(asctime)s %(message)s',level=logging.DEBUG)

or:

logging.root.handlers = []
logging.basicConfig(format='%(asctime)s %(message)s',level=logging.DEBUG)

where the first of these two using the loop is the safest (since any destruction code for the handler can be called explicitly inside the logging framework). Still, this is a hack, since we rely on logging.root.handlers to be a list.


Here's the one piece of the puzzle that the above answers didn't mention... and then it will all make sense: the "root" logger -- which is used if you call, say, logging.info() before logging.basicConfig(level=logging.DEBUG) -- has a default logging level of WARNING.

That's why logging.info() and logging.debug() don't do anything: because you've configured them not to, by... um... not configuring them.

Possibly related (this one bit me): when NOT calling basicConfig, I didn't seem to be getting my debug messages, even though I set my handlers to DEBUG level. After a bit of hair-pulling, I found you have to set the level of the custom logger to be DEBUG as well. If your logger is set to WARNING, then setting a handler to DEBUG (by itself) won't get you any output on logger.info() and logger.debug().

Tags:

Python

Logging