When exceptions happens, you may find it useful to log the exception and its stack trace for further investigation. In this article, you will learn how to retrieve the current exception and its properties – its type and its stack trace.

Log exception in python

exc_info and traceback module

The exc_info is viable tool to find information about currently handled exception. In other words, when called inside the except block of try except construct, this function will provide details about the exception being caught. The following data will be returned as a tuple with 3 values:

  • The value at position 1 is the type of the exception being caught
  • The value at position 2 is the exception being caught
  • The value at position 3 is a traceback object which contains data about call stack (stack trace) at the point when the exception occurred.

Consider the following snippet and its output:

exc_info sample #1 - the currently handled exception
import sys
try:
    xx = '1' + 5
except Exception,ee:
    ( exception_type, exception , traceback ) = sys.exc_info()
    print 'The exception being handle (from except block ) ==> id : {0} , type: {1}'.format( id(ee) , type(ee)       )
    print 'The exception being handle (from sys.exc_info ) ==> id : {0} , type: {1}'.format( id(ee) , exception_type )
exc_info sample #1 output
The excecption being handle (from except block ) ==> id : 37028088 , type: <type 'exceptions.TypeError'>
The excecption being handle (from sys.exc_info ) ==> id : 37028088 , type: <type 'exceptions.TypeError'>

As we can see, the sys.exc_info() return the currently handled exception and its type (ee in the snippet). In the snippet, the function may seem not very useful since we already know which exception is handled from the except block. The full potential of this function derives from its ability to return the current exception even if it is called inside a function which is being called inside the except block:

exc_info sample #2 - the currently handled exception
import sys
def formatException():
    ( exception_type, exception , traceback ) = sys.exc_info()
    return 'The excecption being handle (from sys.exc_info ) ==> id : {0} , type: {1}'.format( id(ee) , exception_type )
try:
    xx = '1' + 5
except Exception,ee:
    print 'The excecption being handle (from except block ) ==> id : {0} , type: {1}'.format( id(ee) , type(ee)       )
    print formatException()
exc_info sample #2 output
The excecption being handle (from except block ) ==> id : 37224736 , type: <type 'exceptions.TypeError'>
The excecption being handle (from sys.exc_info ) ==> id : 37224736 , type: <type 'exceptions.TypeError'>

we can also use the value at position 3 of the tuple returned from sys.exc_info(). This value is a traceback object which contains the call stack state when the exception occurred. The traceback module contains functions which allow us to extract, format and print stack traces.

We will use the extract_tb from traceback module which return a list of tuples. Each tuple in the list represent a function in the call stack. The tuple:

  • The value at position 3 is the function name
  • The value at position 1 is the file where this function is defined
  • The value at position 2 is the line in this file where the next function in the call stack was invoked. Please note, In the last function, this will be the number of the line where the excecption was raised.
  • The value at position 4 is contents of this line

The logExecption

Let’s define the logExecption in log module. For simplicity, we will print the exception to screen – You can change it to your needs.

logException
import sys
import traceback
def logException():
    ( exception_type, exception , tb ) = sys.exc_info()
    ss = '{0} => {1}\n'.format( exception_type , exception )
    ii = 0
    for (fn, linenum , func , line ) in traceback.extract_tb(tb):
        ss += '   {4} | {2:<20} | {0:<20} | {1:>3} | {3:<20}\n'.format(fn,linenum,func,line,ii);
        ii += 1
    print ss

The following demo demonstrate the format of the exception in the log

logException sample
import log
def f1():
    try:
        f2()
    except Exception,ee:
        log.logException()
def f2():
    f3()
def f3():
    xx = '1' + 5
f1()
logException sample output
<type 'exceptions.TypeError'> => cannot concatenate 'str' and 'int' objects
    0 | f1                   | 03.py                |   5 | f2()
    1 | f2                   | 03.py                |  10 | f3()
    2 | f3                   | 03.py                |  13 | xx = '1' + 5

Summery

The logException will allow you to log excecption to a log file and continue with exectution of the program. Later, With this information at hand, you can easily find the reason why the exception was raised.