2009-06-23 18 views
26

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

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

Cualquier ideas sobre cómo rastrear hasta situaciones como estas se aprecian :)

Saludos, Chriss

Respuesta

8

Al usar Zope, que desea instalar o Products.signalstackmr.freeze; ¡estos fueron diseñados solo para este propósito!

Envía una señal USR1 a tu servidor Zope e inmediatamente vaciará los rastreos de pila de todos los hilos en la consola. Hará esto incluso si todos los hilos Zope están bloqueados.

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

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

+0

Muchas gracias, esto es exactamente lo que necesito. – Chriss

+0

Hoy en día en Plone "no se necesitan paquetes especiales" http: // stackoverflow.com/a/36633215/3046069 – Danimal

+0

@Danimal: gracias, agregado a la publicación. 2.12.5 fue lanzado un año después de que escribí esta respuesta. –

0

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

35

Como la fluctuación de fase indica en una respuesta anterior sys._current_frames() le ofrece lo que necesita para v2.5 +. Para los perezosos el siguiente fragmento de código que funcionó para mí y puede ayudarle a:

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" 
13

para Python 3.3 y más adelante, hay faulthandler.dump_traceback().

El siguiente código produce resultados similares, pero incluye el nombre de la secuencia y podría mejorarse para imprimir más información.

for th in threading.enumerate(): 
    print(th) 
    traceback.print_stack(sys._current_frames()[th.ident]) 
    print() 
1

sólo por el bien integridad, Products.LongRequestLogger es muy útil para identificar los cuellos de botella, y para ello se vuelca stacktraces a intervalos específicos.

Cuestiones relacionadas