How to catch and print the full exception traceback without halting/exiting the program?

后端 未结 15 2246
天命终不由人
天命终不由人 2020-11-22 13:46

I want to catch and log exceptions without exiting, e.g.,

try:
    do_stuff()
except Exception, err:
    print(Exception, err)
    # I want to print the entir         


        
15条回答
  •  余生分开走
    2020-11-22 14:24

    I don't see this mentioned in any of the other answers. If you're passing around an Exception object for whatever reason...

    In Python 3.5+ you can get a trace from an Exception object using traceback.TracebackException.from_exception(). For example:

    import traceback
    
    
    def stack_lvl_3():
        raise Exception('a1', 'b2', 'c3')
    
    
    def stack_lvl_2():
        try:
            stack_lvl_3()
        except Exception as e:
            # raise
            return e
    
    
    def stack_lvl_1():
        e = stack_lvl_2()
        return e
    
    e = stack_lvl_1()
    
    tb1 = traceback.TracebackException.from_exception(e)
    print(''.join(tb1.format()))
    

    However, the above code results in:

    Traceback (most recent call last):
      File "exc.py", line 10, in stack_lvl_2
        stack_lvl_3()
      File "exc.py", line 5, in stack_lvl_3
        raise Exception('a1', 'b2', 'c3')
    Exception: ('a1', 'b2', 'c3')
    

    This is just two levels of the stack, as opposed to what would have been printed on screen had the exception been raised in stack_lvl_2() and not intercepted (uncomment the # raise line).

    As I understand it, that's because an exception records only the current level of the stack when it is raised, stack_lvl_3() in this case. As it's passed back up through the stack, more levels are being added to its __traceback__. But we intercepted it in stack_lvl_2(), meaning all it got to record was levels 3 and 2. To get the full trace as printed on stdout we'd have to catch it at the highest (lowest?) level:

    import traceback
    
    
    def stack_lvl_3():
        raise Exception('a1', 'b2', 'c3')
    
    
    def stack_lvl_2():
        stack_lvl_3()
    
    
    def stack_lvl_1():
        stack_lvl_2()
    
    
    try:
        stack_lvl_1()
    except Exception as exc:
        tb = traceback.TracebackException.from_exception(exc)
    
    print('Handled at stack lvl 0')
    print(''.join(tb.stack.format()))
    

    Which results in:

    Handled at stack lvl 0
      File "exc.py", line 17, in 
        stack_lvl_1()
      File "exc.py", line 13, in stack_lvl_1
        stack_lvl_2()
      File "exc.py", line 9, in stack_lvl_2
        stack_lvl_3()
      File "exc.py", line 5, in stack_lvl_3
        raise Exception('a1', 'b2', 'c3')
    

    Notice that the stack print is different, the first and last lines are missing. Because it's a different format().

    Intercepting the exception as far away from the point where it was raised as possible makes for simpler code while also giving more information.

提交回复
热议问题