Python:実行中のプロセスにコンソールを接続することは可能ですか?


81

プロセスの状態を確認したいだけです。コンソールをプロセスにアタッチして、プロセス内の関数を呼び出して、いくつかのグローバル変数を確認することは可能ですか。

プロセスは影響を受けずに実行されている方が良いです(もちろん、パフォーマンスは少し低下する可能性があります)


7
だから基本的にはデバッガ?
st0le 2010年

コマンドラインインタープリターpython.exeのようなもの
Bin Chen

回答:


42

プログラムのソースコードにアクセスできる場合は、この機能を比較的簡単に追加できます。

レシピ576515を参照してください:Debugging a running python process by interrupting and providing an interactive prompt (Python)

引用するには:

これは、それを使用するすべてのPythonプログラムが現在の時点で中断され、通常のPythonインタラクティブコンソールを介して通信できるようにするコードを提供します。これにより、ローカル、グローバル、および関連するプログラムの状態を調査したり、任意の関数やクラスを呼び出したりすることができます。

使用するには、プロセスがモジュールをインポートし、起動中の任意の時点でlisten()を呼び出す必要があります。このプロセスを中断するには、スクリプトを直接実行して、デバッグするプロセスのプロセスIDをパラメーターとして指定します。


ほぼ同じ概念の別の実装がrconsoleによって提供されます。ドキュメントから:

rconsoleは、オートコンプリート機能を備えたリモートPythonコンソールであり、実行中のスクリプトの名前空間を検査および変更するために使用できます。

スクリプトで呼び出すには、次のようにします。

from rfoo.utils import rconsole
rconsole.spawn_server()

シェルからアタッチするには、次のようにします。

$ rconsole

セキュリティに関する注意:spawn_server()で開始されたrconsoleリスナーはすべてのローカル接続を受け入れるため、共有ホスティングまたは同様の環境での使用は安全でない可能性があります。


2
それは本当にとてもいいレシピです。入力と出力にパイプとファイルを使用することは本当に賢いことであり、まともなプロジェクトならどれでもそのような機能の恩恵を受けると思います。
erkmene 2010年

2
ただし、非常に安全ではないため、注意して使用してください
fmark 2010年

レシピを試しましたが、Pythonのインストールが壊れました。'module'オブジェクトには属性 'getmro'がありません
'Cabral

コードにスタブを追加してrpcサーバーを起動した後、cython拡張機能をコンパイルしましたが、rconsoleは操作時に常に恥ずべきことに壊れます。rfoo._rfoo.EofError: 0
Sajuuk 2017

60

これによりプロセスが中断されますが(スレッドで開始しない限り)、codeモジュールを使用してPythonコンソールを開始できます。

import code
code.interact()

これは、ユーザーがを実行してインタラクティブコンソールを終了するまでブロックされexit()ます。

このcodeモジュールは、少なくともPython v2.6、おそらく他のバージョンで利用できます。

私はこのアプローチをLinux作業のシグナルと組み合わせて使用​​する傾向があります(Windowsの場合は以下を参照)。Pythonスクリプトの先頭でこれを叩きます:

import code
import signal
signal.signal(signal.SIGUSR2, lambda sig, frame: code.interact())

次にkill -SIGUSR2 <PID><PID>はプロセスIDであるシェルからトリガーします。次に、プロセスは実行中の処理をすべて停止し、コンソールを表示します。

Python 2.6.2 (r262:71600, Oct  9 2009, 17:53:52)
[GCC 3.4.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>

通常、そこから、優れたWinPDBのようなリモートデバッガーのサーバー側コンポーネントをロードします。

WindowsはPOSIX準拠のOSではないため、Linuxと同じ信号を提供しません。ただし、Python v2.2以降では、Windows固有のシグナルが公開されますSIGBREAKCTRL+を押すとトリガーされPause/Breakます)。これは通常の+ ()操作に干渉しないため、便利な代替手段です。CTRLCSIGINT

したがって、上記のポータブルで少し醜いバージョンは次のとおりです。

import code
import signal
signal.signal(
        vars(signal).get("SIGBREAK") or vars(signal).get("SIGUSR2"),
        lambda sig, frame: code.interact()
        )

