Playing with loggers

Shall we spend some time exploring a little bit about loggers? We shall! Let’s do it.

Visit the docs for more detailed information about the logging module. Let’s use a simple example, from the documentation, to illustrate the basic usage:

def simple_exmaple():
    # create logger
    logger = logging.getLogger('StreamHandler')
    logger.setLevel(logging.DEBUG)

    # create console handler and set level to debug
    ch = logging.StreamHandler()

    # create formatter
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    # add formatter to ch
    ch.setFormatter(formatter)

    # add ch to logger
    logger.addHandler(ch)

    # 'application' code
    logger.debug('debug message')
    logger.info('info message')
    logger.warn('warn message')
    logger.error('error message')
    logger.critical('critical message')

Initially we’re creating a new logger and setting it’s level to DEBUG. You can check the log levels here (with this level we can use debug and above levels). In the next step we create a handler, determining where we want to log to. In this case StreamHandler  will log to the console. Next we setup a formatter for our output and add it to our handler.  Our handler is ready so we add it to our logger. At last, we take out logger for a test run.

What if we want to log to a file? Couldn’t be easier:

def with_file_handler():
    # create logger
    logger = logging.getLogger('FileHandler')
    logger.setLevel(logging.DEBUG)

    # create console handler
    fh = logging.FileHandler('with_file_handler.log')

    # create formatter
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    # add formatter to fh
    fh.setFormatter(formatter)

    # add ch to logger
    logger.addHandler(fh)

    # 'application' code
    logger.debug('debug message')
    logger.info('info message')
    logger.warn('warn message')
    logger.error('error message')
    logger.critical('critical message')

Almost exactly the same, we only change the handler to a FileHandler and specify the log file name.

What if we want to log to both the console and a file? You can either use two loggers or add two handlers to the same logger. Let’s see how to accomplish the latter:

def with_both():
    # create logger
    logger = logging.getLogger('Both')
    logger.setLevel(logging.DEBUG)

    # create console handler and set level to debug
    ch = logging.StreamHandler()

    # create console handler and set level to debug
    fh = logging.FileHandler('with_both.log')    

    # create formatter
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    # add formatter to ch
    ch.setFormatter(formatter)
    fh.setFormatter(formatter)

    # add ch to logger
    logger.addHandler(ch)
    logger.addHandler(fh)

    # 'application' code
    logger.debug('debug message')
    logger.info('info message')
    logger.warn('warn message')
    logger.error('error message')
    logger.critical('critical message')

It’s just a combination of the two previous examples. You can even a little bit further and use the root logger:

def with_root_logger():

    # create console handler and set level to debug
    ch = logging.StreamHandler()
    
    # create console handler and set level to debug
    fh = logging.FileHandler('with_root_logger.log')
    
    # create formatter
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    # add formatter to ch
    ch.setFormatter(formatter)
    fh.setFormatter(formatter)

    # add ch to logger
    logging.getLogger().addHandler(ch)
    logging.getLogger().addHandler(fh)
    logging.getLogger().setLevel(logging.DEBUG)

    # 'application' code
    logging.debug('debug message')
    logging.info('info message')
    logging.warn('warn message')
    logging.error('error message')
    logging.critical('critical message')

Easy isn’t it? I hope this gives you a quick intro into the Python’s logging module. Don’t forget to visit the docs .