Domanda

Ho questa applicazione Python che viene bloccato da un momento all'altro e non riesco a trovare dove.

C'è un modo per segnalare interprete Python per mostrare il codice esatto che è in esecuzione?

Un qualche tipo di on-the-fly stacktrace?

Le domande relative a:

È stato utile?

Soluzione

Ho un modulo che uso per situazioni come questa - in cui un processo in esecuzione per un lungo tempo, ma si blocca a volte sconosciuto e irriproducibile motivi.È un po ' sporca, e funziona solo su sistemi unix (richiede segnali):

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

Da usare, basta chiamare la funzione listen() a un certo punto, quando il programma si avvia (Si potrebbero anche mettere in site.py per avere tutti i programmi python lo uso), e farlo funzionare.In qualsiasi momento, inviare il processo di un segnale SIGUSR1, utilizzando uccidere, o in python:

    os.kill(pid, signal.SIGUSR1)

Questo farà sì che il programma di pausa per una console python presso il punto è attualmente in, che mostra la traccia dello stack, e che consente di manipolare le variabili.Utilizzare ctrl-d (EOF) per continuare l'esecuzione (anche se nota che è probabilmente interrupt I/O, ecc il punto è segnale, quindi non è completamente non invadente.

Ho un altro script che fa la stessa cosa, a meno che comunica con il processo in esecuzione attraverso un tubo (per consentire il debug sullo sfondo dei processi, ecc).È un po ' grande per postare qui, ma ho aggiunto come un python cookbook ricetta.

Altri suggerimenti

Il consiglio di installare un gestore di segnale è buono, e lo uso molto.Per esempio, bzr installa di default un SIGQUIT gestore che richiama pdb.set_trace() immediatamente cadere in un pdb prompt.(Vedere il bzrlib.breakin sorgente del modulo per i dettagli esatti.) Pdb è possibile non solo ottenere l'stack corrente, ma anche ispezionare le variabili, etc.

Tuttavia, a volte ho bisogno di eseguire il debug di un processo che non ho avuto l'accortezza di installare il gestore di segnale in.Su linux è possibile collegare gdb per il processo e ottenere un pitone stack trace alcuni gdb macro.Mettere http://svn.python.org/projects/python/trunk/Misc/gdbinit in ~/.gdbinit, e poi:

  • Collegare gdb: gdb -p PID
  • Ottenere python stack trace: pystack

Non è totalmente affidabile, purtroppo, ma non funziona la maggior parte del tempo.

Infine, il collegamento strace spesso può dare una buona idea di ciò che un processo sta facendo.

Io sono quasi sempre a che fare con più thread e thread principale, generalmente, non è fare molto, quindi, ciò che è più interessante è il dump di tutti i pile (che è più come il Java dump).Qui è una implementazione basata su questo 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)

Ottenere una traccia dello stack di un impreparati programma in python, in esecuzione in una base di python senza i simboli di debug può essere fatto con pyrasite.Funzionato come un fascino per me, in su 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, la cui risposta conteneva un puntatore a questo, tra gli altri strumenti.)

>>> import traceback
>>> def x():
>>>    print traceback.extract_stack()

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

Si può anche ben formato della traccia dello stack, vedere il docs.

Modifica:Per simulare Java comportamento, come suggerito da @Douglas Leeder, aggiungere questo:

import signal
import traceback

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

per il codice di avvio dell'applicazione.Quindi è possibile stampare la pila per l'invio di SIGUSR1 per l'esecuzione di Python processo.

Il traceback il modulo ha alcune funzioni, tra cui:print_stack:

import traceback

traceback.print_stack()

Si può provare il faulthandler modulo.È possibile installarlo utilizzando pip install faulthandler e aggiungere:

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

all'inizio del tuo programma.Quindi inviare SIGUSR1 al vostro processo (es: kill -USR1 42) per visualizzare il Python traceback di tutti i thread sullo standard output. Leggere la documentazione per ulteriori opzioni (es:log in un file) e altri modi per visualizzare il traceback.

Il modulo è ora parte di Python 3.3.Per Python 2, vedere http://faulthandler.readthedocs.org/

Ciò che veramente mi ha aiutato qui è spiv punta (che vorrei votare e commentare se avessi i punti di reputazione) per ottenere una traccia dello stack di un impreparati Python processo.Tranne che non lavoro fino a quando ho modificato il gdbinit script.Così:

  • download http://svn.python.org/projects/python/trunk/Misc/gdbinit e metterlo in ~/.gdbinit

  • modifica, modifica PyEval_EvalFrame per PyEval_EvalFrameEx [edit:non è più necessario;il file collegato già questo cambiamento di 2010-01-14]

  • Collegare gdb: gdb -p PID

  • Ottenere python stack trace: pystack

Vorrei aggiungere questo come commento haridsv risposta, ma mi manca la reputazione di fare così:

Alcuni di noi sono ancora bloccati su una versione di Python di età superiore a 2.6 (necessario per il Thread.ident), così ho preso il funzionamento di codice in Python 2.5 (anche se senza il nome del thread visualizzato come tale:

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)

python -dv yourscript.py

