367

私は時々立ち往生しているこのPythonアプリケーションを持っていて、どこにいるのかわかりません。

実行中の正確なコードを表示するようにPythonインタープリターに信号を送る方法はありますか?

ある種のオンザフライスタックトレース?

関連する質問:

4

29 に答える 29

338

私はこのような状況で使用するモジュールを持っています-プロセスは長時間実行されますが、未知の再現不可能な理由で時々スタックします。それは少しハッキーで、UNIXでのみ機能します(信号が必要です):

import code, traceback, signal

def debug(sig, frame):
    """Interrupt running process, and provide a python prompt for
    interactive debugging."""
    d={'_frame':frame}         # Allow access to frame object.
    d.update(frame.f_globals)  # Unless shadowed by global
    d.update(frame.f_locals)

    i = code.InteractiveConsole(d)
    message  = "Signal received : entering python shell.\nTraceback:\n"
    message += ''.join(traceback.format_stack(frame))
    i.interact(message)

def listen():
    signal.signal(signal.SIGUSR1, debug)  # Register handler

使用するには、プログラムの起動時にlisten()関数を呼び出し(site.pyに貼り付けて、すべてのPythonプログラムに使用させることもできます)、実行させます。いつでも、killを使用して、またはpythonでプロセスにSIGUSR1シグナルを送信します。

    os.kill(pid, signal.SIGUSR1)

これにより、プログラムは現在の時点でPythonコンソールにブレークし、スタックトレースが表示され、変数を操作できるようになります。control-d(EOF)を使用して、実行を続行します(ただし、信号を送信した時点でI / Oなどを中断する可能性があるため、完全に邪魔にならないわけではありません。

同じことを行う別のスクリプトがありますが、パイプを介して実行中のプロセスと通信する点が異なります(バックグラウンドプロセスのデバッグなどを可能にするため)。ここに投稿するには少し大きいですが、Pythonクックブックレシピとして追加しました。

于 2008-09-25T13:38:45.257 に答える
151

シグナルハンドラーをインストールするという提案は良いもので、私はそれをよく使います。たとえば、bzrはデフォルトで SIGQUIT ハンドラーをインストールし、これを呼び出しpdb.set_trace()てすぐにpdbプロンプトにドロップします。(正確な詳細については、bzrlib.breakinモジュールのソースを参照してください。) pdb を使用すると、(コマンドを使用して) 現在のスタック トレースを取得できるだけでなく、(w)here変数などを検査することもできます。

ただし、シグナル ハンドラーをインストールするための先見の明がなかったプロセスをデバッグする必要がある場合があります。http://svn.python.org/projects/python/trunk/Misc/gdbinitを入れてから:~/.gdbinit

  • gdb をアタッチします。gdb -p PID
  • Python スタック トレースを取得します。pystack

残念ながら完全に信頼できるわけではありませんが、ほとんどの場合は機能します。

最後に、アタッチstraceすると、プロセスが何をしているかがよくわかります。

于 2008-09-29T00:44:13.467 に答える
79

私はほとんどの場合複数のスレッドを扱っており、メインスレッドは一般的にあまり機能していないため、最も興味深いのはすべてのスタックをダンプすることです(これは、Javaのダンプに似ています)。これがこのブログに基づく実装です:

import threading, sys, traceback

def dumpstacks(signal, frame):
    id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
    code = []
    for threadId, stack in sys._current_frames().items():
        code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""), threadId))
        for filename, lineno, name, line in traceback.extract_stack(stack):
            code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
            if line:
                code.append("  %s" % (line.strip()))
    print("\n".join(code))

import signal
signal.signal(signal.SIGQUIT, dumpstacks)
于 2010-04-02T23:23:47.080 に答える
37
>>> import traceback
>>> def x():
>>>    print traceback.extract_stack()

>>> x()
[('<stdin>', 1, '<module>', None), ('<stdin>', 2, 'x', None)]

スタック トレースを適切にフォーマットすることもできます。 docsを参照してください。

編集:@Douglas Leederが提案するように、Javaの動作をシミュレートするには、これを追加します:

import signal
import traceback

