2010-09-13 16 views
438

Sto scrivendo un programma che analizza 10 siti Web, individua i file di dati, salva i file e li analizza per creare dati che possono essere facilmente utilizzati nella libreria NumPy. Ci sono tonnellate di errori che questo file incontra attraverso collegamenti errati, XML mal formato, voci mancanti e altre cose che devo ancora classificare. Inizialmente ho fatto questo programma per gestire gli errori in questo modo:Come stampare il traceback completo senza arrestare il programma?

try: 
    do_stuff() 
except: 
    pass 

Ma ora voglio registrare gli errori:

try: 
    do_stuff() 
except Exception, err: 
    print Exception, err 

Nota che questa è la stampa ad un file di log per la revisione successiva. Questo di solito stampa dati molto inutili. Quello che voglio è stampare esattamente le stesse linee stampate quando l'errore si innesca senza il tentativo, eccetto intercettare l'eccezione, ma non voglio che fermi il mio programma poiché è annidato in una serie di cicli for che vorrei vedere a completamento.

risposta

258

Alcune altre risposte hanno già indicato il modulo traceback.

Si prega di notare che con print_exc, in alcuni casi d'angolo, non otterrete ciò che vi aspettereste. In Python 2.x:

import traceback 

try: 
    raise TypeError("Oups!") 
except Exception, err: 
    try: 
     raise TypeError("Again !?!") 
    except: 
     pass 

    traceback.print_exc() 

...visualizzerà il traceback dell'eccezione ultima:

Traceback (most recent call last): 
    File "e.py", line 7, in <module> 
    raise TypeError("Again !?!") 
TypeError: Again !?! 

Se si ha realmente bisogno per accedere all'originale traceback una soluzione è quella di memorizzare nella cache le informazioni di eccezione come restituito da exc_info in una variabile locale e visualizzarlo utilizzando print_exception:

import traceback 
import sys 

try: 
    raise TypeError("Oups!") 
except Exception, err: 
    try: 
     exc_info = sys.exc_info() 

     # do you usefull stuff here 
     # (potentially raising an exception) 
     try: 
      raise TypeError("Again !?!") 
     except: 
      pass 
     # end of useful stuff 


    finally: 
     # Display the *original* exception 
     traceback.print_exception(*exc_info) 
     del exc_info 

Produrre:

Traceback (most recent call last): 
    File "t.py", line 6, in <module> 
    raise TypeError("Oups!") 
TypeError: Oups! 

Poche insidie ​​con questo però:

  • Dal doc di sys_info:

    Assigning the traceback return value to a local variable in a function that is handling an exception will cause a circular reference. This will prevent anything referenced by a local variable in the same function or by the traceback from being garbage collected. [...] If you do need the traceback, make sure to delete it after use (best done with a try ... finally statement)

  • ma, dallo stesso documento:

    Beginning with Python 2.2, such cycles are automatically reclaimed when garbage collection is enabled and they become unreachable, but it remains more efficient to avoid creating cycles.


D'altra parte, consentendo di accedere al traceback associati con un'eccezione, Python 3 produce un risultato meno sorprendente:

import traceback 

try: 
    raise TypeError("Oups!") 
except Exception as err: 
    try: 
     raise TypeError("Again !?!") 
    except: 
     pass 

    traceback.print_tb(err.__traceback__) 

... visualizzerà:

File "e3.py", line 4, in <module> 
    raise TypeError("Oups!") 
4

Avrete bisogno di mettere il try/tranne all'interno del più innerloop in cui può verificarsi l'errore, cioè

for i in something: 
    for j in somethingelse: 
     for k in whatever: 
      try: 
       something_complex(i, j, k) 
      except Exception, e: 
       print e 
     try: 
      something_less_complex(i, j) 
     except Exception, e: 
      print e 

... e così via

In altre parole, si avrà bisogno di avvolgere affermazioni che potrebbero fallire nel tentativo/eccetto il più specifico possibile, nel modo più interiore possibile.

2

Si desidera il modulo traceback. Ti permetterà di stampare dump dello stack come fa normalmente Python. In particolare, la funzione print_last stamperà l'ultima eccezione e una traccia dello stack.

479

traceback.format_exc() o sys.exc_info() produrrà più informazioni se è quello che vuoi.

import traceback 
import sys 

try: 
    do_stuff() 
except Exception: 
    print(traceback.format_exc()) 
    # or 
    print(sys.exc_info()[0]) 
+9

Perché non usare semplicemente 'traceback.print_exc()'? –

+13

Voglio la stringa, mi fa piacere volting mi ha mostrato il metodo ('format_exc()') per ottenere la stringa :) –

+2

