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

python: is it possible to attach a console into a running process

我只想看看进程的状态,是否可以在进程中附加一个控制台,这样我就可以调用进程内部的函数并查看一些全局变量。

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


这将中断您的进程(除非您在线程中启动它),但您可以使用code模块启动python控制台:

1
2
import code
code.interact()

这将被阻止,直到用户通过执行exit()退出交互控制台。

code模块至少在python 2.6版中可用,可能还有其他版本。

对于我的Linux工作,我倾向于将这种方法与信号结合使用(对于Windows,请参见下文)。我把它放在了我的python脚本的顶部:

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

然后从带有kill -SIGUSR2 的shell中触发它,其中是进程ID。然后该进程停止它正在执行的操作,并显示一个控制台:

1
2
3
4
5
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 2.2及更高版本公开了一个特定于Windows的信号SIGBREAK(由按CTRLPause/Break触发)。这不会干扰正常的CTRLC+(SIGINT)操作,因此是一种方便的选择。

因此,一个便携的,但有点难看的,上面的版本是:

1
2
3
4
5
6
import code
import signal
signal.signal(
        vars(signal).get("SIGBREAK") or vars(signal).get("SIGUSR2"),
        lambda sig, frame: code.interact()
        )

这种方法的优点:

  • 没有外部模块(所有标准的python工具)
  • 在触发之前几乎不消耗任何资源(2x导入)

下面是我在生产环境中使用的代码,它将加载winpdb的服务器端(如果可用),并返回到打开Python控制台。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 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


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

见配方576515:Debugging a running python process by interrupting and providing an interactive prompt (Python)

引述:

This provides code to allow any python
program which uses it to be
interrupted at the current point, and
communicated with via a normal python
interactive console. This allows the
locals, globals and associated program
state to be investigated, as well as
calling arbitrary functions and
classes.

To use, a process should import the
module, and call listen() at any point
during startup. To interrupt this
process, the script can be run
directly, giving the process Id of the
process to debug as the parameter.

rconsole提供了大致相同概念的另一个实现。从文档中:

rconsole is a remote Python console
with auto completion, which can be
used to inspect and modify the
namespace of a running script.

To invoke in a script do:

1
2
from rfoo.utils import rconsole
rconsole.spawn_server()

To attach from a shell do:

1
$ rconsole

Security note: The rconsole listener
started with spawn_server() will
accept any local connection and may
therefore be insecure to use in shared
hosting or similar environments!


使用吡嗪外壳。我不敢相信它能这么好地工作,但确实如此。"给它一个PID,得到一个外壳"。

1
2
3
4
5
6
7
8
9
10
11
12
13
$ 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。

根据这个答案改编。

注:只有在CONFIG_SECURITY_YAMA开启的情况下构建的内核/系统才需要关闭ptrace_scope属性的线路。小心在敏感环境中干扰ptrace_作用域,因为它可能会引入某些安全漏洞。详情请参阅此处。


为什么不简单地使用PDB模块?它允许您停止脚本,检查元素值,并逐行执行代码。由于它是基于Python解释器构建的,所以它还提供了经典解释器提供的特性。要使用它,只需在代码中放置这两行代码,您希望在其中停止并检查它:

1
2
import pdb
pdb.set_trace()


另一种不向python脚本添加内容的可能性描述如下:

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

不幸的是,这个解决方案还需要一些预先考虑,至少在某种程度上,您需要使用一个包含调试符号的Python版本。


使用pycharm,我在Ubuntu中无法连接到进程。解决这个问题的方法是禁用yama。有关更多信息,请参阅askubuntu

1
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope