2010-09-13 6 views
438

Ich schreibe ein Programm, das 10 Websites analysiert, Datendateien sucht, die Dateien speichert und dann analysiert, um Daten zu erstellen, die problemlos in der NumPy-Bibliothek verwendet werden können. Es gibt tons von Fehlern, die diese Datei durch schlechte Links, schlecht formatierte XML, fehlende Einträge und andere Dinge, die ich noch kategorisieren muss. Ich habe zunächst dieses Programm, um Fehler wie damit zu umgehen:Wie kann man den gesamten Traceback drucken, ohne das Programm zu stoppen?

try: 
    do_stuff() 
except: 
    pass 

Aber jetzt will ich Fehler protokollieren:

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

Hinweis: Dies ist das Drucken in eine Protokolldatei für eine spätere Überprüfung. Dies druckt normalerweise sehr nutzlose Daten aus. Was ich will, ist genau die gleichen Zeilen gedruckt zu drucken, wenn der Fehler ohne try ausgelöst wird - außer das Abfangen der Ausnahme, aber ich möchte nicht, dass es mein Programm anhält, da es in einer Reihe von for-Schleifen verschachtelt ist, die ich gerne hätte bis zur Fertigstellung.

Antwort

258

Einige andere Antworten haben bereits auf das Modul traceback hingewiesen.

Bitte beachten Sie, dass mit print_exc, in einigen Fällen, Sie nicht erhalten, was Sie erwarten würden. In Python 2.x:

import traceback 

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

    traceback.print_exc() 

...die Rückverfolgung der letzten Ausnahme wird angezeigt:

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

Wenn Sie wirklich das Original Zurückverfolgungs eine Lösung zugreifen müssen, ist die Ausnahme Infos als zurück von exc_info in einer lokalen Variablen zwischenzuspeichern und zeigen sie es mit 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 

Producing:

Nur wenige Fallen mit diesem aber:

  • Vom doc von 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)

  • aber aus dem gleichen doc:

    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.


Auf der anderen Seite, indem Sie mit einer Ausnahme der Zurückverfolgungs zugeordnet zuzugreifen, Python 3 erzeugt ein weniger überraschendes Ergebnis:

import traceback 

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

    traceback.print_tb(err.__traceback__) 

... wird angezeigt:

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

Sie müssen den Versuch setzen/außer in den meisten Innenschleife, wo der Fehler auftreten kann, dh

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 

... und so weiter

Mit anderen Worten, müssen Sie wickeln Anweisungen, die in try/except so spezifisch wie möglich versagen können, in der innersten Schleife wie möglich.

2

Sie möchten das Modul traceback. Sie können damit Stack-Dumps drucken, wie es Python normalerweise macht. Insbesondere wird die print_last Funktion die letzte Ausnahme und eine Stapelüberwachung drucken.

479

traceback.format_exc() oder sys.exc_info() wird mehr Informationen ergeben, wenn es das ist, was Sie wollen.

import traceback 
import sys 

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

Warum nicht einfach 'traceback.print_exc()' verwenden? –

+13

Ich möchte die Zeichenfolge, ich bin froh, zeigte mir die Methode ('format_exc()'), um die Zeichenfolge :) –

+2

@FrozenFlame, weil Sie es möglicherweise selbst protokollieren möchten, bevor es erneut – casraf

130

Wenn Sie debuggen und nur den aktuellen Stack-Trace sehen möchten, können Sie einfach anrufen:

traceback.print_stack()

Sie müssen keine Ausnahme manuell auslösen, nur um sie erneut abzufangen.

+4

Das Traceback-Modul macht genau das - Erheben und fangen Sie eine Ausnahme. – ppperry

49

How to print the full traceback without halting the program?

Wenn Sie nicht Ihr Programm auf einen Fehler stoppen wollen, müssen Sie mit einem Versuch diesen Fehler zu handhaben/außer:

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

die vollständige Rückverfolgung zu extrahieren, werden wir verwenden das traceback Modul aus der Standardbibliothek:

import traceback 

Und eine anständig komplizierten Stacktrace zu zeigen, zu schaffen, dass wir die volle stacktrace erhalten:

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

def do_something_that_might_error(): 
    raise_error() 

Printing

Um Druck die volle Rückverfolgung, verwenden Sie die traceback.print_exc Methode:

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

Welche druckt:

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! 

Besser als Druck, Protokollierung:

Es empfiehlt sich jedoch, einen Logger für Ihr Modul einzurichten. Es wird den Namen des Moduls kennen und in der Lage seiner Ebene zu ändern (unter anderen Attributen, wie Handler)

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

In diesem Fall sollten Sie die logger.exception Funktion statt:

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

welche protokolliert:

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! 

Oder vielleicht wollen Sie nur die Zeichenfolge, wobei in diesem Fall, werden Sie die traceback.format_exc Funktion wollen statt:

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

Welche protokolliert:

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! 

Fazit

Und für alle drei Optionen, wir sehen wir die gleiche Leistung erhalten, wie wenn wir einen Fehler haben:

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

wie oben gesagt und auch für mich, 'traceback.print_exc()' gibt nur den letzten Aufruf zurück: Wie gelingt es Ihnen, mehrere Ebenen des Stacks (und möglicherweise alle levele s?) – geekobi

+0

@geekobi Ich bin mir nicht sicher was du fragst hier. Ich zeige, dass wir das Traceback bis zum Einstiegspunkt des Programms/Interpreters bekommen. Worüber bist du nicht klar? –

5

Um die präzise Stack-Trace, als eine Zeichenfolge, die wäre wurden ausgelöst, wenn kein Versuch/außer es gab, um darüber zu treten, einfach legen Sie das in den Ausnahmeblock, der die beleidigende Ausnahme abfängt.

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

Hier ist, wie es zu verwenden (unter der Annahme flaky_func definiert ist, und log ruft Ihre Lieblings Logging-System):

import traceback 
import sys 

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

Es ist eine gute Idee, zu fangen und re-raisen KeyboardInterrupt s, so dass Sie kann das Programm immer noch mit Strg-C beenden.Protokollierung liegt außerhalb des Bereichs der Frage, aber eine gute Option ist logging. Dokumentation für die Module sys und traceback.

+0

Dies funktioniert nicht in Python 3 und muss in 'wanted_trace = traceback.format_exc()' geändert werden. Die Übergabe von 'sys.exc_info()' als Argument war nie das Richtige, wird aber in Python 2 stillschweigend ignoriert - aber nicht in Python 3 (jedenfalls 3.6.4). – martineau

Verwandte Themen