@FrozenFlame perché potresti voler loggare te stesso prima di lanciarlo di nuovo – casraf

130

Se si esegue il debug e si desidera semplicemente visualizzare la traccia dello stack corrente, è sufficiente chiamare:

traceback.print_stack()

Non è necessario sollevare manualmente un'eccezione solo per riprenderla.

+4

Il modulo traceback fa esattamente quello - sollevare e prendere un'eccezione – ppperry

49

How to print the full traceback without halting the program?

Quando non si vuole fermare il programma su un errore, è necessario gestire tale errore con un try/tranne:

try: 
    do_something_that_might_error() 
except Exception as error: 
    handle_the_error(error) 

Per estrarre il pieno traceback, useremo il modulo traceback dalla libreria standard:

import traceback 

E per creare uno stacktrace decentemente complicato per dimostrare che si ottiene il pieno stacktrace:

def raise_error(): 
    raise RuntimeError('something bad happened!') 

def do_something_that_might_error(): 
    raise_error() 

stampa

Per stampa traceback completo, utilizzare il metodo traceback.print_exc:

try: 
    do_something_that_might_error() 
except Exception as error: 
    traceback.print_exc() 

che stampa:

Traceback (most recent call last): 
    File "<stdin>", line 2, in <module> 
    File "<stdin>", line 2, in do_something_that_might_error 
    File "<stdin>", line 2, in raise_error 
RuntimeError: something bad happened! 

Meglio di stampa, la registrazione:

Tuttavia, una procedura consigliata è quella di impostare il registratore per il modulo. Si conosce il nome del modulo ed essere in grado di modificare i livelli di (tra gli altri attributi, come ad esempio i gestori)

import logging 
logging.basicConfig(level=logging.DEBUG) 
logger = logging.getLogger(__name__) 

In questo caso, si desidera la funzione logger.exception invece:

try: 
    do_something_that_might_error() 
except Exception as error: 
    logger.exception(error) 

che registra:

ERROR:__main__:something bad happened! 
Traceback (most recent call last): 
    File "<stdin>", line 2, in <module> 
    File "<stdin>", line 2, in do_something_that_might_error 
    File "<stdin>", line 2, in raise_error 
RuntimeError: something bad happened! 

O forse si desidera solo la stringa, in questo caso, si desidera che la funzione traceback.format_exc invece:

try: 
    do_something_that_might_error() 
except Exception as error: 
    logger.debug(traceback.format_exc()) 

che registra:

DEBUG:__main__:Traceback (most recent call last): 
    File "<stdin>", line 2, in <module> 
    File "<stdin>", line 2, in do_something_that_might_error 
    File "<stdin>", line 2, in raise_error 
RuntimeError: something bad happened! 

Conclusione

E per tutte e tre le opzioni, che vediamo noi ottenere lo stesso risultato quando abbiamo un errore:

>>> do_something_that_might_error() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 2, in do_something_that_might_error 
    File "<stdin>", line 2, in raise_error 
RuntimeError: something bad happened! 
+0

come detto sopra e anche per me, 'traceback.print_exc()' restituisce solo l'ultima chiamata: come riesci a restituire più livelli dello stack (e probabilmente tutti i levle?) – geekobi

+0

@geekobi Non sono sicuro di cosa stai chiedendo qui. Dimostro che otteniamo il traceback fino al punto di ingresso del programma/interprete. Su cosa non sei chiaro? –

5

Per ottenere il preciso traccia stack, come una stringa, che sarebbe sono stati sollevati in assenza di tentativi/eccetto se fossero lì per scavalcarlo, semplicemente posto questo nel blocco eccetto che cattura l'eccezione incriminata.

desired_trace = traceback.format_exc(sys.exc_info()) 

Ecco come usarlo (supponendo flaky_func è definito, e log chiama il sistema di registrazione preferito):

import traceback 
import sys 

try: 
    flaky_func() 
except KeyboardInterrupt: 
    raise 
except Exception: 
    desired_trace = traceback.format_exc(sys.exc_info()) 
    log(desired_trace) 

E 'una buona idea per la cattura e re-raise KeyboardInterrupt s, in modo da può ancora uccidere il programma usando Ctrl-C.La registrazione è al di fuori della portata della domanda, ma una buona opzione è logging. Documentazione per i moduli sys e traceback.

+0

Questo non funziona in Python 3 e deve essere cambiato in 'desired_trace = traceback.format_exc()'. Passare a 'sys.exc_info()' dato che l'argomento non è mai stata la cosa giusta da fare, ma viene silenziosamente ignorato in Python 2, ma non in Python 3 (3.6.4 comunque). – martineau

Problemi correlati