signal.signal(signal.SIGUSR1, lambda sig, stack: traceback.print_stack(stack))

アプリケーションのスタートアップ コードに追加します。SIGUSR1次に、実行中の Python プロセスに送信することで、スタックを出力できます。

于 2008-09-25T08:29:32.643 に答える
30

tracebackモジュールにはいくつかの優れた機能があります。

import traceback

traceback.print_stack()
于 2008-09-25T08:27:16.923 に答える
20

ここで本当に助けになったのは、準備されていないPythonプロセスからスタックトレースを取得するためのspivのヒント(レピュテーションポイントがあれば投票してコメントする)です。gdbinitスクリプトを変更するまで機能しなかったことを除いて。それで:

  • http://svn.python.org/projects/python/trunk/Misc/gdbinitをダウンロードして、~/.gdbinit

  • 編集して、に変更PyEval_EvalFrameしますPyEval_EvalFrameEx[編集:もう必要ありません; リンクされたファイルには、2010-01-14の時点ですでにこの変更があります]

  • gdbをアタッチします:gdb -p PID

  • Pythonスタックトレースを取得します。pystack

于 2009-03-06T12:49:11.137 に答える
13

python -dv yourscript.py

これにより、インタプリタがデバッグモードで実行され、インタプリタが実行していることのトレースが得られます。

コードをインタラクティブにデバッグする場合は、次のように実行する必要があります。

python -m pdb yourscript.py

これは、Pythonデバッガーであるモジュール「pdb」を使用してスクリプトを実行するようにPythonインタープリターに指示します。このように実行すると、インタープリターはGDBのようにインタラクティブモードで実行されます。

于 2008-09-25T08:24:24.997 に答える
12

これをコメントとしてharidsv の応答に追加しますが、そうする評判がありません。

私たちの中には、2.6 (Thread.ident に必要) よりも古いバージョンの Python にまだ行き詰まっている人もいるので、Python 2.5 で動作するコードを取得しました (ただし、スレッド名は表示されません)。

import traceback
import sys
def dumpstacks(signal, frame):
    code = []
    for threadId, stack in sys._current_frames().items():
            code.append("\n# Thread: %d" % (threadId))
        for filename, lineno, name, line in traceback.extract_stack(stack):
            code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
            if line:
                code.append("  %s" % (line.strip()))
    print "\n".join(code)

import signal
signal.signal(signal.SIGQUIT, dumpstacks)
于 2011-03-31T16:30:51.250 に答える
11

faulthandlerPython 3.3 で新しく追加されたモジュールを見てみましょう。Python 2 で使用するfaulthandlerバックポートは PyPI で利用できます。

于 2012-01-26T13:57:38.473 に答える
7

Solaris では、pstack(1) を使用できます。Python コードを変更する必要はありません。例えば。