このアプローチの利点:

  • 外部モジュールなし(すべての標準Pythonのもの)
  • トリガーされるまでリソースをほとんど消費しません(2xインポート)

これは、WinPDBのサーバー側(利用可能な場合)をロードし、Pythonコンソールを開くことにフォールバックする本番環境で使用するコードです。

# Break into a Python console upon SIGUSR1 (Linux) or SIGBREAK (Windows:
# CTRL+Pause/Break).  To be included in all production code, just in case.
def debug_signal_handler(signal, frame):
    del signal
    del frame

    try:
        import rpdb2
        print
        print
        print "Starting embedded RPDB2 debugger. Password is 'foobar'"
        print
        print
        rpdb2.start_embedded_debugger("foobar", True, True)
        rpdb2.setbreak(depth=1)
        return
    except StandardError:
        pass

    try:
        import code
        code.interact()
    except StandardError as ex:
        print "%r, returning to normal program flow" % ex

import signal
try:
    signal.signal(
            vars(signal).get("SIGBREAK") or vars(signal).get("SIGUSR1"),
            debug_signal_handler
            )
except ValueError:
    # Typically: ValueError: signal only works in main thread
    pass

Pythonコンソールを入手したら、WinPDBのサーバー側コンポーネントをロードする方法について詳しく教えてください。
クリスチャンロング

1
回答に製品コードを追加しましたが、基本的にはコンソールで次のように入力するだけです。 '' import rpdb2; rpdb2.start_embedded_debugger( "foobar"、True、True) ''そしてプロンプトが表示され
たら

26

ピラサイトシェルを使用します。うまくいくとは信じられませんが、うまくいきます。「それにpidを与えて、シェルを手に入れなさい」。

$ sudo pip install pyrasite
$ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope # If YAMA activated, see below.
$ pyrasite-shell 16262
Pyrasite Shell 2.0
Connected to 'python my_script.py'
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.

>>> globals()
>>> print(db_session)
>>> run_some_local_function()
>>> some_existing_local_variable = 'new value'

これにより、実行中のpythonプロセスのglobals()変数とlocals()変数、およびその他のすばらしいものにアクセスできるpythonシェルが起動します。

これはUbuntuで個人的にテストしただけですが、OSXにも対応しているようです。

この答えから適応。

注:ptrace_scopeプロパティをオフにする回線は、CONFIG_SECURITY_YAMAオンで構築されたカーネル/システムにのみ必要です。特定のセキュリティの脆弱性が発生する可能性があるため、機密性の高い環境でptrace_scopeをいじることに注意してください。詳細はこちらをご覧ください。


@Dirkあるプロセスが別の無関係なプロセスとトレース/対話できるようにするには、ptrace_scopeが不可欠だと思います。
python1981 2016年

明らかに、それはYAMAを備えたシステムでのみです。編集を提案し、元のコメントを削除しました。(これもしばらくの間行く予定です。)
Dirk

ドッカーで使用するためにここを参照してください:stackoverflow.com/questions/37072468/...
マイケル・スタインバーグ

4

単にpdbモジュールを使用しないのはなぜですか?これにより、スクリプトを停止し、要素の値を検査し、コードを1行ずつ実行できます。また、Pythonインタープリターに基づいて構築されているため、従来のインタープリターが提供する機能も提供します。これを使用するには、コードに次の2行を入れて、停止して検査します。

import pdb
pdb.set_trace()

3
threading.enumerate()の特定のスレッドに対して起動する方法を知っていますか?
yucer 2018

4

Pythonスクリプトに何かを追加せずに、別の可能性をここで説明します。

https://wiki.python.org/moin/DebuggingWithGdb

残念ながら、このソリューションには、少なくともデバッグシンボルを含むバージョンのPythonを使用する必要がある限り、ある程度の事前の考慮が必要です。


ほとんどのLinuxディストリビューションでは、Pythonはデバッグシンボルを使用して構築されていますが、デバッグシンボルは別のパッケージに含まれています。デバッグシンボルパッケージは、Pythonスクリプトがすでに開始された後にインストールできます。
W.Mann

1

PyCharmを使用して、Ubuntuのプロセスに接続できませんでした。これに対する修正は、YAMAを無効にすることです。詳細については、askubuntuを参照してください

echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.