2009-06-23 25 views
26

Sto provando a scaricare un elenco di tutti i thread attivi incluso lo stack corrente di ciascuno. Posso ottenere una lista di tutti i thread usando threading.enumerate(), ma non riesco a capire un modo per arrivare allo stack da lì.Stack stack di tutte le discussioni attive

Sfondo: Un'app Zope/Plone impazzisce di tanto in tanto, consuma il 100% della CPU e deve essere riavviata. Ho la sensazione che sia un loop che non termina correttamente, ma non posso riprodurlo nel test-environment per la verifica. Sono riuscito a registrare un gestore di segnale che può essere attivato dall'esterno, quindi posso attivare un codice non appena la situazione si ripresenta. Se potessi scaricare lo stacktrace per tutti i thread attivi, questo mi darebbe un'idea di cosa va storto. La cosa buco eseguito su Python 2.4 ...

Tutte le idee su come rintracciare situazioni come queste sono apprezzati :)

Cheers, Chriss

risposta

8

Quando si utilizza Zope, si desidera installare o Products.signalstackmr.freeze; questi sono stati progettati proprio per questo scopo!

Invia un segnale USR1 al server Zope e eseguirà immediatamente il dump dello stack per tutti i thread sulla console. Lo farà anche se tutti i thread di Zope sono bloccati.

Sotto il cofano questi pacchetti usano indirettamente threadframes; per Python versioni 2.5 e successive, quando non è utilizzando Zope, è possibile creare la stessa funzionalità utilizzando la funzione sys._current_frames() per accedere ai frame di stack per thread.

A partire da Zope 2.12.5 questa funzionalità è integrata in Zope stessa e non è più necessario installare ulteriori pacchetti.

+0

Grazie mille, questo è esattamente ciò di cui ho bisogno! – Chriss

+0

Al giorno d'oggi in Plone "non sono necessari pacchetti speciali" http: // StackOverflow.it/a/36633215/3046069 – Danimal

+0

@Danimal: grazie, aggiunto al post. 2.12.5 è stato rilasciato un anno dopo aver scritto questa risposta. –

0

C'è una ricetta applicabile ASPN. È possibile utilizzare threading.enumerate() per ottenere tutti i tid, quindi chiamare _async_raise() con qualche eccezione adatta per forzare una traccia dello stack.

35

Come indica il jitter in una risposta precedente, sys._current_frames() fornisce ciò che è necessario per v2.5 +. Per i più pigri il seguente frammento di codice ha funzionato per me e può aiutare 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

per Python 3.3 e successivamente, non v'è faulthandler.dump_traceback().

Il codice seguente produce un output simile, ma include il nome del thread e potrebbe essere migliorato per stampare ulteriori informazioni.

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

Solo per completezza, Products.LongRequestLogger è super utile per identificare i colli di bottiglia, e per fare in modo che discariche stacktraces a intervalli specifici.