捕获并打印完整的 Python 异常回溯,无需停止/退出程序

发布于 2024-09-19 22:59:50 字数 283 浏览 28 评论 0原文

我想在不退出的情况下捕获并记录异常,例如,

try:
    do_stuff()
except Exception as err:
    print(Exception, err)
    # I want to print the entire traceback here,
    # not just the exception name and details

我想打印与引发异常时打印的完全相同的输出,而没有 try/ except 拦截异常,并且我不想要它退出我的程序。

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

try:
    do_stuff()
except Exception as err:
    print(Exception, err)
    # I want to print the entire traceback here,
    # not just the exception name and details

I want to print the exact same output that is printed when the exception is raised without the try/except intercepting the exception, and I do not want it to exit my program.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(20

分分钟 2024-09-26 22:59:50

traceback.format_exc() 将如果您想要的话,会产生更多信息。

import traceback

def do_stuff():
    raise Exception("test exception")

try:
    do_stuff()
except Exception:
    print(traceback.format_exc())

这输出:

Traceback (most recent call last):
  File "main.py", line 9, in <module>
    do_stuff()
  File "main.py", line 5, in do_stuff
    raise Exception("test exception")
Exception: test exception

traceback.format_exc() will yield more info if that's what you want.

import traceback

def do_stuff():
    raise Exception("test exception")

try:
    do_stuff()
except Exception:
    print(traceback.format_exc())

This outputs:

Traceback (most recent call last):
  File "main.py", line 9, in <module>
    do_stuff()
  File "main.py", line 5, in do_stuff
    raise Exception("test exception")
Exception: test exception
丢了幸福的猪 2024-09-26 22:59:50

其他一些答案已经指出了 traceback 模块。

请注意,使用print_exc,在某些极端情况下,您将无法获得您所期望的结果。在 Python 2.x 中:

import traceback

try:
    raise TypeError("Oups!")
except Exception, err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_exc()

...将显示最后异常的回溯:

Traceback (most recent call last):
  File "e.py", line 7, in <module>
    raise TypeError("Again !?!")
TypeError: Again !?!

如果您确实需要访问原始回溯一个解决方案是缓存从 exc_info异常信息 code>放在局部变量中,并使用 print_exception 显示它

import traceback
import sys

try:
    raise TypeError("Oups!")
except Exception, err:
    try:
        exc_info = sys.exc_info()

        # do you usefull stuff here
        # (potentially raising an exception)
        try:
            raise TypeError("Again !?!")
        except:
            pass
        # end of useful stuff


    finally:
        # Display the *original* exception
        traceback.print_exception(*exc_info)
        del exc_info

生产:

Traceback (most recent call last):
  File "t.py", line 6, in <module>
    raise TypeError("Oups!")
TypeError: Oups!

尽管如此,很少有陷阱:

  • 来自sys_info

    <块引用>

    将回溯返回值分配给正在处理异常的函数中的局部变量将导致循环引用。这将防止同一函数中的局部变量或回溯引用的任何内容被垃圾收集。 [...] 如果您确实需要回溯,请确保在使用后将其删除(最好使用 try ...finally 语句来完成)

  • 但是,来自同一个文档:

    <块引用>

    从 Python 2.2 开始,当启用垃圾收集并且它们变得无法访问时,此类循环会自动回收,但避免创建循环仍然更有效。


另一方面,通过允许您访问与异常相关的回溯,Python 3 会产生一个不太令人惊讶的结果:

import traceback

try:
    raise TypeError("Oups!")
except Exception as err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_tb(err.__traceback__)

...将显示:

  File "e3.py", line 4, in <module>
    raise TypeError("Oups!")

Some other answer have already pointed out the traceback module.

Please notice that with print_exc, in some corner cases, you will not obtain what you would expect. In Python 2.x:

import traceback

try:
    raise TypeError("Oups!")
except Exception, err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_exc()

...will display the traceback of the last exception:

Traceback (most recent call last):
  File "e.py", line 7, in <module>
    raise TypeError("Again !?!")
TypeError: Again !?!

If you really need to access the original traceback one solution is to cache the exception infos as returned from exc_info in a local variable and display it using print_exception:

import traceback
import sys

try:
    raise TypeError("Oups!")
except Exception, err:
    try:
        exc_info = sys.exc_info()

        # do you usefull stuff here
        # (potentially raising an exception)
        try:
            raise TypeError("Again !?!")
        except:
            pass
        # end of useful stuff


    finally:
        # Display the *original* exception
        traceback.print_exception(*exc_info)
        del exc_info

Producing:

Traceback (most recent call last):
  File "t.py", line 6, in <module>
    raise TypeError("Oups!")
TypeError: Oups!

Few pitfalls with this though:

  • From the doc of sys_info:

    Assigning the traceback return value to a local variable in a function that is handling an exception will cause a circular reference. This will prevent anything referenced by a local variable in the same function or by the traceback from being garbage collected. [...] If you do need the traceback, make sure to delete it after use (best done with a try ... finally statement)

  • but, from the same doc:

    Beginning with Python 2.2, such cycles are automatically reclaimed when garbage collection is enabled and they become unreachable, but it remains more efficient to avoid creating cycles.


On the other hand, by allowing you to access the traceback associated with an exception, Python 3 produce a less surprising result:

import traceback

try:
    raise TypeError("Oups!")
except Exception as err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_tb(err.__traceback__)

... will display:

  File "e3.py", line 4, in <module>
    raise TypeError("Oups!")
合约呢 2024-09-26 22:59:50

如果您正在调试并且只想查看当前的堆栈跟踪,您可以简单地调用:

traceback.print_stack()

无需手动引发异常来再次捕获它。

If you're debugging and just want to see the current stack trace, you can simply call:

traceback.print_stack()

There's no need to manually raise an exception just to catch it again.

寂寞美少年 2024-09-26 22:59:50

如何在不停止程序的情况下打印完整的回溯?

当您不想因错误而停止程序时,您需要使用 try/ except 来处理该错误:

try:
    do_something_that_might_error()
except Exception as error:
    handle_the_error(error)

要提取完整的回溯,我们将使用标准库中的 traceback 模块:

import traceback

并创建一个相当复杂的堆栈跟踪来证明我们获得了完整的堆栈跟踪:

def raise_error():
    raise RuntimeError('something bad happened!')

def do_something_that_might_error():
    raise_error()

打印完整的回溯,请使用traceback.print_exc方法:

try:
    do_something_that_might_error()
except Exception as error:
    traceback.print_exc()

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

打印 打印、日志记录:

但是,最佳实践是为您的模块设置一个记录器。它将知道模块的名称并能够更改级别(以及其他属性,例如处理程序)

import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

在这种情况下,您将需要 logger.exception 函数:

try:
    do_something_that_might_error()
except Exception as error:
    logger.exception(error)

哪些日志:

ERROR:__main__:something bad happened!
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

或者也许您只需要字符串,在这种情况下,您将需要 traceback.format_exc 函数:

try:
    do_something_that_might_error()
except Exception as error:
    logger.debug(traceback.format_exc())

哪个日志:

DEBUG:__main__:Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

结论

对于所有三个选项,我们看到我们得到的输出与我们有一个相同的输出错误:

>>> do_something_that_might_error()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

使用哪个

性能问题在这里并不重要,因为 IO 通常占主导地位。我更喜欢,因为它以向前兼容的方式精确地完成了所要求的操作:

logger.exception(error)

可以调整日志记录级别和输出,从而可以轻松关闭而无需接触代码。通常,做直接需要的事情是最有效的方法。

How to print the full traceback without halting the program?

When you don't want to halt your program on an error, you need to handle that error with a try/except:

try:
    do_something_that_might_error()
except Exception as error:
    handle_the_error(error)

To extract the full traceback, we'll use the traceback module from the standard library:

import traceback

And to create a decently complicated stacktrace to demonstrate that we get the full stacktrace:

def raise_error():
    raise RuntimeError('something bad happened!')

def do_something_that_might_error():
    raise_error()

Printing

To print the full traceback, use the traceback.print_exc method:

try:
    do_something_that_might_error()
except Exception as error:
    traceback.print_exc()

Which prints:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

Better than printing, logging:

However, a best practice is to have a logger set up for your module. It will know the name of the module and be able to change levels (among other attributes, such as handlers)

import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

In which case, you'll want the logger.exception function instead:

try:
    do_something_that_might_error()
except Exception as error:
    logger.exception(error)

Which logs:

ERROR:__main__:something bad happened!
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

Or perhaps you just want the string, in which case, you'll want the traceback.format_exc function instead:

try:
    do_something_that_might_error()
except Exception as error:
    logger.debug(traceback.format_exc())

Which logs:

DEBUG:__main__:Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

Conclusion

And for all three options, we see we get the same output as when we have an error:

>>> do_something_that_might_error()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

Which to use

Performance concerns aren't important here as IO usually dominates. I'd prefer, since it does precisely what's being requested in a forward compatible way:

logger.exception(error)

Logging levels and outputs can be adjusted, making it easy to turn off without touching the code. And usually doing what's directly needed is the most efficient way to do it.

终难愈 2024-09-26 22:59:50

traceback.format_exception(exception_object)

如果您只有异常对象,则可以从 Python 3 中代码的任意点以字符串形式获取回溯:

import traceback

''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))

