pudb
pudb copied to clipboard
Suggestion: combine tmux with pudb
Debug remote process is not the easiest task today. Usually you have access to the running machine/container but since its impossible to attach the debugger to running process you need to use telnet connection / kill the process and rerun it in your terminal.
from my experience using the telnet debugger is much less smooth then using the debugger directly.
The new addition of opening the debugger in different terminal works much more better. to make it more easy to use i thought of mixing tmux with pudb.
the user will do something like:
from pudb.tmux import set_trace; set_trace("my_session")
it will open new session with the name "my_session" (or "my_sessionX" if "my_session" exist) get its tty and set the pudb to write to this terminal
i'd like to get your comments about it. how do you manage to debug remote processes? will it be valuable for you? is it something worth putting in this repository? new package?
See https://github.com/inducer/pudb/pull/315. The actual code to call tmux was initially in that PR but it was later removed (I wasn't clear why myself).
The prior effort was essentially a shell script mostly unrelated to pudb that would start tmux and print the tty name, which I felt was sufficiently unrelated to not merit inclusion. I would be happy to consider a more automated approach.
I think having it "just work" if it's enabled in the settings could be useful. Even for local debugging when a separate tty PuDB could assumedly avoid switching out of cooked mode and just leave the UI intact when continuing (https://github.com/inducer/pudb/issues/48), since stdout/stderr would just go to the controlling terminal.
Just to put my two cents here: I've been playing around with the PUDB_TTY behavior and I've found this to be the simplest PoC to put it to work:
pudb-client (executed in a new shell, in tmux, in screen...)
#!/bin/sh
trap '' INT
echo "Waiting for server..."
exec perl -MPOSIX -e pause
pudb-server:
#!/bin/sh
echo "Waiting for client..."
tty=
until [ -n "${tty}" ]; do
sleep 1
pid="$(pgrep -xfn 'perl -MPOSIX -e pause')"
[ -n "${pid}" ] && tty="$(ps -o tty= -p "${pid}")"
done
export PUDB_TTY="/dev/${tty}"
exec "${PYINTERP:-python}" -m pudb.run "${@}"
(I don't really like the idea of getting the TTY by constantly polling, but cannot think of a better —portable— way to achieve this. Maybe with sockets and/or FS watchers + temporary files?)
The client could be rewritten in python, instead of relying on the one-liner perl script, to provide:
- Better SIGINT handling. Accidentally closing the debug session with
^Cis a really frustrating experience, but so is not being able to easily finish the client when PuDB quits. - Its own entrypoint in PuDB.
I've being testing the different approaches with strace, and these two seems to block in the most efficient way:
# Requires a CPython-compatible Python implementation
python -c 'import ctypes; ctypes.CDLL(None).pause()'
# Known to work on Unix but not on Windows
python -c 'import select; select.select([], [], [])'
Hope this helps!
Thanks for investigating and putting this together. The level of automation achieved here is more to my liking, though the grepping through the process list still seems fishy. If we can, we may want to introduce a token into the perl line to clearly identify that the terminal is waiting for a pudb to connect. Also, what happens if you want to have two of those sessions at a time?
Hi @inducer, I'm glad you find interesting this approach :)
I've been thinking about how to improve this process, and I've uploaded a more refined PoC. It uses temporary Unix sockets, so multiple PuDB instances can coexist attached to different clients (pointing to distinct sockets).
Additionally, now the client knows the server PID and can propagate the Ctrl+C signal to start debugging.
Hope you find this useful.
Workflow-wise, I think this looks promising. Thanks for putting it together. If you could turn this into a pull request (e.g. as python -m pudb.server and -m pudb.client?), we could discuss details. Some things to figure out:
- security implications
- naming of the socket (include user name? interpreter version?)
and perhaps a few things I'm missing.