faulthandler --- Python トレースバックをダンプする

Added in version 3.3.


このモジュールには、Python のトレースバックを明示的にダンプしたり、フォールトの発生時、タイムアウト後、ユーザーシグナルの受信時にダンプしたりする関数があります。 SIGSEGV、SIGFPE、SIGABRT、SIGBUS、SIGILL シグナルに対するフォールトハンドラを登録するには、faulthandler.enable() を呼び出してください。 環境変数 PYTHONFAULTHANDLER を設定するか、コマンドラインオプション -X faulthandler を指定すると、起動時に有効にすることもできます。

Pythonのフォールトハンドラは、apportやWindowsのフォールトハンドラのようなシステムフォールトハンドラと互換性があります。このモジュールは sigaltstack() 関数が使用可能であればシグナルハンドラ用に代替スタックを利用します。これによってスタックオーバーフロー時にもトレースバックを出力することができます。

フォールトハンドラは絶望的なケースで呼び出されます。そのためシグナルセーフな関数しか使うことができません (例: ヒープメモリ上にメモリ確保はできません)。この制限により、tracebackのダンプ機能は通常のPythonのtracebackと比べてごく僅かなものです:

  • ASCIIのみサポートされます。エンコード時には backslashreplace エラーハンドラを使用します。

  • すべての文字列は500文字以内に制限されています。

  • ファイル名、関数名、行番号だけを表示します (ソースコードは表示しません)。

  • 1 スレッドあたり 100 フレーム、合計 100 スレッドに制限されています (スレッド数は max_threads で設定できます)。

  • 順序は逆で、最も新しい呼び出しから表示します。

デフォルトでは、Pythonのtracebackは sys.stderr に書き出されます。tracebackを見るには、対象アプリケーションはターミナル上で実行しなければなりません。 faulthandler.enable() に渡す引数によってログファイルを指定することができます。

モジュールはC言語で実装されているので、アプリのクラッシュ時でもPythonがデッドロックした場合でもダンプができます。

Python 開発モード は Python の起動時に faulthandler.enable() を呼び出します。

参考

pdb モジュール

Python プログラム用の対話的なソースコードデバッガです。

traceback モジュール

Python プログラムのスタックトレースを抽出、書式化、表示する標準インターフェイスです。

tracebackのダンプ

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

すべてのスレッドのトレースバックを file にダンプします。 all_threads が False の場合は現在のスレッドだけをダンプします。 max_threads はダンプするスレッド数の上限です。

参考

トレースバックオブジェクトの表示に使える traceback.print_tb()。

バージョン 3.5 で変更: この関数にファイル記述子を渡せるようになりました。

バージョン 3.15 で変更: キーワード引数 max_threads が追加されました。

C スタックのダンプ

Added in version 3.14.

faulthandler.dump_c_stack(file=sys.stderr)

現在のスレッドの C スタックトレースを file にダンプします。

Python のビルドが対応していない場合や、OS がスタックトレースを提供しない場合は、C スタックのダンプの代わりにエラーを表示します。

C スタックの互換性

システムが C レベルの backtrace(3) または dladdr1(3) をサポートしない場合、C スタックのダンプは機能しません。 スタックの代わりにエラーを表示します。

また、一部のコンパイラは CPython の C スタックのダンプ実装をサポートしません。 そのため OS がスタックのダンプをサポートしていても、スタックの代わりに別のエラーが表示される場合があります。

注釈

C スタックのダンプは、呼び出しスタック内のバイナリの DWARF レベルによっては非常に時間がかかる場合があります。

フォールトハンドラの状態

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

フォールトハンドラを有効にします。 Python のトレースバックをダンプするために、SIGSEGV、SIGFPE、SIGABRT、SIGBUS、SIGILL シグナルのハンドラを登録します。 all_threads が True の場合は、実行中のすべてのスレッドのトレースバックを出力します。 それ以外の場合は現在のスレッドだけをダンプします。

フォールトハンドラを無効にするまで file を開いたままにしておく必要があります。 ファイル記述子の問題 を参照してください。