自 Python 3.10 起,这可以进一步简化为: 谢谢

tb_str = ''.join(traceback.format_exception(exc_obj))

完整示例:

#!/usr/bin/env python3

import traceback

def f():
    g()

def g():
    raise Exception('asdf')

try:
    g()
except Exception as e:
    exc_obj = e

tb_str = ''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
print(tb_str)

或使用更简单的 Python 3.10 界面:

tb_str = ''.join(traceback.format_exception(exc_obj))

其中任何一个的输出:

Traceback (most recent call last):
  File "./main.py", line 12, in <module>
    g()
  File "./main.py", line 9, in g
    raise Exception('asdf')
Exception: asdf

文档: 谢谢 python.org/3.10/library/traceback.html#traceback.format_exception" rel="noreferrer">https://docs.python.org/3.10/library/traceback.html#traceback.format_exception

另请参阅: 从异常对象中提取回溯信息

已测试 Python 3.11.4、Ubuntu 23.04。

traceback.format_exception(exception_object)

If you only have the exception object, you can get the traceback as a string from any point of the code in Python 3 with:

import traceback

''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))

Since Python 3.10, this can be further simplified to: thanks

tb_str = ''.join(traceback.format_exception(exc_obj))

Full example:

#!/usr/bin/env python3

import traceback

