使用 kill 信号进入 pdb

enter pdb with kill signal

在最近的一个项目中,我想在生产使用状态下调试我的程序。生产环境很复杂,发现问题就想调试程序

这就是我想要实现的:每当我想调试时,我都会向程序发送一个终止信号,希望 pdb 调试器会出现。它是这样的:

import pdb
import signal
import time

def handler(signal, frame):
  pdb.set_trace()

signal.signal(signal.SIGTERM, handler)
a=1
while True:
  a+=1
  time.sleep(1)

但是,由于我必须 运行 使用 nohup 的程序,所有输出都将重定向到 nohup.out,所以我无法与 pdb 交互。

有没有类似的东西可以做到这一点?

如果您 运行 来自终端的程序,您可以使用 tty 命令来记录 tty 设备,并传递给环境中的程序:

TTY=`tty` nohup ./myprog.py

然后在处理程序中再次打开 tty 并将 stdin 和 stdout 设置为文件:

import sys,os

def handler(signal, frame):
  tty = os.getenv('TTY')
  sys.stdin = sys.stdout = open(tty,"r+")
  pdb.set_trace()

如果您像评论中那样从当前 tty 中分离程序,那么您 可以尝试类似的东西,使用相同的 python 代码。这次 运行 你的程序有:

TTY=/tmp/link  nohup ./myprog.py &

并关闭终端。打开一个新终端并为这个新的 tty 创建缺少的 link:

ln -s `tty` /tmp/link

然后在一行中给出 kill 命令以向 python 进程发出信号,并且 然后立即做一个sleep。这样 shell 就不再与 pdb 用于来自 tty 的输入。例如,在一行中:

kill -term $pid; sleep 99999

然后您将让 pdb 连接到 /tmp/link,这是您的 tty。退出 pdb 时,键入 ctrl-c 会停止睡眠。

如果你需要在pdb中使用ctrl-c,而你正在使用bash, 将 sleep 99999 替换为 suspend。当你退出 pdb 时,使用终端的菜单发送信号 sigcont 返回挂起的进程 bash.

一种完全不同的方法,在我看来更简单、更优雅,是使用 rpyc。我已经在我的复杂系统中使用这种方法很长时间了,它使实时调试变得非常容易。

基本上,您需要做的是定义一个简单的 rpyc API 服务,其中包含 "exposed" 方法到 return 引用 ("netrefs") 到最你系统中有趣的对象。然后,在启动时在进程中启动 rpyc ThreadedServer

然后,只要您愿意,您就可以简单地创建一个 rpyc 客户端,并连接到进程,通过 API 检索对对象的引用,并检查它们(透明地,就好像那些 netrefs 是本地对象)。使用正确的 API 方法,您几乎可以在实时过程中访问 任何内容

此方法的其他优点是 (1) 此交互式会话甚至不必影响 运行 过程(当然,除非您调用会导致副作用等的方法), (2) 它不必是交互式的,即您可以轻松编写一个连接到进程并从中打印一些信息的脚本。