Python Get Traceback (Stack trace) from Exception Object

At times you will want to catch an exception and extract the stack trace from the exception object to capture it somewhere (for instance log it).

In our codebase, we generally aim to handle all kinds of unexpected or incorrect input and output by putting validations and expecting certain kinds of exceptions (try/except). But there still remain cases where we want a “catch-all” behaviour of simply expecting any kind of Exception and capturing/logging the stack trace for future debugging.

So if you want to extract and capture the entire stack trace from an exception object in Python, then the right way is to use the traceback Python library that provides a standard interface to extract, format and print stack traces of Python programs (including those associated with an exception object – e.__traceback__).

In most cases, the traceback.format_exc() method should do the job. It returns a string containing:

  • A header that says Traceback (most recent call last):
  • Stack traceback
  • The exception type and value after the stack trace (eg: NameError: name 'some_var' is not defined)

The format is similar to the exception strings/output that the Python interpreter throws to stdout when it encounters an error in your program. Let’s see a simple example of how to get the traceback:

# tb.py
import traceback

def func1():
    raise ValueError("Some error occurred!")

def func2():
    return func1()

def func3():
    try:
        func2()
    except Exception as e:
        # Return the traceback/stack trace as a string
        return traceback.format_exc()

print(func3())

When you run the code above, you’ll see the returned traceback printed in your terminal:

$ python tb.py
Traceback (most recent call last):
  File "tb.py", line 12, in func3
    func2()
  File "tb.py", line 8, in func2
    return func1()
  File "tb.py", line 5, in func1
    raise ValueError("Some error occurred!")
ValueError: Some error occurred!

Feel free to go through the other methods in the docs. For instance, you can use traceback.print_exc() to write to a file instead of returning a string:

...

def func3():
    try:
        func2()
    except Exception as e:
        with open('print.txt', 'w+') as f:
            traceback.print_exc(file=f)

print(func3())

Or if you want to generate the traceback string by explicitly passing the exception object (for some reason), then something like this will help:

...

def func3():
    try:
        func2()
    except Exception as e:
        return ''.join(traceback.TracebackException.from_exception(e).format())

print(func3())

Also with a combination of traceback.format_list() and traceback.extract_stack(), one can extract the raw traceback of the “current stack frame” which can help capture even more information like who was the caller of func3() (the print statement):

current_stack_frame = traceback.format_list(traceback.extract_stack())
print(''.join(current_stack_frame))

Bonus: Instead of accessing the traceback, if you just want to log it in your except block, then read this article.

Leave a Reply

Your email address will not be published. Required fields are marked *