Che farà interprete per l'esecuzione in modalità di debug e per darvi una traccia di ciò che l'interprete sta facendo.

Se si desidera in modo interattivo il debug del codice dovrebbe funzionare così:

python -m pdb yourscript.py

Che racconta l'interprete python per eseguire il tuo script con il modulo "pdb" che è il python debugger, se si esegue come l'interprete, che verrà eseguito in modalità interattiva, come GDB

Date un'occhiata al faulthandler modulo, di nuovo in Python 3.3.Un faulthandler backport per l'uso in Python 2 è disponibile su PyPI.

Su Solaris, è possibile utilizzare pstack(1) modifiche al codice python sono necessari.es.

# 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.

Se siete su un sistema Linux, utilizzare la suggestione di gdb con Python debug delle estensioni (può essere in python-dbg o python-debuginfo pacchetto).Aiuta anche con le applicazioni multithread, applicazioni GUI e C moduli.

Eseguire il programma con:

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

In questo modo gdb per preparare python <programname>.py <arguments> e ronu di esso.

Ora, quando si programma si blocca, passare in gdb console, premere Ctr+C ed eseguire:

(gdb) thread apply all py-list

Vedere esempio di sessione per info qui e qui.

Ero alla ricerca di un po ' di una soluzione per eseguire il debug del mio thread e l'ho trovato qui grazie a haridsv.Io uso leggermente versione semplificata che impiega il 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)

Per le mie esigenze, ho anche il filtro thread per nome.

Vale la pena di guardare Pydb, "una versione ampliata del Python debugger vagamente basato sul gdb comando set".Esso comprende segnale manager che può prendere cura di avviare il debugger quando un determinato segnale viene inviato.

Un Estate 2006 del progetto di Codice guardò l'aggiunta di remote-funzionalità di debug per pydb in un modulo chiamato mpdb.

Ho messo insieme qualche strumento che si attacca in esecuzione di Python processo e inietta un po ' di codice per ottenere una shell di Python.

Vedi qui: https://github.com/albertz/pydbattach

pyringe è un debugger in grado di interagire con l'esecuzione di python processi di stampa stack trace, variabili, etc.senza qualsiasi a priori l'installazione.

Mentre ho spesso utilizzato il gestore di segnale soluzione in passato, può ancora spesso essere difficile riprodurre il problema in certi ambienti.

Non c'è modo di collegare in esecuzione di un pitone di processo e di ottenere risultati ragionevoli.Cosa posso fare se i processi di lock-up è di aggancio strace e cercando di capire esattamente cosa sta succedendo.

Purtroppo, spesso, strace è l'osservatore che "correzioni" condizioni di gara che l'uscita è inutile anche lì.

È possibile utilizzare PuDB, un Pitone debugger con un maledizioni interfaccia per fare questo.Basta aggiungere

from pudb import set_interrupt_handler; set_interrupt_handler()

per il codice e utilizzare Ctrl-C quando si vuole rompere.Si può continuare con c e rompere di nuovo più volte se ne sente la mancanza e la voglia di riprovare.

Come eseguire il debug di qualsiasi funzione in console:

Creare la funzione dove si utilizzare ppb.set_trace(), poi la funzione che si desidera eseguire il debug.

>>> import pdb
>>> import my_function

>>> def f():
...     pdb.set_trace()
...     my_function()
... 

Quindi, chiamare una funzione creata:

>>> f()
> <stdin>(3)f()
(Pdb) s
--Call--
> <stdin>(1)my_function()
(Pdb) 

Felice di debug :)

Non so nulla di simile a java risposta SIGQUIT, è quindi possibile costruire nell'applicazione.Forse si potrebbe fare un server in un altro thread che possono ottenere un stacktrace in risposta a un messaggio di qualche tipo?

utilizzare il modulo inspect.

importazione di ispezionare aiuto(ispezionare.stack) Guida in funzione di stack nel modulo di ispezione:

stack(context=1) Restituire un elenco di record per lo stack di sopra del chiamante telaio.

Io la trovo molto utile.

In Python 3, pdb installa automaticamente un gestore di segnale la prima volta che si utilizza c(ont(inue) il debugger.La pressione di ctrl-C e poi ti lasciano a destra indietro in là.In Python 2, ecco una one-liner, che dovrebbe funzionare anche in tempi relativamente vecchie versioni (testato in 2.7 ma ho controllato il sorgente Python torna a 2.4 e si è guardato bene):

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

pdb è la pena di imparare se spendere qualsiasi quantità di tempo di debug Python.L'interfaccia è un po ' ottuso, ma dovrebbe essere familiare a chiunque abbia utilizzato strumenti simili, come gdb.

Nel caso In cui avete bisogno di fare questo con uWSGI, ha Python Tracebacker built-in e è solo una questione di abilitazione nella configurazione (numero è collegato il nome per ogni lavoratore):

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

Una volta fatto questo, è possibile stampare backtrace semplicemente collegando alla presa:

uwsgi --connect-and-read /var/run/uwsgi/pytrace1

Io sono in GDB campo con il python estensioni.Seguire https://wiki.python.org/moin/DebuggingWithGdb, che 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

Anche in considerazione info threads e thread apply all py-bt.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top