# pstack 16000 | grep : | head
16000: /usr/bin/python2.6 /usr/lib/pkg.depotd --cfg svc:/application/pkg/serv
[ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:282 (_wait) ]
[ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:295 (wait) ]
[ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:242 (block) ]
[ /usr/lib/python2.6/vendor-packages/cherrypy/_init_.py:249 (quickstart) ]
[ /usr/lib/pkg.depotd:890 (<module>) ]
[ /usr/lib/python2.6/threading.py:256 (wait) ]
[ /usr/lib/python2.6/Queue.py:177 (get) ]
[ /usr/lib/python2.6/vendor-packages/pkg/server/depot.py:2142 (run) ]
[ /usr/lib/python2.6/threading.py:477 (run)
etc.
于 2011-08-28T21:30:38.647 に答える
6

スレッドをデバッグするための解決策をしばらく探していましたが、haridsv のおかげでここで見つけました。私は、traceback.print_stack() を採用した、少し簡略化したバージョンを使用しています。

import sys, traceback, signal
import threading
import os

def dumpstacks(signal, frame):
  id2name = dict((th.ident, th.name) for th in threading.enumerate())
  for threadId, stack in sys._current_frames().items():
    print(id2name[threadId])
    traceback.print_stack(f=stack)

signal.signal(signal.SIGQUIT, dumpstacks)

os.killpg(os.getpgid(0), signal.SIGQUIT)

必要に応じて、スレッドを名前でフィルタリングします。

于 2012-04-15T20:28:10.047 に答える
6

Linux システムを使用している場合はgdb、Python デバッグ拡張機能 (インpython-dbgまたはpython-debuginfoパッケージ) の優れた機能を使用してください。また、マルチスレッド アプリケーション、GUI アプリケーション、および C モジュールにも役立ちます。

次のようにプログラムを実行します。

$ gdb -ex r --args python <programname>.py [arguments]

これは、それgdbを準備python <programname>.py <arguments>してr解凍するように指示します。

プログラムがハングしたら、gdbコンソールに切り替え、押しCtr+Cて実行します。

(gdb) thread apply all py-list

セッションの例と詳細については、こちらこちらをご覧ください。

于 2013-06-24T08:03:31.333 に答える
4

実行中の Python プロセスにアタッチし、コードを挿入して Python シェルを取得するツールをハックしました。

ここを参照してください: https://github.com/albertz/pydbattach

于 2012-04-06T18:49:30.193 に答える
1

これを行うには、curses インターフェースを備えた Python デバッガーであるPuDBを使用できます。追加するだけ

from pudb import set_interrupt_handler; set_interrupt_handler()

コードに追加し、中断したい場合は Ctrl-C を使用します。c失敗してやり直したい場合は、続行して何度でも中断できます。

于 2013-04-27T00:54:57.780 に答える
1

私はPython拡張機能を備えたGDBキャンプにいます。https://wiki.python.org/moin/DebuggingWithGdbに従ってください。つまり、

  1. dnf install gdb python-debuginfoまたsudo apt-get install gdb python2.7-dbg
  2. gdb python <pid of running process>
  3. py-bt

と も考慮info threadsしてthread apply all py-btください。

于 2018-04-18T12:31:10.410 に答える
0

SIGQUITに対するJavaの応答に似たものは何も知らないので、アプリケーションに組み込む必要があるかもしれません。ある種のメッセージへの応答でスタックトレースを取得できるサーバーを別のスレッドで作成できるかもしれません。

于 2008-09-25T09:06:39.747 に答える
0

実行中の Python プロセスにフックして妥当な結果を得る方法はありません。プロセスがロックアップした場合に私が行うことは、strace を接続して、正確に何が起こっているのかを把握しようとすることです。

残念ながら、多くの場合、strace は競合状態を「修正」するオブザーバーであるため、そこでも出力が役に立たなくなります。

于 2008-09-25T09:09:54.670 に答える
0

検査モジュールを使用します。

import inspect help(inspect.stack) モジュール inspect の関数スタックに関するヘルプ:

stack(context=1) 呼び出し元のフレームの上のスタックのレコードのリストを返します。

本当にとても役に立ちます。

于 2009-09-16T06:44:42.513 に答える
0

Python 3 では、デバッガーで c(ont(inue)) を初めて使用するときに、pdb が自動的にシグナル ハンドラーをインストールします。後で Control-C を押すと、そこに戻ります。Python 2 では、比較的古いバージョンでも機能するはずのワンライナーを次に示します (2.7 でテストしましたが、Python ソースを 2.4 に戻して確認したところ、問題ないように見えました)。

import pdb, signal
signal.signal(signal.SIGINT, lambda sig, frame: pdb.Pdb().set_trace(frame))

Python のデバッグに少しでも時間を費やすなら、pdb を学ぶ価値があります。インターフェースは少しわかりにくいですが、gdb などの同様のツールを使用したことがある人にはなじみがあるはずです。

于 2014-12-14T02:16:25.313 に答える
0

uWSGI でこれを行う必要がある場合は、Python Tracebackerが組み込まれており、構成で有効にするだけです (番号は各ワーカーの名前に付けられます)。

py-tracebacker=/var/run/uwsgi/pytrace

これが完了したら、ソケットに接続するだけでバックトレースを出力できます。

uwsgi --connect-and-read /var/run/uwsgi/pytrace1
于 2015-04-28T06:15:05.903 に答える