Mostrar el seguimiento de la pila desde una aplicación Python en ejecución


Tengo esta aplicación Python que se atasca de vez en cuando y no puedo averiguar dónde.

¿Hay alguna forma de indicar al intérprete Python que le muestre el código exacto que se está ejecutando?

¿Algún tipo de carrera sobre la marcha?

Preguntas relacionadas:

Author: Community, 2008-09-25

24 answers

Tengo un módulo que uso para situaciones como esta, donde un proceso se ejecutará durante mucho tiempo, pero a veces se atasca por razones desconocidas e irreproducibles. Es un poco hackeado, y solo funciona en unix (requiere señales):

import code, traceback, signal

def debug(sig, frame):
    """Interrupt running process, and provide a python prompt for
    interactive debugging."""
    d={'_frame':frame}         # Allow access to frame object.
    d.update(frame.f_globals)  # Unless shadowed by global
    d.update(frame.f_locals)

    i = code.InteractiveConsole(d)
    message  = "Signal received : entering python shell.\nTraceback:\n"
    message += ''.join(traceback.format_stack(frame))
    i.interact(message)

def listen():
    signal.signal(signal.SIGUSR1, debug)  # Register handler

Para usarlo, simplemente llame a la función listen () en algún momento cuando se inicie su programa (incluso podría pegarlo site.py para que todos los programas python lo usen), y dejar que se ejecute. En cualquier momento, envíe al proceso una señal SIGUSR1, usando kill, o in python:

    os.kill(pid, signal.SIGUSR1)

Esto hará que el programa se rompa a una consola python en el punto en el que se encuentra actualmente, mostrándole el seguimiento de la pila y permitiéndole manipular las variables. Use control-d (EOF) para continuar ejecutando (aunque tenga en cuenta que probablemente interrumpirá cualquier E/S, etc. en el punto que señale, por lo que no es completamente no intrusivo.

Tengo otro script que hace lo mismo, excepto que se comunica con el proceso en ejecución a través de una tubería (para permitir la depuración procesos en segundo plano, etc.). Es un poco grande para publicar aquí, pero lo he agregado como una receta de libro de cocina de python .

 294
Author: Brian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-10 16:05:19

La sugerencia de instalar un manejador de señal es buena, y la uso mucho. Por ejemplo, bzr instala por defecto un controlador SIGQUIT que invoca pdb.set_trace() para colocarlo inmediatamente en un prompt pdb. (Véase el bzrlib.fuente del módulo breakin para los detalles exactos.) Con pdb no solo puede obtener el seguimiento de pila actual,sino también inspeccionar variables, etc.

Sin embargo, a veces necesito depurar un proceso que no tuve la previsión de instalar el manejador de señales. En Linux, puede adjuntar gdb al proceso y obtener un seguimiento de pila de python con algunas macros gdb. Put http://svn.python.org/projects/python/trunk/Misc/gdbinit en ~/.gdbinit, entonces:

  • Adjuntar bgf: gdb -p PID
  • Obtenga el seguimiento de la pila de python: pystack

Desafortunadamente, no es totalmente confiable, pero funciona la mayor parte del tiempo.

Finalmente, adjuntar strace a menudo puede darte una buena idea de lo que está haciendo un proceso.

 137
Author: spiv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-01 14:02:31

Casi siempre estoy tratando con múltiples subprocesos y el subproceso principal generalmente no está haciendo mucho, por lo que lo más interesante es volcar todas las pilas (que es más como el volcado de Java). Aquí hay una implementación basada en este blog :

import threading, sys, traceback

def dumpstacks(signal, frame):
    id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
    code = []
    for threadId, stack in sys._current_frames().items():
        code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""), threadId))
        for filename, lineno, name, line in traceback.extract_stack(stack):
            code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
            if line:
                code.append("  %s" % (line.strip()))
    print "\n".join(code)

import signal
signal.signal(signal.SIGQUIT, dumpstacks)
 63
Author: haridsv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-07 06:29:09

Obtener un seguimiento de pila de un programa python no preparado, que se ejecuta en un python común sin depurar símbolosse puede hacer con pyrasite. Funcionó como un encanto para mí en Ubuntu Trusty:

$ sudo pip install pyrasite
$ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
$ sudo pyrasite 16262 dump_stacks.py # dumps stacks to stdout/stderr of the python program

(Hat tip a @Albert, cuya respuesta contenía un puntero a esto, entre otras herramientas.)

 40
Author: Nickolay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-26 18:22:20
>>> import traceback
>>> def x():
>>>    print traceback.extract_stack()

>>> x()
[('<stdin>', 1, '<module>', None), ('<stdin>', 2, 'x', None)]

También puede formatear muy bien el seguimiento de la pila, consulte los documentos .

Editar : Para simular el comportamiento de Java, como sugiere @Douglas Leeder, agregue esto:

