python: ¿es posible adjuntar una consola a un proceso en ejecución?

81

Solo quiero ver el estado del proceso, si es posible adjuntar una consola al proceso, para poder invocar funciones dentro del proceso y ver algunas de las variables globales.

Es mejor que el proceso se esté ejecutando sin verse afectado (por supuesto, el rendimiento puede disminuir un poco)

Bin Chen
fuente
7
así que básicamente, ¿un depurador?
st0le
algo así como el intérprete de línea de comandos python.exe
Bin Chen
versión pdb: stackoverflow.com/questions/25308847/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respuestas:

42

Si tiene acceso al código fuente del programa, puede agregar esta funcionalidad con relativa facilidad.

Consulte la receta 576515 :Debugging a running python process by interrupting and providing an interactive prompt (Python)

Citar:

Esto proporciona código para permitir que cualquier programa de Python que lo use sea interrumpido en el punto actual y se comunique con él a través de una consola interactiva de Python normal. Esto permite investigar los locales, globales y el estado del programa asociado, así como llamar a funciones y clases arbitrarias.

Para usarlo, un proceso debe importar el módulo y llamar a listen () en cualquier momento durante el inicio. Para interrumpir este proceso, el script se puede ejecutar directamente, dando el Id. De proceso del proceso a depurar como parámetro.


Rconsole proporciona otra implementación de aproximadamente el mismo concepto . De la documentación:

rconsole es una consola remota de Python con finalización automática, que se puede usar para inspeccionar y modificar el espacio de nombres de un script en ejecución.

Para invocar en un script, haga lo siguiente:

from rfoo.utils import rconsole
rconsole.spawn_server()

Para adjuntar desde un caparazón, haga lo siguiente:

$ rconsole

Nota de seguridad: El oyente de rconsole iniciado con spawn_server () aceptará cualquier conexión local y, por lo tanto, puede que no sea seguro usarlo en un alojamiento compartido o entornos similares.

fmark
fuente
2
Esa es realmente una receta muy buena. El uso de tuberías y archivos para la entrada y la salida es realmente inteligente y creo que cualquier proyecto decente se beneficiaría de esta funcionalidad.
erkmene
2
Sin embargo, es muy inseguro, así que
úselo
Probé la receta y se rompió la instalación de Python. El objeto 'módulo' no tiene atributo 'getmro'
Victor 'Chris' Cabral
Compilé la extensión cython, después de agregar el código auxiliar al código e inicié el servidor rpc, pero rconsole siempre se romperá vergonzosamente en cualquier operación. rfoo._rfoo.EofError: 0
Sajuuk
60

Esto interrumpirá su proceso (a menos que lo inicie en un hilo), pero puede usar el codemódulo para iniciar una consola Python:

import code
code.interact()

Esto se bloqueará hasta que el usuario salga de la consola interactiva ejecutando exit().

El codemódulo está disponible al menos en Python v2.6, probablemente en otros.

Tiendo a usar este enfoque en combinación con señales para mi trabajo con Linux (para Windows, ver más abajo). Pongo esto en la parte superior de mis scripts de Python:

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

Y luego desencadenarlo desde un shell con kill -SIGUSR2 <PID>, donde <PID>está el ID del proceso. Luego, el proceso detiene lo que esté haciendo y presenta una consola:

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

Generalmente, desde allí cargaré el componente del lado del servidor de un depurador remoto como el excelente WinPDB .

Windows no es un sistema operativo compatible con POSIX , por lo que no proporciona las mismas señales que Linux. Sin embargo, Python v2.2 y superior exponen una señal específica de WindowsSIGBREAK (activada presionando CTRL+ Pause/Break). Esto no interfiere con el funcionamiento normal CTRL+ C( SIGINT), por lo que es una alternativa útil.

Por lo tanto, una versión portátil, pero un poco fea, de lo anterior es:

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

Ventajas de este enfoque:

  • Sin módulos externos (todas las cosas estándar de Python)
  • Apenas consume recursos hasta que se activa (importación 2x)

Aquí está el código que utilizo en mi entorno de producción que cargará el lado del servidor de WinPDB (si está disponible) y volverá a abrir una consola 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
RobM
fuente
¿Puede dar más detalles sobre cómo carga el componente del lado del servidor de WinPDB una vez que tiene una consola Python?
Christian Long
1
Agregué mi código de producción a la respuesta, pero esencialmente solo necesita ingresar lo siguiente en una consola: '' import rpdb2; rpdb2.start_embedded_debugger ("foobar", True, True) '' y luego inicie la GUI de WinPDB con la contraseña "foobar" cuando se le solicite
RobM
26

Utilice pyrasite-shell . No puedo creer que funcione tan bien, pero lo hace. " Dale un pid, consigue un caparazón ".

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

Esto lanza el shell de Python con acceso a las variables globals () y locals () de ese proceso de Python en ejecución, y otras cosas maravillosas.

Solo probé esto personalmente en Ubuntu, pero parece ser compatible con OSX también.

Adaptado de esta respuesta .

Nota: La línea que desactiva la ptrace_scopepropiedad solo es necesaria para los kernels / sistemas que se han construido con CONFIG_SECURITY_YAMAon. Tenga cuidado al jugar con ptrace_scope en entornos sensibles porque podría introducir ciertas vulnerabilidades de seguridad. Consulte aquí para obtener más detalles.

python1981
fuente
@Dirk Creo que ptrace_scope es esencial para permitir que un proceso rastree / interactúe con otro proceso no relacionado.
python1981
Obviamente, eso es solo en sistemas que tienen YAMA. Propuesta editar y eliminar mi comentario original. (Este también irá dentro de algún tiempo.)
Dirk
Consulte aquí para usar en Docker: stackoverflow.com/questions/37072468/…
Michael Steinberg
5

¿Por qué no utilizar simplemente el módulo pdb ? Le permite detener un script, inspeccionar los valores de los elementos y ejecutar el código línea por línea. Y dado que se basa en el intérprete de Python, también proporciona las funciones proporcionadas por el intérprete clásico. Para usarlo, simplemente coloque estas 2 líneas en su código, donde desea detenerlo e inspeccionarlo:

import pdb
pdb.set_trace()
mdeous
fuente
3
¿Sabes cómo ejecutarlo para un hilo dado de threading.enumerate ()?
Yucer
4

Aquí se describe otra posibilidad, sin agregar cosas a los scripts de Python:

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

Desafortunadamente, esta solución también requiere algo de previsión, al menos en la medida en que necesite usar una versión de Python con símbolos de depuración.

Joshua Richardson
fuente
Para la mayoría de las distribuciones de Linux, Python está construido con símbolos de depuración, pero los símbolos de depuración residen en un paquete diferente. El paquete de símbolos de depuración se puede instalar después de que su script de Python ya haya comenzado.
W.Mann
1

Usando PyCharm, estaba obteniendo un error al conectarme al proceso en Ubuntu. La solución para esto es desactivar YAMA. Para obtener más información, consulte askubuntu

echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
shao.lo
fuente