def f():
    g()

def g():
    raise Exception('asdf')

try:
    g()
except Exception as e:
    exc_obj = e

tb_str = ''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
print(tb_str)

or with the simpler Python 3.10 interface:

tb_str = ''.join(traceback.format_exception(exc_obj))

Output for either of them:

Traceback (most recent call last):
  File "./main.py", line 12, in <module>
    g()
  File "./main.py", line 9, in g
    raise Exception('asdf')
Exception: asdf

Documentation: https://docs.python.org/3.10/library/traceback.html#traceback.format_exception

See also: Extract traceback info from an exception object

Tested Python 3.11.4, Ubuntu 23.04.

半枫 2024-09-26 22:59:50

首先,不要使用 print 进行日志记录,有一个稳定、经过验证且经过深思熟虑的 stdlib 模块可以做到这一点:日志记录。您绝对应该使用它。

其次,当有一种原生且简单的方法时,不要试图使用不相关的工具搞乱。就是这样:

log = logging.getLogger(__name__)

try:
    call_code_that_fails()
except MyError:
    log.exception('Any extra info you want to see in your logs')

就是这样。现在你已经完成了。

对任何对底层如何工作感兴趣的人的解释

log.exception 实际上所做的只是调用 log.error (即,日志事件级别错误然后打印回溯。

为什么更好?

嗯,这里有一些考虑因素:

  • 这是正确的;
  • 它很简单;
  • 这很简单。

为什么没有人应该使用 traceback 或使用 exc_info=True 调用记录器或使用 sys.exc_info 亲自动手?

嗯,只是因为!它们的存在都有不同的目的。例如,traceback.print_exc 的输出与解释器本身生成的回溯有点不同。如果你使用它,你会让任何阅读你日志的人感到困惑,他们会用头撞你的日志。

exc_info=True 传递给日志调用是不合适的。 但是,当捕获可恢复的错误并且您想要使用回溯记录它们(例如使用INFO级别)时,它很有用,因为log.exception 仅生成一级日志 - ERROR

而且你绝对应该尽可能避免弄乱 sys.exc_info 。它只是不是一个公共接口,而是一个内部接口 - 如果您明确知道自己在做什么,您可以使用它。它不仅仅用于打印异常。

First, do not use prints for logging, there is a stable, proven and well-thought out stdlib module to do that: logging. You definitely should use it instead.

Second, do not be tempted to do a mess with unrelated tools when there is a native and simple approach. Here it is:

log = logging.getLogger(__name__)

try:
    call_code_that_fails()
except MyError:
    log.exception('Any extra info you want to see in your logs')

That's it. You are done now.

Explanation for anyone who is interested in how things work under the hood

What log.exception is actually doing is just a call to log.error (that is, log event with level ERROR) and print traceback then.

Why is it better?

Well, here are some considerations:

  • it is just right;
  • it is straightforward;
  • it is simple.

Why should nobody use traceback or call logger with exc_info=True or get their hands dirty with sys.exc_info?

Well, just because! They all exist for different purposes. For example, traceback.print_exc's output is a little bit different from tracebacks produced by the interpreter itself. If you use it, you will confuse anyone who reads your logs, they will be banging their heads against them.

Passing exc_info=True to log calls is just inappropriate. But, it is useful when catching recoverable errors and you want to log them (using, e.g INFO level) with tracebacks as well, because log.exception produces logs of only one level - ERROR.

And you definitely should avoid messing with sys.exc_info as much as you can. It's just not a public interface, it's an internal one - you can use it if you definitely know what you are doing. It is not intended for just printing exceptions.

红衣飘飘貌似仙 2024-09-26 22:59:50

除了 Aaron Hall 的回答之外,如果您正在记录日志,但不想使用 logging.exception( )(因为它记录在 ERROR 级别),您可以使用较低的级别并传递 exc_info=True。例如

try:
    do_something_that_might_error()
except Exception:
    logging.info('General exception noted.', exc_info=True)

In addition to Aaron Hall's answer, if you are logging, but don't want to use logging.exception() (since it logs at the ERROR level), you can use a lower level and pass exc_info=True. e.g.

try:
    do_something_that_might_error()
except Exception:
    logging.info('General exception noted.', exc_info=True)
若相惜即相离 2024-09-26 22:59:50

我在任何其他答案中都没有看到这一点。如果您出于某种原因传递 Exception 对象...

在 Python 3.5+ 中,您可以使用 traceback.TracebackException.from_exception()。例如:

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()))

