The Invent with Python Blog

Fri 06 April 2012

Stop Using "print" for Debugging: A 5 Minute Quickstart Guide to Python’s logging Module

Posted by Al Sweigart in python   

  • This tutorial is short.
  • To figure out bugs in your code, you might put in print statements/print() calls to display the value of variables.
  • Don’t do this. Use the Python logging module.

The logging is better than printing because:

  • It's easy to put a timestamp in each message, which is very handy.
  • You can have different levels of urgency for messages, and filter out less urgent messages.
  • When you want to later find/remove log messages, you won't get them confused for real print() calls.
  • If you just print to a log file, it's easy to leave the log function calls in and just ignore them when you don't need them. (You don't have to constantly pull out print() calls.)

Using print is for coders with too much time on their hands. Use logging instead. Also, learn to use the Python debugger to debug bugs and Pylint to prevent bugs and make your code readable.

To print log messages to the screen, copy and paste this code:

import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
logging.debug('This is a log message.')

To write log messages to a file, you can copy and paste this code (the only difference is in bold):

import logging
logging.basicConfig(filename='log_filename.txt', level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
logging.debug('This is a log message.')

Later runs of the program will append to the end of the log file, rather than overwrite the file.

To log messages to a file AND printed to the screen, copy and paste the following:

import logging
logger = logging.getLogger()

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

fh = logging.FileHandler('log_filename.txt')

ch = logging.StreamHandler()

logger.debug('This is a test log message.')

Make sure that the logger variable is global, so that you can use it in functions. (You don't need the "global logger" at the top of the function, because the logger variable is only read, not modified.)

The different levels of logging, from highest urgency to lowest urgency, are:

  2. ERROR
  4. INFO
  5. DEBUG

The setLevel() call sets the minimum log level of messages it actually logs. So if you fh.setLevel(logging.ERROR), then WARNING, INFO, and DEBUG log messages will not be written to the log file (since fh is the log handler for the log file, as opposed to ch which is the handler for the console screen.)

To write a log message in one of these five levels, use the following functions:

  1. logger.critical('This is a critical message.')
  2. logger.error('This is an error message.')
  3. logger.warning('This is a warning message.')
  4.'This is an informative message.')
  5. logger.debug('This is a low-level debug message.')

There's plenty more you can do, but this all you need to know to never again use print() calls to do your debugging work.

The Python documentation has more info, including a Basic Tutorial, an Advanced Tutorial, and a Logging Cookbook.

Also, the pprint.pprint() function is great for "pretty printing" dictionaries and lists that have nested dictionaries and lists in them. The pprint.pformat() function returns the string of this content, rather than printing it to the screen.

One final tip: You can use the tail -f logfile.txt command to show a file as it is being written to. The -f stands for "follow". Just leave a terminal/console window open with this command running, and new text in the log file will appear as it is written. This way, you don't have to keep opening/reloading a text editor to view the latest text in the log file.

The tail command comes on Mac OS X and Linux OSes. On Windows, you can download the Cygwin project to get the tail command.


Learn to program with my books for beginners, free under a Creative Commons license:

Take my Automate the Boring Stuff with Python online Udemy course. Use this link to apply a 60% discount.