Intro to Debugging with logger

Peter Haferl
4 min readSep 16, 2019

--

We have all written code that doesn’t work or doesn’t give us the results we want. The more complex the code is, the harder it is to debug. To do so, we need to check the progress of an iteration or function at specific checkpoints to find when the process goes awry. If you are like me, you have been doing this with the print function:

Here, we have some code that isn’t giving us the result we are looking for. By using the print method we are able to figure out the problem. We observe that upon every iteration, we get a total of 0 and the first iteration assigns i = 0. This is because the range starts at 0 instead of 1. We now can easily replace the range with range(1, n+1) and get the desired result:

Voila, that seemed to solve the issue and we were able to successfully debug with the print method! BUT, here comes the point when the print method suffers. We must now go back and remove the debugging print methods that we don’t want in the final program. Given such a simple example it doesn’t seem like such a bad scenario, especially when we are thrilled that our code finally works. However, when debugging more complex code, perhaps spanning hundreds or even thousands of lines of code, the task is long and tedious. Not only is it a lot of work, we could mistakenly delete print functions we want to keep and/or have to debug later on and have to redo the entire process.

Rest assured, there is an easier way. With the logging module in python we can get the same debugging capability as the print method and a bunch of other added functionality as well. Here is the logging module debugging the same code:

The logging process is initiated with the method logging.basicConfig(). Here we can set some base arguments to describe the type of readout we would like from the log messages. The arguments set include the logging level (more on this later) and the format of the readout (the date, time, logging level, logging message). The logging messages are then set using logging.debug() in a similar implementation as the print() function.

We get the same output message as with the print method, but now with some additional information. Furthermore, when we fix the code and no longer need to debug we can simply call logging.disable():

We no longer need to go back and delete the logging messages, relieving us of a lot of work of deleting the print message and allowing us to go back and debug if further problems arise. We can also run the logging.disable() code later in the program and any following logging messages will not be shown to the user.

All the debugging that we’ve seen so far has been done in the level of ‘DEBUG’ using logging.debug(). That is just one of 6 in the level hierarchy:

So here we have been working with DEBUG/logging.debug(), the 2nd to lowest level in terms of hierarchy. The hierarchical structure allows us to order our logging to prevent frivolous log messages to be displayed in the end program. For example, if we had log messages of each level and were done debugging at the INFO and DEBUG, but still want log messages of higher levels (WARNING/ERROR/CRITICAL) to display, we could set level equal to ’WARNING’ in the .basicConfig() method:

Lastly, if we do not wish to have any logging messages print during the running of the program and would rather have a separate text file to view outside of the development environment and/or output (e.g. you don’t want a bunch of error messages to litter your code output), you can export the error logs using the filename argument in the logging.basicConfig() method:

Output File Contents

That wraps up the basics of using the logging module for debugging your code in Python. For more details and special implementations, I suggest exploring the documentation. Happy debugging!

Resources:

  1. SWEIGART, AL. AUTOMATE THE BORING STUFF WITH PYTHON. No Starch Press, 2015.

--

--

Peter Haferl

Analytical chemist-turned-data scientist with a passion for data-driven investigations and decision making.