Python: How to use the logging module

Sending print statements to the console is very common in Python coding. It is simply a matter of using the key word print, followed by what you want printed to the screen. For example:

# variables
year = '2015'
xldate = 41000
pvid_list = ["19615056", "15612770", "15612771"]

# print a raw string
print "Print this string..."

# print a raw string and variable containing a string
print "The year is", year

# print three variables, containing a string, number, and list
print year, xldate, pvid_list

Which yields:

Print this string...
The year is 2015
2015 41000 ['19615056', '15612770', '15612771']

Now lets say you want to not only send print statements to the console, but you also want those print statements to be captured in a log. This can be ideal if you have a large script with many functions and you want to have a saved record that can be examined for each run of the script.

Python has a logging module that makes this possible. To use this module, you will need to include an ‘import logging’ statement at the top of your script. For the code example I will share for this tutorial, you will also need to import the ‘inspect’ module.

The code I am going to share includes a function called log_handlers that creates two handlers for the logging module.

  • StreamHandler() – controls what is printed to the console
  • FileHandler() – controls what is printed to the log file

Whenever you start your script, you will need to access this function to initialize the handlers. For example, in main():

global logger
logger = log_handlers(logging.INFO, logging.INFO)

Before your script ends, you should shut the logging module down. For example, I used this as the last line of code in main():

logging.shutdown()

In order to use the logger created previously, you will need to use the following code in place of a print statement. Where you would previously print a string to the console like this:

# print a raw string
print "Print this string..."

You can now print the same string to the console AND the log file by using logger.info() with the string in parenthesis, like this:

# print a raw string to both the console and the log
logger.info('Print this string...')

Where you would previously print a string and variable to the console like this:

# print a raw string and variable containing a string
print "The year is", year

You can now print the same string and variable to the console AND the log file using logger.info like this:

logger.info("The year is: %s" % (year))

Notice that the variable name year is in its own parenthesis. The string value stored in the variable will be substituted into the %s in the double quotes. This will yield the same results as the print statement.

Where you would previously print three variables, containing a string, number, and list like this:

# print three variables, containing a string, number, and list
print year, xldate, pvid_list

You can now print the same three variables to the console AND the log file using logger.info like this:

logger.info("%s %s %s" % (year, xldate, pvid_list))

Notice that all three variable names are in the parenthesis, separated by commas. Each of these point to their own %s placeholder in the string portion (in order). The first variable points to the first %s, the second variable points to the second %s, etc..

The output is the same as the print statement:

2015 41000 ['19615056', '15612770', '15612771']

All three lines also went to the log file, in this case called “Output_log_020615_1129.txt”:

The log file can be named anything you like. It can have the extension .txt or .log. In this example case, I used today’s date and timestamp as part of the name of the log. “Output_log_” + MMDDYY + “_” + HHMM + “.txt”.

Here is the log_handlers function that makes this work:

def log_handlers(file_level, console_level = None):
    function_name = inspect.stack()[1][3]
    logger = logging.getLogger(function_name)
    logger.setLevel(logging.DEBUG) #By default, DEBUG logs all messages

    #log_name = 'Output_log_' + getDate() + '.log'
    log_name = 'Output_log_' + getDate() + '_' + getTime() + '.txt'

    # Clear out existing handlers to avoid duplicated data
    logger.handlers = []

    if not logger.handlers:
        if console_level != None:
            ch = logging.StreamHandler() #StreamHandler logs to console
            ch.setLevel(console_level)
            ch_format = logging.Formatter('%(message)s')
            ch.setFormatter(ch_format)
            logger.addHandler(ch)

        #FileHandler logs to log file. mode='w' is optional for overwrite
        fh = logging.FileHandler(log_name.format(function_name), mode='w')
        fh.setLevel(file_level)
        fh_format = logging.Formatter('%(message)s')
        fh.setFormatter(fh_format)
        logger.addHandler(fh)

    return logger

The mode=‘w’ in the Filehandler setup is optional and will cause the log handler to overwrite the existing log file with each subsequent execution of your script. This can be left off and the default setting would be “append”.

fh = logging.FileHandler(log_name.format(function_name), mode='w')

For example:

fh = logging.FileHandler(log_name.format(function_name))

While this tutorial covers just a single use case, there are many other things that can be done with the logging module. For more details, visit the following website resources:
https://docs.python.org/2/library/logging.html
http://www.blog.pythonlibrary.org/2012/08/02/python-101-an-intro-to-logging

Complete Python code for this tutorial can be found on my github here:
https://github.com/chris-relaxing/python-how-to-use-logging