但是,上面的代码会导致:

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')

这只是堆栈的两层,而不是在 stack_lvl_2() 中引发异常且未被拦截时在屏幕上打印的内容 (取消注释 # raise 行)。

据我了解,这是因为异常在引发时仅记录堆栈的当前级别,在本例中为 stack_lvl_3() 。当它通过堆栈向上传递时,更多级别将添加到其 __traceback__ 中。但是我们在 stack_lvl_2() 中拦截了它,这意味着它要记录的只是级别 3 和 2。为了获得标准输出上打印的完整跟踪,我们必须在最高(最低? ) 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()))

导致:

Handled at stack lvl 0
  File "exc.py", line 17, in <module>
    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')

请注意,堆栈打印不同,第一行和最后一行丢失。因为它是一个不同的format()< /a>.

在尽可能远离引发异常的地方拦截异常可以使代码更简单,同时也提供更多信息。

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 <module>
    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.

铁轨上的流浪者 2024-09-26 22:59:50

在 python3(适用于 3.9)中,我们可以定义一个函数,并可以在我们想要打印详细信息的地方使用它。

import traceback

def get_traceback(e):
    lines = traceback.format_exception(type(e), e, e.__traceback__)
    return ''.join(lines)

try:
    1/0
except Exception as e:
    print('------Start--------')
    print(get_traceback(e))
    print('------End--------')

try:
    spam(1,2)
except Exception as e:
    print('------Start--------')
    print(get_traceback(e))
    print('------End--------')

输出如下:

bash-3.2$ python3 /Users/soumyabratakole/PycharmProjects/pythonProject/main.py
------Start--------
Traceback (most recent call last):
  File "/Users/soumyabratakole/PycharmProjects/pythonProject/main.py", line 26, in <module>
    1/0
ZeroDivisionError: division by zero

