Python Fundamentals Tutorial: Debugging Tools

15. Debugging Tools

15.1. logging

The logging module in the Python standard libraries is similar in function to log4j and all of its derivatives in other languages. Logging configuration is hierarchical and can range from very simple to very complex to suit application needs.

Here is an example of a very standard logging configuration and its usage.

Note that you should ideally find a place in your application that will only be executed once in order to configure the logging.

logconfig.py. 

import logging
from logging import handlers

def config():
    logger = logging.getLogger('app')
    logger.setLevel(logging.ERROR)
    handler = handlers.RotatingFileHandler(
            'debug.log',
            maxBytes=(1024*1024),
            backupCount=5
            )
    formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)

    logger = logging.getLogger('app.othersub')
    logger.setLevel(logging.DEBUG)

debug-1-logging.py. 

import logging

from logconfig import config

config()

logger = logging.getLogger('app.sub')
logger.debug('something interesting just happened')
logger.error('something horrible just happened')

logger2 = logging.getLogger('app.othersub')
logger2.debug('HMM> something interesting just happened')
logger2.setLevel(logging.DEBUG)
logger2.error('UH-OH> something horrible just happened')

class YouCantDoThatException(Exception):
    pass

class ThatsABadThingException(Exception):
    pass

def dobrokenstuff():
    d = {}
    e = {}
    key = 'missingkey'
    try:
        # val = d[key]
        # raise YouCantDoThatException
        raise KeyError('badkey')
    except KeyError, ke:
        d[key] = 'samplestring'
        logger2.exception('two exceptions')
    else:
        val = val.reverse()
        print val
        val = val.lower()
        finalval = e[val]
        logger2.debug('ELSE: HERE I AM')
    finally:
        logger2.debug('FINALLY: HERE I AM')

def dostuff():
    try:
        dobrokenstuff()
    except YouCantDoThatException, e:
        logger2.exception('Don\'t do that')

try:
    dostuff()
except:
    logger.exception("How did this happen?")

$ cat debug.log
2010-08-01 21:03:28,074 - DEBUG - something interesting just happened
2010-08-01 21:03:28,074 - ERROR - something horrible just happened

15.2. pprint

In conjunction with the logging module, the pprint (pretty print) module can be very helpful. It is easy to include a list or dictionary in a log statement, but it can be hard to read when debugging. In the pprint module, the pprint function prints to standard out while the pformat function returns a string that is more likely to be useful in logging or for other custom output requirements.

>>> import pprint
>>> deep = [{'letter': let, 'index': i, 'extended': let*i}
...         for i, let in enumerate(list('abcdefg'))]
>>> deep
[{'index': 0, 'extended': '', 'letter': 'a'}, {'index': 1, 'extended': 'b', 'letter': 'b'}, {'index': 2, 'extended': 'cc', 'letter': 'c'}, {'index': 3, 'extended': 'ddd', 'letter': 'd'}, {'index': 4, 'extended': 'eeee', 'letter': 'e'}, {'index': 5, 'extended': 'fffff', 'letter': 'f'}, {'index': 6, 'extended': 'gggggg', 'letter': 'g'}]

>>> pprint.pprint(deep)
[{'extended': '', 'index': 0, 'letter': 'a'},
 {'extended': 'b', 'index': 1, 'letter': 'b'},
 {'extended': 'cc', 'index': 2, 'letter': 'c'},
 {'extended': 'ddd', 'index': 3, 'letter': 'd'},
 {'extended': 'eeee', 'index': 4, 'letter': 'e'},
 {'extended': 'fffff', 'index': 5, 'letter': 'f'},
 {'extended': 'gggggg', 'index': 6, 'letter': 'g'}]

15.3. Lab

  1. Create a simple script with three loggers ‘app’, ‘app.sub’, ‘app.sub.sub’.
  2. Log a debug and critical message for each.
  3. Set ‘app’ to CRITICAL and ‘app.sub.sub’ to DEBUG. What messages do you get?
  4. Include a timestamp and the log level in your messages.
  5. raise an Exception and log it with .exception()

Copyright © 2020 ProTech. All Rights Reserved.

Sign In Create Account

Navigation

Social Media