Logging in modules

In every module, import the logging module

import logging

In every module routine, use the snippet

logger = logging.getLogger(__name__)

Do not create a logger at module level.

In the routine, you may generate e.g. a debug message with

logger.debug("This is a debug message")

Logging in scripts – Configuring the root logger

Every script should configure the root level logger (e.g. in the main routine)

logger = logging.getLogger()
logger.setLevel(logging.INFO)

See http://victorlin.me/posts/2012/08/26/good-logging-practice-in-python for further configuration options.

Is is important that getLogger is called with no arguments, in order to obtain the root logger. Any options set for the root logger are passed to all loggers in the hierarchy.

Note that creating the logger explicitly is more robust than the alternative method for configuring the root level logger through module methods, e.g.

logging.basicConfig(level=logging.INFO)

This statement will have no effect if there are already any handlers set on the root level logger.

Logger hierarchy

Use the following routine to get a detailed overview of the logging hierarchy

def show_loggers():
    loggers = [('root', logging.getLogger())]
    for name in sorted(logging.Logger.manager.loggerDict.keys()):
        logger = logging.getLogger(name)
        loggers.append( (name, logger) )
    for name, logger in loggers:
        indent = ""
        if name != 'root':
            indent = "   "*(name.count('.')+1)
        if logger.propagate:
            prop = "+ "
        else:
            prop = "  "
        handlers = ""
        if len(logger.handlers) > 0:
            handlers = ": " + str(logger.handlers)
        level = logging.getLevelName(logger.level)
        eff_level = logging.getLevelName(logger.getEffectiveLevel())
        if level == eff_level:
            level_str = ' [%s]' % level
        else:
            level_str = ' [%s -> %s]' % (level, eff_level)
        print indent + prop + name + level_str + handlers