远程热插拔 Python 调试器

Remote hotplug Python debugger

如何使用 Python IDE 集成设置热插拔远程调试器?例如使用 PyCharm。可热插拔的意思是:可以在运行中连接和断开开发服务器。

我在云中有开发服务器(django、nginx、uwsgi、postgres、debian),并使用 PyCharm 作为主要 IDE(但如果你有任何其他解决方案 IDE,请提供)。

有时,我需要在没有 stopping/restarting 开发服务器的情况下连接和调试脚本。使用 PyCharm 的调试器 (pydevd),如果调试器服务器 (Connection refused) 不工作,开发服务器将无法启动,如果我在开发服务器处于 运行 时停止远程调试器,它会崩溃,例如

An existing connection was forcibly closed by the remote host

我找到了 pdg/epdg,但它们没有与 PyCharm 集成。 PyCharm 也有一个很好的特性:"Attach to process",但它只适用于本地进程。

可能可行的基本方法是为要调试的程序设置一个信号处理程序以加载到调试器中。然后向进程发送信号进行调试(通过 kill 命令),然后您就可以远程连接了。

以下是您如何通过 python trepan debuggers

import signal

def signal_handler(num, f):
    from trepan.interfaces import server as Mserver
    from trepan.api import debug
    connection_opts={'IO': 'TCP', 'PORT': 1955}
    intf = Mserver.ServerInterface(connection_opts=connection_opts)
    dbg_opts = {'interface': intf}
    print('Starting TCP server listening on port 1955.')
    debug(dbg_opts=dbg_opts)
    return

signal.signal(signal.SIGUSR1, signal_handler)
# Go about your business...

import time
import os
print(os.getpid())
for i in range(10000):
    time.sleep(0.2)

现在 运行 即:

$ python /tmp/foo.py
8530

从上面的输出中,我们列出了我们要调试的 Python 进程的 pid。

现在在 shell 中,我们发送一个信号告诉进程进入在信号处理程序中设置的调试器。你将不得不调整 进程号。

$ kill -USR1 8530   # Adjust the pid to what you see above

在 shell 我们 运行 /tmp/foo.py 你现在应该看到 新输出:

$ python /tmp/foo.py
8530
Starting TCP server listening on port 1955. # This is new

回到我们发出 kill -USR1 的 shell,我们现在附加现在停止在调试器中的进程:

$ trepan2 --client --port 1955
Connected.
(/tmp/foo.py:11 @101): signal_handler
-- 11     return
(trepan2*) list
  6         connection_opts={'IO': 'TCP', 'PORT': 1955}
  7         intf = Mserver.ServerInterface(connection_opts=connection_opts)
  8         dbg_opts = {'interface': intf}
  9         print('Starting TCP server listening on port 1955.')
 10         debug(dbg_opts=dbg_opts)
 11  ->     return
 12
 13     signal.signal(signal.SIGUSR1, signal_handler)
 14     # Go about your business...
 (trepan2*) backtrace
 ->   0 signal_handler(num=10, f=<frame object at 0x7f9036796050>)
      called from file '/tmp/foo.py' at line 11
 ##   1 <module> file '/tmp/foo.py' at line 20