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

Python

Python Problem Overview


I just want to see the state of the process, is it possible to attach a console into the process, so I can invoke functions inside the process and see some of the global variables.

It's better the process is running without being affected(of course performance can down a little bit)

Python Solutions


Solution 1 - Python

This will interrupt your process (unless you start it in a thread), but you can use the code module to start a Python console:

import code
code.interact()

This will block until the user exits the interactive console by executing exit().

The code module is available in at least Python v2.6, probably others.

I tend to use this approach in combination with signals for my Linux work (for Windows, see below). I slap this at the top of my Python scripts:

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

And then trigger it from a shell with kill -SIGUSR2 <PID>, where <PID> is the process ID. The process then stops whatever it is doing and presents a console:

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)
>>>

Generally from there I'll load the server-side component of a remote debugger like the excellent WinPDB.

Windows is not a POSIX-compliant OS, and so does not provide the same signals as Linux. However, Python v2.2 and above expose a Windows-specific signal SIGBREAK (triggered by pressing CTRL+Pause/Break). This does not interfere with normal CTRL+C (SIGINT) operation, and so is a handy alternative.

Therefore a portable, but slightly ugly, version of the above is:

import code
import signal
signal.signal(
        vars(signal).get("SIGBREAK") or vars(signal).get("SIGUSR2"),
        lambda sig, frame: code.interact()
        )

Advantages of this approach:

  • No external modules (all standard Python stuff)
  • Barely consumes any resources until triggered (2x import)

Here's the code I use in my production environment which will load the server-side of WinPDB (if available) and fall back to opening a Python console.

# 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

Solution 2 - Python

If you have access to the program's source-code, you can add this functionality relatively easily.

See Recipe 576515: Debugging a running python process by interrupting and providing an interactive prompt (Python)

To quote: > 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.


Another implementation of roughly the same concept is provided by rconsole. From the documentation:

> 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:

from rfoo.utils import rconsole
rconsole.spawn_server()

> To attach from a shell do:

$ 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!

Solution 3 - Python

Use pyrasite-shell. I can't believe it works so well, but it does. "Give it a pid, get a shell".

$ 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'

This launches the python shell with access to the globals() and locals() variables of that running python process, and other wonderful things.

Only tested this personally on Ubuntu but seems to cater for OSX too.

Adapted from this answer.

Note: The line switching off the ptrace_scope property is only necessary for kernels/systems that have been built with CONFIG_SECURITY_YAMA on. Take care messing with ptrace_scope in sensitive environments because it could introduce certain security vulnerabilities. See here for details.

Solution 4 - Python

Why not simply using the pdb module? It allows you to stop a script, inspect elements values, and execute the code line by line. And since it is built upon the Python interpreter, it also provides the features provided by the classic interpreter. To use it, just put these 2 lines in your code, where you wish to stop and inspect it:

import pdb
pdb.set_trace()

Solution 5 - Python

Another possibility, without adding stuff to the python scripts, is described here:

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

Unfortunately, this solution also requires some forethought, at least to the extent that you need to be using a version of python with debugging symbols in it.

Solution 6 - Python

pdb_attach worked well for us for attaching the Python debugger to a long-running process.

The author describes it as follows: This package was made in response to frustration over debugging long running processes. Wouldn't it be nice to just attach pdb to a running python program and see what's going on? Well that's exactly what pdb-attach does.

Set it up as follows in your main module:

import pdb_attach
pdb_attach.listen(50000)  # Listen on port 50000.

When the program is running, attach to it by calling pdb_attach from the command line with the PID of the program and the port passed to pdb_attach.listen():

$ python -m pdb_attach <PID> 50000
(Pdb)  # Interact with pdb as you normally would

Solution 7 - Python

Using PyCharm, I was getting a failure to connect to process in Ubuntu. The fix for this is to disable YAMA. For more info see askubuntu

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

Solution 8 - Python

You can use my project madbg. It is a python debugger that allows you to attach to a running python program and debug it in your current terminal. It is similar to pyrasite and pyringe, but supports python3, doesn't require gdb, and uses IPython for the debugger (which means pdb with colors and autocomplete).

For example, to see where your script is stuck, you could run:

madbg attach <pid>

After that you will have a pdb shell, in which you can invoke functions and inspect variables.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBin ChenView Question on Stackoverflow
Solution 1 - PythonRobMView Answer on Stackoverflow
Solution 2 - PythonfmarkView Answer on Stackoverflow
Solution 3 - PythonpythonjsgeoView Answer on Stackoverflow
Solution 4 - PythonmdeousView Answer on Stackoverflow
Solution 5 - PythonJoshua RichardsonView Answer on Stackoverflow
Solution 6 - PythonmrtsView Answer on Stackoverflow
Solution 7 - Pythonshao.loView Answer on Stackoverflow
Solution 8 - PythonkmaorkView Answer on Stackoverflow