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

  • 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() logger.setLevel(logging.DEBUG) formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') fh = logging.FileHandler('log_filename.txt') fh.setLevel(logging.DEBUG) fh.setFormatter(formatter) logger.addHandler(fh) ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) ch.setFormatter(formatter) logger.addHandler(ch) 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:

  1. CRITICAL
  2. ERROR
  3. WARNING
  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. logger.info('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.


Page 1 of 2 | Next page