我只想查看流程的状态,是否可以将控制台附加到流程中,所以我可以在流程内部调用函数并查看一些全局变量。
最好在不受影响的情况下运行该进程(当然,性能可能会下降一点)
我只想查看流程的状态,是否可以将控制台附加到流程中,所以我可以在流程内部调用函数并查看一些全局变量。
最好在不受影响的情况下运行该进程(当然,性能可能会下降一点)
Answers:
如果您有权访问程序的源代码,则可以相对轻松地添加此功能。
参见配方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侦听器将接受任何本地连接,因此在共享主机或类似环境中使用时可能不安全!
rfoo._rfoo.EofError: 0
这将中断您的进程(除非您在线程中启动它),但是您可以使用该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+ C(SIGINT)操作,并且因此是一个方便的替代。
因此,上述的一种可移植但有点难看的版本是:
import code
import signal
signal.signal(
vars(signal).get("SIGBREAK") or vars(signal).get("SIGUSR2"),
lambda sig, frame: code.interact()
)
这种方法的优点:
这是我在生产环境中使用的代码,该代码将加载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
使用吡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,因为它可能会引入某些安全漏洞。有关详细信息,请参见此处。
此处描述了另一种可能的方法,无需在python脚本中添加内容:
https://wiki.python.org/moin/DebuggingWithGdb
不幸的是,此解决方案还需要一些周全的考虑,至少在某种程度上需要使用其中带有调试符号的python版本。