How to get a complete exception stack trace in Python

27,938

Solution 1

I don't know if there is a better way, but here's what I did:

import traceback
import sys

def format_exception(e):
    exception_list = traceback.format_stack()
    exception_list = exception_list[:-2]
    exception_list.extend(traceback.format_tb(sys.exc_info()[2]))
    exception_list.extend(traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1]))

    exception_str = "Traceback (most recent call last):\n"
    exception_str += "".join(exception_list)
    # Removing the last \n
    exception_str = exception_str[:-1]

    return exception_str

def main1():
    main2()

def main2():
    try:
        main3()
    except Exception as e:
        print "Printing only the traceback above the current stack frame"
        print "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
        print
        print "Printing the full traceback as if we had not caught it here..."
        print format_exception(e)

def main3():
    raise Exception()

if __name__ == '__main__':
    main1()

And here's the output I get:

Printing only the traceback above the current stack frame
Traceback (most recent call last):
  File "exc.py", line 22, in main2
    main3()
  File "exc.py", line 31, in main3
    raise Exception()
Exception


Printing the full traceback as if we had not caught it here...
Traceback (most recent call last):
  File "exc.py", line 34, in <module>
    main1()
  File "exc.py", line 18, in main1
    main2()
  File "exc.py", line 22, in main2
    main3()
  File "exc.py", line 31, in main3
    raise Exception()
Exception

Solution 2

Here's a function based on this answer. It will also work when no exception is present:

def full_stack():
    import traceback, sys
    exc = sys.exc_info()[0]
    stack = traceback.extract_stack()[:-1]  # last one would be full_stack()
    if exc is not None:  # i.e. an exception is present
        del stack[-1]       # remove call of full_stack, the printed exception
                            # will contain the caught exception caller instead
    trc = 'Traceback (most recent call last):\n'
    stackstr = trc + ''.join(traceback.format_list(stack))
    if exc is not None:
         stackstr += '  ' + traceback.format_exc().lstrip(trc)
    return stackstr

print full_stack() will print the full stack trace up to the top, including e.g. IPython's interactiveshell.py calls, since there is (to my knowledge) no way of knowing who would catch exceptions. It's probably not worth figuring out anyway...

If print full_stack() is called from within an except block, full_stack will include the stack trace down to the raise. In the standard Python interpreter, this will be identical to the message you receive when not catching the exception (Which is why that del stack[-1] is there, you don't care about the except block but about the try block).

Solution 3

Use

 traceback.print_stack()

http://docs.python.org/library/traceback.html#traceback.print_stack

suxmac2 $ python out.py 
  File "out.py", line 16, in <module>
    a()
  File "out.py", line 5, in a
    b()
  File "out.py", line 11, in b
    traceback.print_stack()

Solution 4


Here is a bit better variant of Tobias Kienzler answer. It works same, but can be called not right in except block, but somewhere deeper. In other words, this variant will print same stacks, when called like

try:
   ...
except Exception:
    print full_stack()

or

def print_full_stack():
    print full_stack()

try:
   ...
except Exception:
    print_full_stack()

Here is code:

def full_stack():
    import traceback, sys
    exc = sys.exc_info()[0]
    if exc is not None:
        f = sys.exc_info()[-1].tb_frame.f_back
        stack = traceback.extract_stack(f)
    else:
        stack = traceback.extract_stack()[:-1]  # last one would be full_stack()
    trc = 'Traceback (most recent call last):\n'
    stackstr = trc + ''.join(traceback.format_list(stack))
    if exc is not None:
        stackstr += '  ' + traceback.format_exc().lstrip(trc)
    return stackstr
Share:
27,938
princ_sameer
Author by

princ_sameer

I'm currently a Senior Python Contractor. After getting a B.Sc in computer science I kind of stumbled into embedded C programming, to my great surprise I enjoyed it. And fortunately I also seemed to be reasonably good at it. This in turn led me to Python which I must confess is much more enjoyable than embedded C :)

Updated on March 31, 2021

Comments

  • princ_sameer
    princ_sameer about 3 years

    The following snippet:

    import traceback
    
    def a():
        b()
    
    def b():
        try:
            c()
        except:
            traceback.print_exc()
    
    def c():
        assert False
    
    a()
    

    Produces this output:

    Traceback (most recent call last):
      File "test.py", line 8, in b
        c()
      File "test.py", line 13, in c
        assert False
    AssertionError
    

    What should I use if I want the complete stack trace including the call to a?

    If it matters I have Python 2.6.6

    edit: What I'd like to get is the same information I'd get if I left the try except out and let the exception propagate to the top level. This snippet for example:

    def a():
        b()
    
    def b():
        c()
    
    def c():
        assert False
    
    a()
    

    Produces this output:

    Traceback (most recent call last):
      File "test.py", line 10, in <module>
        a()
      File "test.py", line 2, in a
        b()
      File "test.py", line 5, in b
        c()
      File "test.py", line 8, in c
        assert False
    AssertionError