2011年5月14日土曜日

Python 3.3 で導入されるデバッグに役立つ faulthandler モジュール

原文はこちら: New faulthandler module in Python 3.3 helps debugging

プログラムが強制終了したり、固まったりしたことをユーザが報告する際にできることは、その状況の再現手順の概要とより詳細な情報を収集しようとすることだけです。信頼できるユーザーからの再現手順であっても、オペレーティングシステムやコンパイラといった環境の違いから、開発者として再現できないこともよくあります。運が良ければ、ユーザーがデバッグツールをインストールしてくれますが、誰かが同じ環境で詳細な情報を収集してくれるまで、ほとんどの時間を待っていなければなりません。

致命的なエラー


Python 3.3 で導入される新たなモジュール faulthandler は、この問題に役立ちます。 faulthandler は、セグメンテーションフォールト、ゼロ除算、処理の中断、バスエラーといった致命的なエラーのトレースバックをダンプする機能を提供します。Python の実行ファイルに対して -X faulthandler オプションを指定するか、もしくは環境変数 PYTHONFAULTHANDLER=1 を設定してから、 faulthandler.enable() を使ってアプリケーション内部で有効化します。出力結果は次のようになります。
Fatal Python error: Segmentation fault

Current thread 0x00007f7babc6b700:
  File "Lib/test/crashers/gc_inspection.py", line 29 in g
  File "Lib/test/crashers/gc_inspection.py", line 32 in <module>
Segmentation fault

タイムアウト


faulthandler は、 faulthandler.dump_tracebacks_later(timeout) を使って、タイムアウトした後にトレースバックをダンプすることもできます。そのタイマーを再起動するために再び呼び出すか、そのタイマーを停止するために faulthandler.cancel_dump_tracebacks_later() を呼び出します。出力結果は次のようになります。
Timeout (0:01:00)!
Current thread 0x00007f987d459700:
  File "Lib/test/crashers/infinite_loop_re.py", line 20 in <module>
timeout 秒毎にトレースバックをダンプするには repeat=True オプションを使ってください。または、そのプログラムが不安定な状態のときに、例えばファイルをフラッシュせずに、すぐに終了するには exit=True を使ってください。

ユーザシグナル


プログラムを実行しているホストへアクセスできるなら、 signal を受け取ったときに、トレースバックをダンプするシグナルハンドラをインストールするために faulthandler.register(signal) を使ってください。UNIX 上では、例えば、 SIGUSR1 シグナルを使えます。 kill -USR1 <pid> は、カレントのトレースバックをダンプします。この機能は Windows 上では使えません。出力結果は次のようになります。
Current thread 0x00007fdc3da74700:
  File "Lib/test/crashers/infinite_loop_re.py", line 19 in <module>
もう1つの方法は、プログラム内で明示的に faulthandler.dump_traceback() を呼び出します。

セキュリティの問題と出力ファイル


faulthandler は、セキュリティの理由からデフォルトで無効化されています。その主な理由は sys.stderr のファイルディスクリプタに保存して、そこへトレースバックを書き込むからです。もし sys.stderr がクローズされて、ファイルディスクリプタが再利用される場合、そのファイルディスクリプタはソケット、パイプ、重要なファイル、またはその他に使われる可能性があります。デフォルトでは、 faulthandler はトレースバックを sys.stderr へ書き込みますが、別のファイルも指定できます。詳細は faulthandler ドキュメント を参照してください。

古い Python バージョン向けのサードパーティモジュール


さらに faulthandler は、 PyPI 上で Python 2.5 から 3.2 を対象としたサードパーティーモジュールとしてメンテナンスされています。Python 3.3 のモジュールとサードパーティモジュール間での主な違いは dump_tracebacks_later() の実装です。Python 3.3 は、ロックのタイムアウトをもつスレッドを使うのに対して、サードパーティモジュールは SIGALRMalarm() を使います。

Python 3.3 の新機能であるロックのタイムアウトは、マイクロ秒単位の精度です。旧バージョンで使われる alarm() タイマーは、秒単位の精度です。さらに SIGALRM シグナルは、 EINTR エラーで失敗したカレントのシステムコールを中断させる可能性があります。

早期の成功


新たな faulthandler モジュールは、既に buildbot の競合状態を追跡するのに役立っています。このモジュールがあなたのプログラムにおいても役立つことを願っています。

0 件のコメント:

コメントを投稿