Get full traceback Get full traceback python python

Get full traceback


As mechmind answered, the stack trace consists only of frames between the site where the exception was raised and the site of the try block. If you need the full stack trace, apparently you're out of luck.

Except that it's obviously possible to extract the stack entries from top-level to the current frame—traceback.extract_stack manages it just fine. The problem is that the information obtained by traceback.extract_stack comes from direct inspection of stack frames without creating a traceback object at any point, and the logging API requires a traceback object to affect traceback output.

Fortunately, logging doesn't require an actual traceback object, it requires an object that it can pass to the formatting routines of the traceback module. traceback doesn't care either—it only uses two attributes of the traceback, the frame and the line number. So, it should be possible to create a linked list of duck-typed faux-traceback objects and pass it off as the traceback.

import sysclass FauxTb(object):    def __init__(self, tb_frame, tb_lineno, tb_next):        self.tb_frame = tb_frame        self.tb_lineno = tb_lineno        self.tb_next = tb_nextdef current_stack(skip=0):    try: 1/0    except ZeroDivisionError:        f = sys.exc_info()[2].tb_frame    for i in xrange(skip + 2):        f = f.f_back    lst = []    while f is not None:        lst.append((f, f.f_lineno))        f = f.f_back    return lstdef extend_traceback(tb, stack):    """Extend traceback with stack info."""    head = tb    for tb_frame, tb_lineno in stack:        head = FauxTb(tb_frame, tb_lineno, head)    return headdef full_exc_info():    """Like sys.exc_info, but includes the full traceback."""    t, v, tb = sys.exc_info()    full_tb = extend_traceback(tb, current_stack(1))    return t, v, full_tb

With these functions in place, your code only requires a trivial modification:

import loggingdef func():    try:        raise Exception('Dummy')    except:        logging.error("Something awful happened!", exc_info=full_exc_info())def func2():    func()func2()

...to give the expected output:

ERROR:root:Something awful happened!Traceback (most recent call last):  File "a.py", line 52, in <module>    func2()  File "a.py", line 49, in func2    func()  File "a.py", line 43, in func    raise Exception('Dummy')Exception: Dummy

Note that the faux-traceback objects are fully usable for introspection—displaying local variables or as argument to pdb.post_mortem()—because they contain references to real stack frames.


Stack trace is collected when exception bubbles up. So you should print traceback on top of desired stack:

import tracebackdef func():    raise Exception('Dummy')def func2():    func()try:    func2()except:    traceback.print_exc()


This is based on user4815162342's answer, but a bit more minimalistic:

import sysimport collectionsFauxTb = collections.namedtuple("FauxTb", ["tb_frame", "tb_lineno", "tb_next"])def full_exc_info():    """Like sys.exc_info, but includes the full traceback."""    t, v, tb = sys.exc_info()    f = sys._getframe(2)    while f is not None:        tb = FauxTb(f, f.f_lineno, tb)        f = f.f_back    return t, v, tb

It avoids throwing the dummy exception, at the cost of requiring the usage of sys._getframe(). It assumes being used in the except clause where the exception was caught, as it goes up two stack frames (full_exc_info and the function that calls full_exc_info – that would be the function that calls the raising code, and as such is already included in the original traceback).

This gives the same output as the code in user4815162342's answer.

If you don't mind the slight differences in formatting, you can also use

import loggingdef func():    try:        raise Exception('Dummy')    except:        logging.exception("Something awful happened!", stack_info=True)def func2():    func()func2()

which results in

ERROR:root:Something awful happened!Traceback (most recent call last):  File "test.py", line 5, in func    raise Exception('Dummy')Exception: DummyStack (most recent call last):  File "test.py", line 12, in <module>    func2()  File "test.py", line 10, in func2    func()  File "test.py", line 7, in func    logging.exception("Something awful happened!", stack_info=True)

In this case, you'll get a trace from the try to the exception, and a second from the root call to the location of the logging call.