python:是否可以将控制台附加到正在运行的进程中


81

我只想查看流程的状态,是否可以将控制台附加到流程中,所以我可以在流程内部调用函数并查看一些全局变量。

最好在不受影响的情况下运行该进程(当然,性能可能会下降一点)


7
所以基本上是调试器?
st0le 2010年

类似于命令行解释器python.exe
Bin Chen 2010年

Answers:


42

如果您有权访问程序的源代码,则可以相对轻松地添加此功能。

参见配方576515Debugging 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

2
但是它非常不安全,请谨慎使用
fmark 2010年

我尝试了食谱,但它破坏了我的python安装。“模块”对象没有属性“getmro”
维克多克里斯'卡布拉尔

在将存根添加到代码中并启动rpc服务器后,我编译了cython扩展,但是rconsole在执行任何操作时都会始终中断。rfoo._rfoo.EofError: 0
Sajuuk

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>,从shell触发它,其中<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兼容的操作系统,因此不能提供与Linux相同的信号。但是,Python v2.2及更高版本公开了Windows特定的信号SIGBREAK(通过按CTRL+触发Pause/Break)。这并不能与正常干扰CTRL+ CSIGINT)操作,并且因此是一个方便的替代。

因此,上述的一种可移植但有点难看的版本是:

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

这种方法的优点:

  • 没有外部模块(所有标准Python东西)
  • 几乎不消耗任何资源,直到触发(两次导入)

这是我在生产环境中使用的代码,该代码将加载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)“,然后在出现提示时使用密码“ foobar”启动WinPDB GUI
RobM

26

使用吡a石壳。我不敢相信它能很好地工作,但是确实可以。“给它一个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 shell,并可以访问正在运行的python进程的globals()和locals()变量,以及其他奇妙的东西。

仅在Ubuntu上对此进行了个人测试,但似乎也可以适应OSX。

这个答案改编。

注意:ptrace_scope仅在使用CONFIG_SECURITY_YAMAon构建的内核/系统中,关闭属性的行才是必需的。在敏感环境中请小心处理ptrace_scope,因为它可能会引入某些安全漏洞。有关详细信息,请参见此处


@Dirk我相信ptrace_scope对于允许一个进程与另一个不相关的进程进行跟踪/交互至关重要。
python1981年

显然,这仅在具有YAMA的系统上。建议修改并删除我的原始评论。(此消息还将在一段时间内发布。)
德克(Dirk


5

为什么不简单地使用pdb模块呢?它允许您停止脚本,检查元素值以及逐行执行代码。由于它是基于Python解释器构建的,因此它还提供了经典解释器提供的功能。要使用它,只需将这两行放在您想要停止并检查它的代码中:

import pdb
pdb.set_trace()

3
你知道如何为给定的threading.enumerate()线程启动它吗?
yucer

4

此处描述了另一种可能的方法,无需在python脚本中添加内容:

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

不幸的是,此解决方案还需要一些周全的考虑,至少在某种程度上需要使用其中带有调试符号的python版本。


对于大多数Linux发行版,python是使用调试符号构建的,但是调试符号位于其他软件包中。可以在启动python脚本后安装调试符号包。
W.Mann '18

1

使用PyCharm,我无法连接到Ubuntu中的进程。解决方法是禁用YAMA。有关更多信息,请参见askubuntu

echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.