------End--------
------Start--------
Traceback (most recent call last):
  File "/Users/soumyabratakole/PycharmProjects/pythonProject/main.py", line 33, in <module>
    spam(1,2)
NameError: name 'spam' is not defined

------End--------

In python3 (works in 3.9) we can define a function and can use that where ever we want to print the details.

import traceback

def get_traceback(e):
    lines = traceback.format_exception(type(e), e, e.__traceback__)
    return ''.join(lines)

try:
    1/0
except Exception as e:
    print('------Start--------')
    print(get_traceback(e))
    print('------End--------')

try:
    spam(1,2)
except Exception as e:
    print('------Start--------')
    print(get_traceback(e))
    print('------End--------')

The output would be like:

bash-3.2$ python3 /Users/soumyabratakole/PycharmProjects/pythonProject/main.py
------Start--------
Traceback (most recent call last):
  File "/Users/soumyabratakole/PycharmProjects/pythonProject/main.py", line 26, in <module>
    1/0
ZeroDivisionError: division by zero

------End--------
------Start--------
Traceback (most recent call last):
  File "/Users/soumyabratakole/PycharmProjects/pythonProject/main.py", line 33, in <module>
    spam(1,2)
NameError: name 'spam' is not defined

------End--------
送君千里 2024-09-26 22:59:50

如果您已经有一个 Error 对象,并且想要打印整个内容,则需要进行这个有点尴尬的调用:

import traceback
traceback.print_exception(type(err), err, err.__traceback__)

没错,print_exception 需要三个位置参数:异常的类型、实际的异常对象以及异常自己的内部回溯属性。

在 python 3.5 或更高版本中,type(err) 是可选的...但它是一个位置参数,因此您仍然必须显式传递 None 来代替它。

traceback.print_exception(None, err, err.__traceback__)

我不知道为什么所有这些不仅仅是 traceback.print_exception(err)。为什么你想要打印出一个错误,以及除了属于该错误的回溯之外的回溯,这超出了我的范围。

If you have an Error object already, and you want to print the whole thing, you need to make this slightly awkward call:

import traceback
traceback.print_exception(type(err), err, err.__traceback__)

That's right, print_exception takes three positional arguments: The type of the exception, the actual exception object, and the exception's own internal traceback property.

In python 3.5 or later, the type(err) is optional... but it's a positional argument, so you still have to explicitly pass None in its place.

traceback.print_exception(None, err, err.__traceback__)

I have no idea why all of this isn't just traceback.print_exception(err). Why you would ever want to print out an error, along with a traceback other than the one that belongs to that error, is beyond me.

我不是你的备胎 2024-09-26 22:59:50

要获得精确堆栈跟踪(作为字符串),如果没有 try/except 来跳过它,就会引发该堆栈跟踪,只需将其放在 except 块中捕获有问题的异常。

desired_trace = traceback.format_exc(sys.exc_info())

以下是如何使用它(假设定义了flaky_func,并且log调用您最喜欢的日志系统):

import traceback
import sys

try:
    flaky_func()
except KeyboardInterrupt:
    raise
except Exception:
    desired_trace = traceback.format_exc(sys.exc_info())
    log(desired_trace)

捕获并重新引发KeyboardInterrupt是个好主意code>s,这样您仍然可以使用 Ctrl-C 终止程序。日志记录超出了问题的范围,但一个不错的选择是日志记录systraceback 模块。

To get the precise stack trace, as a string, that would have been raised if no try/except were there to step over it, simply place this in the except block that catches the offending exception.

desired_trace = traceback.format_exc(sys.exc_info())

Here's how to use it (assuming flaky_func is defined, and log calls your favorite logging system):

import traceback
import sys

try:
    flaky_func()
except KeyboardInterrupt:
    raise
except Exception:
    desired_trace = traceback.format_exc(sys.exc_info())
    log(desired_trace)

It's a good idea to catch and re-raise KeyboardInterrupts, so that you can still kill the program using Ctrl-C. Logging is outside the scope of the question, but a good option is logging. Documentation for the sys and traceback modules.

尸血腥色 2024-09-26 22:59:50
import io
import traceback

try:
    call_code_that_fails()
except:

    errors = io.StringIO()
    traceback.print_exc(file=errors)  # Instead of printing directly to stdout, the result can be further processed
    contents = str(errors.getvalue())
    print(contents)
    errors.close()