c_stack が True の場合、システムがサポートしていれば Python のトレースバックの後に C スタックトレースを表示します。 互換性の詳細は dump_c_stack() を参照してください。

max_threads は、致命的なシグナルの発生時にダンプするスレッド数の上限です。

バージョン 3.5 で変更: この関数にファイル記述子を渡せるようになりました。

バージョン 3.6 で変更: Windows では、Windows 例外のハンドラも登録するようになりました。

バージョン 3.10 で変更: all_threads が真で、ガベージコレクタが回収処理を実行中の場合、そのこともダンプに表示するようになりました。

バージョン 3.14 で変更: データ競合の危険を防ぐため、GIL が無効の場合は現在のスレッドだけをダンプするようになりました。

バージョン 3.14 で変更: c_stack が真の場合、ダンプに C スタックトレースも表示するようになりました。

バージョン 3.15 で変更: キーワード引数 max_threads が追加されました。

faulthandler.disable()

フォールトハンドラを無効にします: enable() によってインストールされたシグナルハンドラをアンインストールします。

faulthandler.is_enabled()

フォールトハンドラが有効かどうかチェックします。

タイムアウト後にtracebackをダンプする

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

timeout 秒後に、または repeat が True の場合は timeout 秒ごとに、すべてのスレッドのトレースバックをダンプします。 exit が True の場合、トレースバックをダンプした後に終了ステータス 1 で _exit() を呼び出します。 (_exit() はプロセスを直ちに終了するため、ファイルバッファのフラッシュなどの後処理は行いません。) この関数を 2 回呼び出すと、新しい呼び出しで以前のパラメータを置き換え、タイムアウトをリセットします。 タイマーの分解能は 1 秒未満です。 max_threads はダンプするスレッド数の上限です。

トレースバックがダンプされるか cancel_dump_traceback_later() が呼び出されるまで、file を開いたままにしておく必要があります。 ファイル記述子の問題 を参照してください。

この関数は監視用のスレッドを使って実装されています。

バージョン 3.5 で変更: この関数にファイル記述子を渡せるようになりました。

バージョン 3.7 で変更: この関数は常に利用可能になりました。

バージョン 3.15 で変更: キーワード引数 max_threads が追加されました。

faulthandler.cancel_dump_traceback_later()

dump_traceback_later() の最新の呼び出しをキャンセルします。

ユーザシグナルに対してtracebackをダンプする

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

ユーザーシグナルを登録します。 signum シグナルのハンドラを登録し、すべてのスレッド、または all_threads が False の場合は現在のスレッドのトレースバックを file にダンプします。 chain が True の場合は以前のハンドラも呼び出します。 max_threads はダンプするスレッド数の上限です。

unregister() でシグナルの登録を解除するまで、file を開いたままにしておく必要があります。 ファイル記述子の問題 を参照してください。

Windowsでは利用不可です。

バージョン 3.5 で変更: この関数にファイル記述子を渡せるようになりました。

バージョン 3.15 で変更: キーワード引数 max_threads が追加されました。

faulthandler.unregister(signum)

ユーザシグナルを登録解除します: register() でインストールした signum シグナルハンドラをアンインストールします。シグナルが登録された場合は True を返し、そうでなければ False を返します。

Windowsでは利用不可です。

ファイル記述子の問題

enable()、dump_traceback_later() ならびに register() は引数 file に渡されたファイル記述子を保持します。ファイルが閉じられファイル記述子が新しいファイルで再利用された場合や、os.dup2() の使用でファイル記述子が置き換えた場合、 traceback の結果は別のファイルへ書き込まれます。ファイルが置き換えられた場合は、毎回これらの関数を呼び出しなおしてください。

使用例

フォールトハンドラを有効化・無効化したときの 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.15/_ctypes.cpython-315d-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.15/_ctypes.cpython-315d-x86_64-linux-gnu.so", at +0x15a33 [0x77b7315e6a33]
  Binary file "/opt/python/build/lib.linux-x86_64-3.15/_ctypes.cpython-315d-x86_64-linux-gnu.so", at +0x164fa [0x77b7315e74fa]
  Binary file "/opt/python/build/lib.linux-x86_64-3.15/_ctypes.cpython-315d-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