faulthandler --- 转储 Python 回溯

在 3.3 版本加入。


此模块包含的函数可以在发生故障、超时或收到用户信号时显式地转储 Python 回溯信息。调用 faulthandler.enable() 可为 SIGSEGVSIGFPESIGABRTSIGBUSSIGILL 信号安装故障处理程序。你也可以通过设置 PYTHONFAULTHANDLER 环境变量或使用 -X faulthandler 命令行选项在启动时启用它们。

故障处理程序与 Apport 或 Windows 故障处理程序等系统故障处理程序兼容。如果 sigaltstack() 函数可用,该模块会为信号处理程序使用备用堆栈。这使得它即使在堆栈溢出时也能转储回溯信息。

故障处理程序是在发生灾难性情况时调用的,因此只能使用信号安全 (signal-safe) 的函数(例如,它不能在堆上分配内存)。由于此限制,与正常的 Python 回溯信息相比,回溯信息的转储是最小化的。

  • 只支持 ASCII。编码时使用 backslashreplace 错误处理程序。

  • 每个字符串限制为 500 个字符。

  • 只显示文件名、函数名和行号。(没有源代码)

  • 它被限制在 100 个帧和 100 个线程内。

  • 顺序是颠倒的:最新的调用会最先显示。

默认情况下,Python 回溯信息会写入 sys.stderr。要看到回溯信息,应用程序必须在终端中运行。或者也可以将日志文件传递给 faulthandler.enable()

该模块是用 C 实现的,因此可以在崩溃或 Python 死锁时转储回溯信息。

Python 开发模式 会在 Python 启动时调用 faulthandler.enable()

参见

模块 pdb

适用于 Python 程序的交互式源代码调试器。

模块 traceback

提取、格式化和打印 Python 程序堆栈跟踪的标准接口。

转储回溯信息

faulthandler.dump_traceback(file=sys.stderr, all_threads=True)

将所有线程的回溯信息转储到 file 中。如果 all_threadsFalse,则只转储当前线程。

参见

traceback.print_tb() 可用于打印回溯对象。

在 3.5 版更改: 增加了向此函数传递文件描述符的支持。

转储 C 堆栈

在 3.14 版本加入。

faulthandler.dump_c_stack(file=sys.stderr)

将当前线程的 C 堆栈跟踪转储到 file 中。

如果 Python 构建不支持或操作系统不提供堆栈跟踪,那么这会打印一个错误信息,而不是转储 C 堆栈。

C 堆栈兼容性

如果系统不支持 C 级别的 backtrace(3)dladdr1(3),那么 C 堆栈转储将无法工作。将会打印错误信息而不是堆栈。

此外,某些编译器不支持 CPython 的 C 堆栈转储实现。因此,即使操作系统支持转储堆栈,也可能会打印一个不同的错误信息而不是堆栈。

备注

转储 C 堆栈的速度可能会非常慢,具体取决于调用堆栈中二进制文件的 DWARF 级别。

故障处理程序状态

faulthandler.enable(file=sys.stderr, all_threads=True, c_stack=True)

启用故障处理程序:为 SIGSEGVSIGFPESIGABRTSIGBUSSIGILL 信号安装处理程序以转储 Python 回溯信息。如果 all_threadsTrue,则为每个正在运行的线程生成回溯信息。否则,只转储当前线程。

file 必须保持打开状态,直到故障处理程序被禁用:请参阅文件描述符问题

如果 c_stackTrue,那么 C 堆栈跟踪将在 Python 回溯之后打印,除非系统不支持。有关兼容性的更多信息,请参阅 dump_c_stack()

在 3.5 版更改: 增加了向此函数传递文件描述符的支持。

在 3.6 版更改: 在 Windows 上,还会安装一个 Windows 异常处理程序。

在 3.10 版更改: 如果 all_threads 为真,转储现在会提及垃圾回收器回收是否正在运行。

在 3.14 版更改: 如果禁用了 GIL,为避免数据竞争的风险,只会转储当前线程。

在 3.14 版更改: 如果 c_stack 为真,转储现在会显示 C 堆栈跟踪。

faulthandler.disable()

禁用故障处理程序:卸载由 enable() 安装的信号处理程序。

faulthandler.is_enabled()

检查故障处理程序是否已启用。

超时后转储回溯信息

faulthandler.dump_traceback_later(timeout, repeat=False, file=sys.stderr, exit=False)

timeout 秒的超时后,转储所有线程的回溯信息;如果 repeatTrue,则每隔 timeout 秒转储一次。如果 exitTrue,则在转储回溯信息后以状态码 1 调用 _exit()。(注意 _exit() 会立即退出进程,这意味着它不会执行任何清理工作,如刷新文件缓冲区。)如果该函数被调用两次,新的调用将替换之前的参数并重置超时。计时器的分辨率为亚秒级。

file 必须保持打开状态,直到回溯信息被转储或调用 cancel_dump_traceback_later():请参阅文件描述符问题

此函数通过一个看门狗线程实现。

在 3.5 版更改: 增加了向此函数传递文件描述符的支持。

在 3.7 版更改: 此函数现在总是可用的。

faulthandler.cancel_dump_traceback_later()

取消对 dump_traceback_later() 的最后一次调用。