import io
import traceback

try:
    call_code_that_fails()
except:

    errors = io.StringIO()
    traceback.print_exc(file=errors)  # Instead of printing directly to stdout, the result can be further processed
    contents = str(errors.getvalue())
    print(contents)
    errors.close()
沧笙踏歌 2024-09-26 22:59:50

您需要将 try/ except 放在可能发生错误的最内层循环中,即

for i in something:
    for j in somethingelse:
        for k in whatever:
            try:
                something_complex(i, j, k)
            except Exception, e:
                print e
        try:
            something_less_complex(i, j)
        except Exception, e:
            print e

...等等换句话说

,您需要将 try/ except 中可能失败的语句尽可能具体地包装在尽可能最内循环。

You will need to put the try/except inside the most innerloop where the error may occur, i.e.

for i in something:
    for j in somethingelse:
        for k in whatever:
            try:
                something_complex(i, j, k)
            except Exception, e:
                print e
        try:
            something_less_complex(i, j)
        except Exception, e:
            print e

... and so on

In other words, you will need to wrap statements that may fail in try/except as specific as possible, in the most inner-loop as possible.

七月上 2024-09-26 22:59:50

关于此答案的评论:print(traceback.format_exc())做得更好对我来说,比 traceback.print_exc() 更重要。对于后者,hello 有时会奇怪地与回溯文本“混合”,就像两者都想同时写入 stdout 或 stderr 一样,产生奇怪的输出(至少在从内部构建时)文本编辑器并在“构建结果”面板中查看输出)。

回溯(最近一次调用最后一次):
文件“C:\Users\User\Desktop\test.py”,第 7 行,位于
地狱 do_stuff()
文件“C:\Users\User\Desktop\test.py”,第 4 行,在 do_stuff
1/0
ZeroDivisionError:整数除或以零取模
o
【0.1秒完成】

所以我使用:

import traceback, sys

def do_stuff():
    1/0

try:
    do_stuff()
except Exception:
    print(traceback.format_exc())
    print('hello')

A remark about this answer's comments: print(traceback.format_exc()) does a better job for me than traceback.print_exc(). With the latter, the hello is sometimes strangely "mixed" with the traceback text, like if both want to write to stdout or stderr at the same time, producing weird output (at least when building from inside a text editor and viewing the output in the "Build results" panel).

Traceback (most recent call last):
File "C:\Users\User\Desktop\test.py", line 7, in
hell do_stuff()
File "C:\Users\User\Desktop\test.py", line 4, in do_stuff
1/0
ZeroDivisionError: integer division or modulo by zero
o
[Finished in 0.1s]

So I use:

import traceback, sys

def do_stuff():
    1/0

try:
    do_stuff()
except Exception:
    print(traceback.format_exc())
    print('hello')
雨巷深深 2024-09-26 22:59:50

此答案中的这种用法是自 Python 3.10 以来的新用法,并且尚未被任何先前的答案涵盖。要打印回溯,可以将异常赋予 Traceback.print_Exception

示例:

import traceback

try:
    object.bad_attr
except Exception as exc:
    traceback.print_exception(exc)

输出回溯:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
AttributeError: type object 'object' has no attribute 'bad_attr'

提醒一下,此答案需要 Python 3.10 或更高版本才能起作用。

要将引用捕获为字符串,请参阅此答案

This usage in this answer is new since Python 3.10, and has not been covered by any prior answer. To print a traceback, it is possible to give the exception to traceback.print_exception.

Example:

import traceback

try:
    object.bad_attr
except Exception as exc:
    traceback.print_exception(exc)

Output traceback:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
AttributeError: type object 'object' has no attribute 'bad_attr'

As a reminder, Python 3.10 or newer is required for this answer to work.

To capture the trackeback as a string, see this answer.

旧竹 2024-09-26 22:59:50

您需要 traceback 模块。它可以让你像 Python 通常那样打印堆栈转储。特别是, print_last 函数将打印最后一个异常和堆栈痕迹。

You want the traceback module. It will let you print stack dumps like Python normally does. In particular, the print_last function will print the last exception and a stack trace.

叹沉浮 2024-09-26 22:59:50

python 3解决方案

stacktrace_helper.py

from linecache import getline
import sys
import traceback


