Volcar stacktraces de todos los hilos activos


Estoy tratando de volcar una lista de todos los subprocesos activos incluyendo la pila actual de cada uno. Puedo obtener una lista de todos los hilos usando threading.enumerate (), pero no puedo encontrar una manera de llegar a la pila desde allí.

Fondo: Una aplicación Zope/Plone se vuelve loca de vez en cuando, consume el 100% de la cpu y necesita reiniciarse. Tengo la sensación de que es un bucle que no termina correctamente, pero no puedo reproducirlo en el entorno de prueba para su verificación. Me las arreglé para registrar una señal manejador que se puede activar desde el exterior, por lo que puedo activar algún código tan pronto como la situación se produce de nuevo. Si pudiera volcar el stacktrace para todos los hilos activos, eso me daría una pista de lo que sale mal. El agujero se ejecuta en Python 2.4...

Cualquier idea sobre cómo rastrear situaciones como estas son apreciadas:)

Saludos, Chriss

Author: scarba05, 2009-06-23

6 answers

Cuando usando Zope, que desea instalar Products.signalstack o mr.congelar; estos fueron diseñados para este fin!

Envíe una señal USR1 a su servidor Zope e inmediatamente volcará los rastros de la pila para todos los subprocesos a la consola. Hará esto incluso si todos los hilos de Zope están bloqueados.

Bajo el capó estos paquetes utilizan indirectamente threadframes; para las versiones de Python 2.5 y superiores, cuando no usando Zope, puede compilar la misma funcionalidad usando el sys._current_frames() función para acceder a los marcos de pila por hilo.

A partir de Zope 2.12.5 esta funcionalidad está integrada en Zope, y ya no es necesario instalar paquetes adicionales.

 9
Author: Martijn Pieters,
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-05-04 14:58:49

Como jitter señala en una respuesta anterior sys._current_frames() le da lo que necesita para v2.5+. Para el perezoso, el siguiente fragmento de código funcionó para mí y puede ayudarlo:

print >> sys.stderr, "\n*** STACKTRACE - START ***\n"
code = []
for threadId, stack in sys._current_frames().items():
    code.append("\n# ThreadID: %s" % 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()))

for line in code:
    print >> sys.stderr, line
print >> sys.stderr, "\n*** STACKTRACE - END ***\n"
 36
Author: codeasone,
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-05-25 20:37:45

Para Python 3.3 y posteriores, hay faulthandler.dump_traceback().

El siguiente código produce una salida similar, pero incluye el nombre del hilo y podría ser mejorado para imprimir más información.

for th in threading.enumerate():
    print(th)
    traceback.print_stack(sys._current_frames()[th.ident])
    print()
 13
Author: nlevitt,
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-05-25 20:43:30

2.4. Lástima. Desde Python 2.5 hay sys._current_frames().

Pero podrías probar threadframe. Y si el makefile te da problemas podrías probar esto setup.py para threadframe

Muestra de salida cuando se usa threadframe

 7
Author: jitter,
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-05-25 20:37:54

Solo para completar, Productos.LongRequestLogger es súper útil para identificar cuellos de botella, y para hacerlo descarga stacktraces en intervalos específicos.

 1
Author: gforcada,
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-11-01 20:32:30

Hay una receta aplicable en ASPN. Puede usar threading.enumerate() para obtener todos los tid, luego simplemente llame a _async_raise() con alguna excepción adecuada para forzar un seguimiento de pila.

 0
Author: jwoolard,
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-06-23 14:26:48