import signal
import traceback

signal.signal(signal.SIGUSR1, lambda sig, stack: traceback.print_stack(stack))

Al código de inicio de su aplicación. Luego puede imprimir la pila enviando SIGUSR1 al proceso Python en ejecución.

 33
Author: Torsten Marek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-25 09:32:24

El rastreo el módulo tiene algunas funciones agradables, entre ellas: print_stack:

import traceback

traceback.print_stack()
 26
Author: gulgi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-04 00:29:50

Lo que realmente me ayudó aquí es el consejo de spiv (que votaría y comentaría si tuviera los puntos de reputación) para obtener un seguimiento de pila de un proceso de Python no preparado. Excepto que no funcionó hasta que me modificado el gdbinit script. Así que:

  • Descargar http://svn.python.org/projects/python/trunk/Misc/gdbinit y ponerlo en ~/.gdbinit

  • editar, cambiando PyEval_EvalFrame a PyEval_EvalFrameEx [editar: ya no es necesario; el el archivo vinculado ya tiene este cambio a partir de 2010-01-14]

  • Attach gdb: gdb -p PID

  • Obtener el seguimiento de la pila de python: pystack

 19
Author: Gunnlaugur Briem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:17

Puede probar el módulo faulthandler. Instálalo usando pip install faulthandler y añade:

import faulthandler, signal
faulthandler.register(signal.SIGUSR1)

Al comienzo de su programa. Luego envíe SIGUSR1 a su proceso (ej: kill -USR1 42) para mostrar el seguimiento de Python de todos los subprocesos a la salida estándar. Lea la documentación para obtener más opciones (por ejemplo: iniciar sesión en un archivo) y otras formas de mostrar el rastreo.

El módulo ahora es parte de Python 3.3. Para Python 2, véase http://faulthandler.readthedocs.org /

 19
Author: haypo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-03 14:54:03

python-dv yourscript.py

Eso hará que el intérprete se ejecute en modo de depuración y le dará un rastro de lo que está haciendo el intérprete.

Si desea depurar interactivamente el código, debe ejecutarlo de la siguiente manera:

python-m pdb yourscript.py

Que le dice al intérprete de python que ejecute su script con el módulo " pdb " que es el depurador de python, si lo ejecuta así el intérprete se ejecutará en modo interactivo, mucho me gusta GDB

 10
Author: Gustavo Rubio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-25 08:24:24

Añadiría esto como un comentario a la respuesta de haridsv , pero me falta la reputación para hacerlo:

Algunos de nosotros todavía estamos atascados en una versión de Python anterior a la 2.6 (requerida para Thread.ident), así que tengo el código trabajando en Python 2.5 (aunque sin el nombre del hilo que se muestra) como tal:

import traceback
import sys
def dumpstacks(signal, frame):
    code = []
    for threadId, stack in sys._current_frames().items():
            code.append("\n# Thread: %d" % (threadId))
        for filename, lineno, name, line in traceback.extract_stack(stack):
            code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
            if line:
                code.append("  %s" % (line.strip()))
    print "\n".join(code)

import signal
signal.signal(signal.SIGQUIT, dumpstacks)
 10
Author: Konstantin Naryshkin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:31:14

Echa un vistazo a la faulthandler módulo nuevo en Python 3.3. A faulthandler backport para usar en Python 2 está disponible en PyPI.

 8
Author: Matt Joiner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-14 20:09:37

En Solaris, puede usar pstack(1) No es necesario realizar cambios en el código python. eg.