def get_stack_trace():
    exc_type, exc_value, exc_tb = sys.exc_info()
    trace = traceback.format_stack()
    trace = list(filter(lambda x: ("\\lib\\" not in x and "/lib/" not in x and "stacktrace_helper.py" not in x), trace))
    ex_type = exc_type.__name__
    ex_line = exc_tb.tb_lineno
    ex_file = exc_tb.tb_frame.f_code.co_filename
    ex_message = str(exc_value)
    line_code = ""
    try:
        line_code = getline(ex_file, ex_line).strip()
    except:
        pass

    trace.insert(
        0, f'File "{ex_file}", line {ex_line}, line_code: {line_code} , ex: {ex_type} {ex_message}',
    )
    return trace


def get_stack_trace_str(msg: str = ""):
    trace = list(get_stack_trace())
    trace_str = "\n".join(list(map(str, trace)))
    trace_str = msg + "\n" + trace_str
    return trace_str

python 3 solution

stacktrace_helper.py:

from linecache import getline
import sys
import traceback


def get_stack_trace():
    exc_type, exc_value, exc_tb = sys.exc_info()
    trace = traceback.format_stack()
    trace = list(filter(lambda x: ("\\lib\\" not in x and "/lib/" not in x and "stacktrace_helper.py" not in x), trace))
    ex_type = exc_type.__name__
    ex_line = exc_tb.tb_lineno
    ex_file = exc_tb.tb_frame.f_code.co_filename
    ex_message = str(exc_value)
    line_code = ""
    try:
        line_code = getline(ex_file, ex_line).strip()
    except:
        pass

    trace.insert(
        0, f'File "{ex_file}", line {ex_line}, line_code: {line_code} , ex: {ex_type} {ex_message}',
    )
    return trace


def get_stack_trace_str(msg: str = ""):
    trace = list(get_stack_trace())
    trace_str = "\n".join(list(map(str, trace)))
    trace_str = msg + "\n" + trace_str
    return trace_str
完美的未来在梦里 2024-09-26 22:59:50

这是我将错误写入日志文件和控制台的解决方案:

import logging, sys
import traceback
logging.basicConfig(filename='error.log', level=logging.DEBUG)

def handle_exception(exc_type, exc_value, exc_traceback):
    if issubclass(exc_type, KeyboardInterrupt):
        sys.__excepthook__(exc_type, exc_value, exc_traceback)
        return
    exc_info=(exc_type, exc_value, exc_traceback)
    logging.critical("\nDate:" + str(datetime.datetime.now()), exc_info=(exc_type, exc_value, exc_traceback))
    print("An error occured, check error.log to see the error details")
    traceback.print_exception(*exc_info)


sys.excepthook = handle_exception

This is my solution to write the error in a log file and also on console:

import logging, sys
import traceback
logging.basicConfig(filename='error.log', level=logging.DEBUG)

def handle_exception(exc_type, exc_value, exc_traceback):
    if issubclass(exc_type, KeyboardInterrupt):
        sys.__excepthook__(exc_type, exc_value, exc_traceback)
        return
    exc_info=(exc_type, exc_value, exc_traceback)
    logging.critical("\nDate:" + str(datetime.datetime.now()), exc_info=(exc_type, exc_value, exc_traceback))
    print("An error occured, check error.log to see the error details")
    traceback.print_exception(*exc_info)


sys.excepthook = handle_exception
桃酥萝莉 2024-09-26 22:59:50

我们可以在不使用 traceback 模块的情况下仅使用 .error().exception() 日志记录方法来记录异常回溯。

import logging

try:
    print(0/0)
except Exception as e:
    logging.error(e, exc_info=True)

或者

import logging

try:
    print(0/0)
except Exception as e:
    logging.exception(e)

We can log exception traceback without using traceback module using only .error() or .exception() method of logging.

import logging

try:
    print(0/0)
except Exception as e:
    logging.error(e, exc_info=True)

or

import logging

try:
    print(0/0)
except Exception as e:
    logging.exception(e)
夜血缘 2024-09-26 22:59:50

你可以这样做:

try:
    do_stuff()
except Exception, err:
    print(Exception, err)
    raise err

You could do:

try:
    do_stuff()
except Exception, err:
    print(Exception, err)
    raise err
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文