私は時々立ち往生しているこのPythonアプリケーションを持っていて、どこにいるのかわかりません。
実行中の正確なコードを表示するようにPythonインタープリターに通知する方法はありますか?
ある種のオンザフライスタックトレース?
関連する質問:
私はこのような状況で使用するモジュールを持っています-プロセスは長時間実行されますが、未知の再現不可能な理由で時々スタックします。それは少しハッキーで、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クックブックレシピとして追加しました。
シグナルハンドラーをインストールするという提案は良いものであり、私はそれをよく使用します。たとえば、bzrはデフォルトでpdb.set_trace()
、pdbプロンプトにすぐにドロップするために呼び出すSIGQUITハンドラーをインストールします。(正確な詳細については、bzrlib.breakinモジュールのソースを参照してください。)pdbを使用すると、((w)here
コマンドを使用して)現在のスタックトレースを取得できるだけでなく、変数などを検査することもできます。
ただし、シグナルハンドラーをインストールする先見の明がなかったプロセスをデバッグする必要がある場合があります。Linuxでは、gdbをプロセスにアタッチし、いくつかのgdbマクロを使用してPythonスタックトレースを取得できます。プットhttp://svn.python.org/projects/python/trunk/Misc/gdbinitで~/.gdbinit
、その後:
gdb -p
PID
pystack
残念ながら、完全に信頼できるわけではありませんが、ほとんどの場合は機能します。
最後に、アタッチstrace
することで、プロセスが何をしているのかがよくわかります。
私はほとんど常に複数のスレッドを扱っており、メインスレッドは一般的にあまり機能していないので、最も興味深いのはすべてのスタックをダンプすることです(これは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)
準備されていないPythonプログラムのスタックトレースを取得し、シンボルをデバッグせずにストックPythonで実行すると、pyrasiteを使用して実行できます。Ubuntu Trustyで私にとって魅力のように働いた:
$ sudo pip install pyrasite $ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
$ sudo pyrasite 16262 dump_stacks.py # dumps stacks to stdout/stderr of the python program
(@Albertへのハットチップ。その回答には、他のツールの中でも、これへのポインターが含まれていました。)
>>> import traceback
>>> def x():
>>> print traceback.extract_stack()
>>> x()
[('<stdin>', 1, '<module>', None), ('<stdin>', 2, 'x', None)]
スタックトレースを適切にフォーマットすることもできます。ドキュメントを参照してください。
編集:@Douglas Leederによって提案されているように、Javaの動作をシミュレートするには、次を追加します。
import signal
import traceback
signal.signal(signal.SIGUSR1, lambda sig, stack: traceback.print_stack(stack))
アプリケーションのスタートアップコードに。次にSIGUSR1
、実行中のPythonプロセスに送信して、スタックを印刷できます。
トレースバックモジュールは、それらの間で、いくつかの素晴らしい機能を持っていますprint_stackを:
import traceback
traceback.print_stack()
フォールトハンドラモジュールを試すことができます。を使用してインストールしpip install faulthandler
、以下を追加します。
import faulthandler, signal
faulthandler.register(signal.SIGUSR1)
プログラムの開始時に。次に、SIGUSR1をプロセス(例:)に送信してkill -USR1 42
、すべてのスレッドのPythonトレースバックを標準出力に表示します。その他のオプション(例:ファイルにログイン)およびトレースバックを表示するその他の方法については、ドキュメントをお読みください。
このモジュールはPython3.3の一部になりました。Python 2については、を参照してください。http://faulthandler.readthedocs.org/
ここで本当に助けになったのは、準備されていないPythonプロセスからスタックトレースを取得するためのspivのヒント(レピュテーションポイントがあれば投票してコメントする)です。gdbinitスクリプトを変更するまで機能しなかったことを除いて。そう:
ダウンロード http://svn.python.org/projects/python/trunk/Misc/gdbinit 入れて ~/.gdbinit
編集して、に変更[編集:不要になりました; リンクされたファイルには、2010-01-14の時点ですでにこの変更があります]PyEval_EvalFrame
しますPyEval_EvalFrameEx
gdbをアタッチします: gdb -p PID
Pythonスタックトレースを取得します。 pystack
python -dv yourscript.py
これにより、インタプリタがデバッグモードで実行され、インタプリタが実行していることのトレースが得られます。
コードをインタラクティブにデバッグする場合は、次のように実行する必要があります。
python -m pdb yourscript.py
これは、Pythonデバッガーであるモジュール「pdb」を使用してスクリプトを実行するようにPythonインタープリターに指示します。このように実行すると、インタープリターはGDBと同様にインタラクティブモードで実行されます。
これをharidsvの応答へのコメントとして追加しますが、そうするという評判がありません。
私たちの何人かはまだ2.6より古いバージョンのPython(Thread.identに必要)で立ち往生しているので、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)
Python3.3のfaulthandler
新機能であるモジュールを見てください。faulthandler
Python2で使用するためのバックポートはPyPIで利用できます。
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.
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
参照してください。例セッションと詳細情報をこことここ。
私は自分のスレッドをデバッグするための解決策をしばらく探していましたが、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)
必要に応じて、スレッドを名前でフィルタリングします。
それは優れたpy-spyで行うことができます。これはPythonプログラムのサンプリングプロファイラーであるため、その仕事はPythonプロセスにアタッチし、それらの呼び出しスタックをサンプリングすることです。したがって、プロセスpy-spy dump --pid $SOME_PID
内のすべてのスレッドの呼び出しスタックをダンプするために必要なのはこれだけです$SOME_PID
。通常、(ターゲットプロセスのメモリを読み取るために)昇格された特権が必要です。
スレッド化されたPythonアプリケーションの場合の例を次に示します。
$ sudo py-spy dump --pid 31080
Process 31080: python3.7 -m chronologer -e production serve -u www-data -m
Python v3.7.1 (/usr/local/bin/python3.7)
Thread 0x7FEF5E410400 (active): "MainThread"
_wait (cherrypy/process/wspbus.py:370)
wait (cherrypy/process/wspbus.py:384)
block (cherrypy/process/wspbus.py:321)
start (cherrypy/daemon.py:72)
serve (chronologer/cli.py:27)
main (chronologer/cli.py:84)
<module> (chronologer/__main__.py:5)
_run_code (runpy.py:85)
_run_module_as_main (runpy.py:193)
Thread 0x7FEF55636700 (active): "_TimeoutMonitor"
run (cherrypy/process/plugins.py:518)
_bootstrap_inner (threading.py:917)
_bootstrap (threading.py:885)
Thread 0x7FEF54B35700 (active): "HTTPServer Thread-2"
accept (socket.py:212)
tick (cherrypy/wsgiserver/__init__.py:2075)
start (cherrypy/wsgiserver/__init__.py:2021)
_start_http_thread (cherrypy/process/servers.py:217)
run (threading.py:865)
_bootstrap_inner (threading.py:917)
_bootstrap (threading.py:885)
...
Thread 0x7FEF2BFFF700 (idle): "CP Server Thread-10"
wait (threading.py:296)
get (queue.py:170)
run (cherrypy/wsgiserver/__init__.py:1586)
_bootstrap_inner (threading.py:917)
_bootstrap (threading.py:885)
Pydb、「gdbコマンドセットに大まかに基づいたPythonデバッガーの拡張バージョン」を見る価値があります。これには、指定されたシグナルが送信されたときにデバッガーの起動を処理できるシグナルマネージャーが含まれています。
2006年夏のコードのプロジェクトと呼ばれるモジュールにpydbにリモートデバッグ機能を追加して見mpdb。
実行中のPythonプロセスにアタッチし、Pythonシェルを取得するためにコードを挿入するツールを一緒にハッキングしました。
ここを参照してください: https://github.com/albertz/pydbattach
pyringeは、事前に設定しなくても、実行中のpythonプロセス、出力スタックトレース、変数などと対話できるデバッガーです。
私は過去にシグナルハンドラソリューションを頻繁に使用しましたが、特定の環境では問題を再現するのが難しい場合があります。
実行中のPythonプロセスにフックして、妥当な結果を得る方法はありません。プロセスがロックアップした場合に私が行うことは、straceをフックして、何が起こっているのかを正確に把握しようとすることです。
残念ながら、多くの場合、straceは競合状態を「修正」して、出力がそこでも役に立たないようにするオブザーバーです。
これを行うには、cursesインターフェースを備えたPythonデバッガーであるPuDBを使用できます。追加するだけです
from pudb import set_interrupt_handler; set_interrupt_handler()
コードに追加し、中断したい場合はCtrl-Cを使用します。c
失敗して再試行したい場合は、続行して何度も中断することができます。
私はPython拡張機能を備えたGDBキャンプにいます。フォローするhttps://wiki.python.org/moin/DebuggingWithGdb、つまり
dnf install gdb python-debuginfo
または sudo apt-get install gdb python2.7-dbg
gdb python <pid of running process>
py-bt
また、とを検討info threads
してくださいthread apply all py-bt
。
コンソールで関数をデバッグする方法:
pdb.set_trace()を使用する関数を作成してから、デバッグする関数を作成します。
>>> import pdb
>>> import my_function
>>> def f():
... pdb.set_trace()
... my_function()
...
次に、作成した関数を呼び出します。
>>> f()
> <stdin>(3)f()
(Pdb) s
--Call--
> <stdin>(1)my_function()
(Pdb)
ハッピーデバッグ:)
次のように、hypnoパッケージを使用できます。
hypno <pid> "import traceback; traceback.print_stack()"
これにより、スタックトレースがプログラムの標準出力に出力されます。
または、stdoutに何も出力したくない場合、またはそれにアクセスできない場合(デーモンなど)、実行中のファイルにアタッチできるPythonデバッガーであるmadbgパッケージを使用できます。 Pythonプログラムを作成し、現在のターミナルでデバッグします。それはに類似しているpyrasite
とpyringe
、より新しい、GDBを必要とせず、用途IPython
(色や自動補完を意味する)デバッガのために。
実行中のプログラムのスタックトレースを確認するには、次のコマンドを実行します。
madbg attach <pid>
そして、デバッガシェルに次のように入力します。 bt
免責事項-私は両方のパッケージを書きました
SIGQUITに対するJavaの応答に似たものは何も知らないので、アプリケーションに組み込む必要があるかもしれません。ある種のメッセージへの応答でスタックトレースを取得できるサーバーを別のスレッドで作成できるかもしれません。
検査モジュールを使用します。
import inspect help(inspect.stack)モジュールinspectの関数スタックに関するヘルプ:
stack(context = 1)呼び出し元のフレームの上のスタックのレコードのリストを返します。
本当に参考になりました。
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などの同様のツールを使用したことのある人なら誰でも知っているはずです。
uWSGIでこれを行う必要がある場合は、Python Tracebackerが組み込まれており、構成で有効にするだけです(各ワーカーの名前に番号が付けられます)。
py-tracebacker=/var/run/uwsgi/pytrace
これを実行すると、ソケットに接続するだけでバックトレースを出力できます。
uwsgi --connect-and-read /var/run/uwsgi/pytrace1
コードが実行された時点で、この小さなスニペットを挿入して、適切にフォーマットされた印刷されたスタックトレースを確認できます。logs
プロジェクトのルートディレクトリにというフォルダがあることを前提としています。
# DEBUG: START DEBUG -->
import traceback
with open('logs/stack-trace.log', 'w') as file:
traceback.print_stack(file=file)
# DEBUG: END DEBUG --!
特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。
ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。
ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。
ジョエル・マクヘイル、マイク・コルター(スクリーンショット:Netflix)「私の神よ、これは1つのことを変えます。」これは、ジョエル・マクヘイルとのジョエル・マクヘイルショーの最後のジョークです。リアリティ番組の嘲笑と寛大なスナキネスの時間は、なじみのある顔を見つけます。
画像経由:@pancakeparadox(Twitter)。1997年にポケモンシリーズが初公開されて以来、チームロケット(またはラテンアメリカではチームロケット)として知られる悪役のグループは、何度もアッシュに直面してきました。
画像:ゲッティ私たち全員が千年もの間生きていて、私たちの体が燃える風によってほこりと長引く悲鳴だけに押し流されたと考えるのは驚くべきことです。私たちがそうしていないことを除いて、それはトランプ政権の最初の週の終わりであり、驚くほど多くの恐ろしいことがすでに起こっています。
そして今、あることを手に入れていると思っていたが、まったく別のことをしてしまった男の話。CBSニュースは、彼女が「ミニブタ」であるという誤ったふりをしてエスターを養子にしたカナダ人のスティーブジェンキンスの心温まる物語をもたらします。これは、特にせいぜいゴールデンレトリバーまたはセントバーナードをストラップします。
Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday
シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。
オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。
Bioscoutは、農家を運転席に置くという使命を負っています。Artesian(GrainInnovate)やUniseedと並んで、最新のシードラウンドでチームを支援できることをうれしく思います。問題真菌症による重大な作物の損失は、農民にとって試練であることが証明されています。
遠隔医療は、パンデミック後の時代では新しいものではなく、時代遅れの分野でもありません。しかし、業界を詳しく見ると、需要と供給の強力な持続可能性と、米国で絶え間ない革命となる強力な潜在的成長曲線を示しています。
2021年は、世界的なベンチャーキャピタル(VC)の資金調達にとって記録的な年でした。DealStreetAsiaによると、東南アジアも例外ではなく、この地域では年間で記録的な25の新しいユニコーンが採掘されました。
計算に対する私たちの欲求とムーアの法則が提供できるものとの間には、指数関数的に増大するギャップがあります。私たちの文明は計算に基づいています—建築と想像力の現在の限界を超える技術を見つけなければなりません。