When exception happen, you may find it helpful to log exception and the stack trace for further investigation. This article shows how to retrieve the currently handled exception, its type, and the stack trace when it is raised.
Find The Exception Details With traceback Module
The exc_info of the traceback
module is a viable tool to find information about the currently handled exception. When called inside the except block of try-except construct, this function will provide details about the exception being Handled.
The function return the all the related data as tuple with three values:
- The value at position 1 is the type of exception being caught
- The value at position 2 is the exception being caught
- The value at position 3 is a
traceback
object containing data about call stack (stack trace) when the exception occurred.
2 Ways To Find The Currently Handled Exception
We usually use the exception object’s provided by except block of the try-except construct to find the currently handled exception. However, we can also find the currently handled exception with the help of exc_info
of the traceback
module.
In the following code snippet, when an exception is raised, we print the object id of the exception object and its type twice. In the first print statement, we display the exception object’s information from the except block of the try-except construct. In the first print statement, we display the exception object’s information we get from the exc_info
function.
Sample 1 – The currently handled exception details with exc_info
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 )
Sample 1 output – The currently handled exception details with exc_info
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, both print statements display the same information; That is, the sys.exc_info()
return the same exception object’s from the except block of the try-except construct (The ee
object in the above snippet).
The Real Value of exc_info Function
We see 2 ways to find the currently handled exception. You may ask why to use exc_info()
when the exception’s object of the currently handled exception is always provided by the except block of the try-except construct. Yes, The function may seem not very useful in the above snippet. First, You already know which type of exception you handle when you are inside except block. Second, you can use the exception’s object provided by the except block.
The full potential of the exc_info
function derives from its ability to return the current exception in all scenarios. For example, To get the currently handled exception, you do not need to call this function directly inside the except block of the try-except construct. You will also get the currently handled exception, even if you call this function inside a being function called inside the except block.
Let’s see it in the following code snippet:
Sample 2 – the currently handled exception with exc_info
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()
Sample 2 Output – the currently handled exception with exc_info
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'>
As we can see, Even though we do not directly call the exc_info inside the except block (we call it indirectly via the formatException function), we get the exception’s object of the currently handled exception.
How to Log Exceptions?
We see a new method to Find the currently handled exception and how we can use it to log the raised exception. You can use this method to log the exception to file and continue with the program’s execution. If you log the type of the exception, the exception’s message, the stack trace that shows you where the exception was raised, and other related data, you can easily find why the exception was raised and fix the problem.
With the above information at hand, it is easy to write a log exception when an exception is raised. Let’s write logException
in the log
module. For simplicity, We will print the exception to the screen – You can change it to your needs.
We log the type of the expection, its message and after that display the stack trace of the exception. To display the stacktrace, we extract_tb
of the traceback
module. We will provide to extract_tb
function the traceback at position 3 of the tuple returned from sys.exc_info()
. For each frame in the stack trace, we display function function name, the file and the line the function located, and the related expression.
Log logException
in log
module
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 demonstrates the format of the log:
Sample 3 – The logException Format Demo
import log
def f1():
try:
f2()
except Exception,ee:
log.logException()
def f2():
f3()
def f3():
xx = '1' + 5
f1()
Sample 3 – The logException Format Demo 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