在用户信号上转储回溯信息

faulthandler.register(signum, file=sys.stderr, all_threads=True, chain=False)

注册一个用户信号:为 signum 信号安装一个处理程序,将所有线程的回溯信息(如果 all_threadsFalse,则为当前线程)转储到 file 中。如果 chain 为 True,则调用前一个处理程序。

file 必须保持打开状态,直到通过 unregister() 取消注册该信号:请参阅文件描述符问题

在 Windows 上不可用。

在 3.5 版更改: 增加了向此函数传递文件描述符的支持。

faulthandler.unregister(signum)

取消注册用户信号:卸载由 register() 安装的 signum 信号的处理程序。如果信号已注册,则返回 True,否则返回 False

在 Windows 上不可用。

文件描述符问题

enable()dump_traceback_later()register() 会保留其 file 参数的文件描述符。如果文件被关闭,其文件描述符被新文件重用,或者使用 os.dup2() 替换了文件描述符,回溯信息将被写入不同的文件。每次替换文件时,都应重新调用这些函数。

示例

在 Linux 上启用和未启用故障处理程序的段错误示例

$ python -c "import ctypes; ctypes.string_at(0)"
Segmentation fault

$ python -q -X faulthandler
>>> import ctypes
>>> ctypes.string_at(0)
Fatal Python error: Segmentation fault

Current thread 0x00007fb899f39700 (most recent call first):
  File "/opt/python/Lib/ctypes/__init__.py", line 486 in string_at
  File "<stdin>", line 1 in <module>

Current thread's C stack trace (most recent call first):
  Binary file "/opt/python/python", at _Py_DumpStack+0x42 [0x5b27f7d7147e]
  Binary file "/opt/python/python", at +0x32dcbd [0x5b27f7d85cbd]
  Binary file "/opt/python/python", at +0x32df8a [0x5b27f7d85f8a]
  Binary file "/usr/lib/libc.so.6", at +0x3def0 [0x77b73226bef0]
  Binary file "/usr/lib/libc.so.6", at +0x17ef9c [0x77b7323acf9c]
  Binary file "/opt/python/build/lib.linux-x86_64-3.14/_ctypes.cpython-314d-x86_64-linux-gnu.so", at +0xcdf6 [0x77b7315dddf6]
  Binary file "/usr/lib/libffi.so.8", at +0x7976 [0x77b73158f976]
  Binary file "/usr/lib/libffi.so.8", at +0x413c [0x77b73158c13c]
  Binary file "/usr/lib/libffi.so.8", at ffi_call+0x12e [0x77b73158ef0e]
  Binary file "/opt/python/build/lib.linux-x86_64-3.14/_ctypes.cpython-314d-x86_64-linux-gnu.so", at +0x15a33 [0x77b7315e6a33]
  Binary file "/opt/python/build/lib.linux-x86_64-3.14/_ctypes.cpython-314d-x86_64-linux-gnu.so", at +0x164fa [0x77b7315e74fa]
  Binary file "/opt/python/build/lib.linux-x86_64-3.14/_ctypes.cpython-314d-x86_64-linux-gnu.so", at +0xc624 [0x77b7315dd624]
  Binary file "/opt/python/python", at _PyObject_MakeTpCall+0xce [0x5b27f7b73883]
  Binary file "/opt/python/python", at +0x11bab6 [0x5b27f7b73ab6]
  Binary file "/opt/python/python", at PyObject_Vectorcall+0x23 [0x5b27f7b73b04]
  Binary file "/opt/python/python", at _PyEval_EvalFrameDefault+0x490c [0x5b27f7cbb302]
  Binary file "/opt/python/python", at +0x2818e6 [0x5b27f7cd98e6]
  Binary file "/opt/python/python", at +0x281aab [0x5b27f7cd9aab]
  Binary file "/opt/python/python", at PyEval_EvalCode+0xc5 [0x5b27f7cd9ba3]
  Binary file "/opt/python/python", at +0x255957 [0x5b27f7cad957]
  Binary file "/opt/python/python", at +0x255ab4 [0x5b27f7cadab4]
  Binary file "/opt/python/python", at _PyEval_EvalFrameDefault+0x6c3e [0x5b27f7cbd634]
  Binary file "/opt/python/python", at +0x2818e6 [0x5b27f7cd98e6]
  Binary file "/opt/python/python", at +0x281aab [0x5b27f7cd9aab]
  Binary file "/opt/python/python", at +0x11b6e1 [0x5b27f7b736e1]
  Binary file "/opt/python/python", at +0x11d348 [0x5b27f7b75348]
  Binary file "/opt/python/python", at +0x11d626 [0x5b27f7b75626]
  Binary file "/opt/python/python", at PyObject_Call+0x20 [0x5b27f7b7565e]
  Binary file "/opt/python/python", at +0x32a67a [0x5b27f7d8267a]
  Binary file "/opt/python/python", at +0x32a7f8 [0x5b27f7d827f8]
  Binary file "/opt/python/python", at +0x32ac1b [0x5b27f7d82c1b]
  Binary file "/opt/python/python", at Py_RunMain+0x31 [0x5b27f7d82ebe]
  <truncated rest of calls>
Segmentation fault