# pstack 16000 | grep : | head
16000: /usr/bin/python2.6 /usr/lib/pkg.depotd --cfg svc:/application/pkg/serv
[ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:282 (_wait) ]
[ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:295 (wait) ]
[ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:242 (block) ]
[ /usr/lib/python2.6/vendor-packages/cherrypy/_init_.py:249 (quickstart) ]
[ /usr/lib/pkg.depotd:890 (<module>) ]
[ /usr/lib/python2.6/threading.py:256 (wait) ]
[ /usr/lib/python2.6/Queue.py:177 (get) ]
[ /usr/lib/python2.6/vendor-packages/pkg/server/depot.py:2142 (run) ]
[ /usr/lib/python2.6/threading.py:477 (run)
etc.
 6
Author: Tim Foster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-28 21:30:38

Si está en un sistema Linux, use la genialidad de gdb con extensiones de depuración de Python (puede estar en el paquete python-dbg o python-debuginfo). También ayuda con aplicaciones multiproceso, aplicaciones GUI y módulos C.

Ejecute su programa con:

$ gdb -ex r --args python <programname>.py [arguments]

Esto instruye a gdb a preparar python <programname>.py <arguments> y r un it.

Ahora cuando el programa se cuelga, cambie a la consola gdb, presione Ctr + C y ejecute:

(gdb) thread apply all py-list

Ver sesión de ejemplo y más información aquí y aquí.

 6
Author: anatoly techtonik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-24 08:08:48

Estaba buscando una solución para depurar mis subprocesos y la encontré aquí gracias a haridsv. Utilizo la versión ligeramente simplificada que emplea el traceback.print_stack ():

import sys, traceback, signal
import threading
import os

def dumpstacks(signal, frame):
  id2name = dict((th.ident, th.name) for th in threading.enumerate())
  for threadId, stack in sys._current_frames().items():
    print(id2name[threadId])
    traceback.print_stack(f=stack)

signal.signal(signal.SIGQUIT, dumpstacks)

os.killpg(os.getpgid(0), signal.SIGQUIT)

Para mis necesidades también filtro hilos por nombre.

 5
Author: Stefan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-03 12:46:04

Vale la pena mirar Pydb, "una versión expandida del depurador de Python basada libremente en el conjunto de comandos gdb". Incluye gestores de señal que pueden encargarse de iniciar el depurador cuando se envía una señal especificada.

Un proyecto de Verano de Código de 2006 analizó la adición de características de depuración remota a pydb en un módulo llamado mpdb.

 3
Author: rcoup,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-29 01:28:29

Hackeé una herramienta que se conecta a un proceso Python en ejecución e inyecta algún código para obtener una shell Python.

Ver aquí: https://github.com/albertz/pydbattach

 3
Author: Albert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-06 18:49:30

Pyringe es un depurador que puede interactuar con procesos python en ejecución, trazas de pila de impresión, variables, etc. sin ninguna configuración a priori.

Si bien he utilizado a menudo la solución de controlador de señal en el pasado, a menudo puede ser difícil reproducir el problema en ciertos entornos.

 2
Author: Dan Lecocq,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-01 09:40:07

No hay forma de engancharse a un proceso python en ejecución y obtener resultados razonables. Lo que hago si los procesos se bloquean es enganchar a Strace y tratar de averiguar qué está pasando exactamente.

Desafortunadamente, a menudo strace es el observador que "corrige" las condiciones de carrera para que la salida también sea inútil allí.

 1
Author: Armin Ronacher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-25 09:09:54

Puedes usar PuDB, un depurador de Python con una interfaz curses para hacer esto. Sólo añadir

from pudb import set_interrupt_handler; set_interrupt_handler()

A su código y use Ctrl-C cuando desee romper. Puede continuar con c y romper de nuevo varias veces si se lo pierde y quiere intentarlo de nuevo.

 1
Author: asmeurer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-27 00:54:57

No conozco nada similar a la respuesta de java a SIGQUIT, por lo que es posible que tenga que compilarlo en su aplicación. Tal vez usted podría hacer un servidor en otro hilo que puede obtener un stacktrace en respuesta a un mensaje de algún tipo?

 0
Author: Douglas Leeder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-25 09:06:39

Utilice el módulo inspect.

Importar inspeccionar ayuda(inspeccionar.pila) Ayuda en la pila de funciones en el módulo inspect:

Pila (contexto=1) Devuelve una lista de registros para la pila encima del frame de la persona que llama.

Lo encuentro muy útil.

 0
Author: Alison R.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-21 16:42:05

En Python 3, pdb instalará automáticamente un manejador de señal la primera vez que use c(ont(inue)) en el depurador. Presionando Control-C después te dejará de nuevo allí. En Python 2, aquí hay una línea que debería funcionar incluso en versiones relativamente antiguas (probadas en 2.7, pero revisé el código fuente de Python de nuevo a 2.4 y se veía bien):

import pdb, signal
signal.signal(signal.SIGINT, lambda sig, frame: pdb.Pdb().set_trace(frame))

Pdb vale la pena aprender si pasas cualquier cantidad de tiempo depurando Python. La interfaz es un poco obtusa, pero debería ser familiar para cualquiera la oms ha utilizado herramientas similares, como gdb.

 0
Author: jtatum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-14 02:16:25

En caso de que necesite hacer esto con uWSGI, tiene incorporado Python Tracebacker y solo es cuestión de habilitarlo en la configuración (el número se adjunta al nombre de cada trabajador):

py-tracebacker=/var/run/uwsgi/pytrace

Una vez hecho esto, puede imprimir la traza inversa simplemente conectándose al socket:

uwsgi --connect-and-read /var/run/uwsgi/pytrace1
 0
Author: Michal Čihař,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-28 06:15:05

Estoy en el campamento GDB con las extensiones de python. Seguir https://wiki.python.org/moin/DebuggingWithGdb , lo que significa

  1. dnf install gdb python-debuginfo o sudo apt-get install gdb python2.7-dbg
  2. gdb python <pid of running process>
  3. py-bt

También considere info threads y thread apply all py-bt.

 0
Author: user7610,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-18 12:31:10