1568 Stimmen

Wie kann man den vollständigen Traceback der Ausnahme abfangen und ausgeben, ohne das Programm anzuhalten/zu beenden?

Ich möchte Ausnahmen abfangen und protokollieren, ohne zu beenden, z. B.,

try:
    do_stuff()
except Exception as err:
    print(Exception, err)
    # I want to print the entire traceback here,
    # not just the exception name and details

Ich möchte genau die gleiche Ausgabe drucken, die gedruckt wird, wenn die Ausnahme ausgelöst wird, ohne dass die try/except die Ausnahme abfängt, und ich tue no Ich möchte, dass es mein Programm beendet.

19 Stimmen

Das ist zwar keine vollständige Antwort, aber vielleicht möchte jemand wissen, dass man viele Informationen erhalten kann, wenn man in err.__traceback__ (zumindest in Python 3.x)

35 Stimmen

Es wurde 825.000 Mal aufgerufen, während man versuchte, herauszufinden, wie man seine Stacktraces ausdrucken kann. Das ist ein weiteres Zen von Python.

14 Stimmen

Anscheinend bin ich der Einzige auf der Welt, der den Stapel ausdrucken möchte. wenn kein Fehler vorliegt (= nur um zu sehen, wie ich genau zu dieser Zeile gekommen bin (es ist nicht mein Code, und er ist so hässlich, dass ich nicht weiß, wie er hierher gekommen ist!)).

1454voto

volting Punkte 14083

traceback.format_exc() o sys.exc_info() liefert mehr Informationen, wenn Sie das wollen.

import traceback
import sys

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

23 Stimmen

print(sys.exc_info()[0] druckt <class 'Exception'> .

16 Stimmen

Verwenden Sie nicht exc... der Traceback enthält alle Informationen stackoverflow.com/questions/4564559/

1 Stimmen

Es mag erwartet werden (oder auch nicht), aber dies erzeugt keinen vollständigen Traceback. Es ist durch die Punkte begrenzt, die die Ausnahme auslösen und sie behandeln (Python 3.8). Sie müssen nicht try / catch a den Traceback anzeigen .

867voto

Sylvain Leroux Punkte 47483

In einigen anderen Antworten wurde bereits auf die Traceback Modul.

Bitte beachten Sie, dass bei print_exc In einigen Eckfällen werden Sie nicht das 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()

...zeigt den Traceback des Befehls zuletzt Ausnahme:

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

Wenn Sie wirklich auf das Original zugreifen müssen Traceback Eine Lösung ist die Zwischenspeicherung der Ausnahme-Infos wie zurückgegeben von exc_info in einer lokalen Variablen und zeigen Sie sie 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

Produzieren:

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

Allerdings gibt es dabei einige Fallstricke:

  • Aus dem Dokument von sys_info :

    Das Zuweisen des Traceback-Rückgabewerts an eine lokale Variable in einer Funktion, die eine Ausnahme behandelt, führt zu einer Zirkelbezug . Dadurch wird verhindert, dass alles, worauf eine lokale Variable in derselben Funktion oder der Traceback verweist, in den Garbage Collect gelangt. [...] Wenn Sie den Traceback benötigen, stellen Sie sicher, dass Sie ihn nach der Verwendung löschen (am besten mit einem Versuch ... endlich Aussage)

  • sondern aus demselben Dokument:

    Ab Python 2.2 werden solche Zyklen automatisch zurückgewonnen wenn die Müllabfuhr aktiviert ist und sie unerreichbar werden, aber es ist immer noch effizienter, die Erzeugung von Zyklen zu vermeiden.


Andererseits können Sie durch den Zugriff auf den Traceback verbunden mit eine Ausnahme, Python 3 liefert 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!")

383voto

dimo414 Punkte 44554

Wenn Sie debuggen und nur den aktuellen Stack-Trace sehen wollen, können Sie einfach aufrufen:

traceback.print_stack()

Es ist nicht nötig, eine Ausnahme manuell auszulösen, nur um sie wieder abzufangen.

16 Stimmen

Das Traceback-Modul tut genau das - eine Ausnahme auslösen und abfangen.

7 Stimmen

Die Ausgabe erfolgt übrigens standardmäßig nach STDERR. Es erschien nicht in meinen Protokollen, weil es an eine andere Stelle umgeleitet wurde.

1 Stimmen

@pppery Ich kann es mit Python 3.8 nicht sehen. Und die Sache mit try y catch ist, dass es nicht den vollständigen Traceback anzeigt, nur von raise a except .

238voto

Wie kann man den vollständigen Traceback ausdrucken, ohne das Programm anzuhalten?

Wenn Sie Ihr Programm bei einem Fehler nicht anhalten wollen, müssen Sie diesen Fehler mit einem try/except behandeln:

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

Um den vollständigen Traceback zu extrahieren, verwenden wir die traceback Modul aus der Standardbibliothek:

import traceback

Und um einen anständig komplizierten Stacktrace zu erstellen, um zu demonstrieren, dass wir den vollständigen Stacktrace erhalten:

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

def do_something_that_might_error():
    raise_error()

Drucken

An drucken den vollständigen Traceback, verwenden Sie die traceback.print_exc Methode:

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

Welche Drucke:

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 Drucken, Protokollieren:

Am besten ist es jedoch, einen Logger für Ihr Modul einzurichten. Er kennt den Namen des Moduls und ist in der Lage, die Ebenen zu ändern (neben anderen Attributen, wie z. B. Handler)

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

In diesem Fall müssen Sie die logger.exception stattdessen die Funktion:

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

Welche Protokolle:

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 Zeichenkette, in diesem Fall brauchen Sie die traceback.format_exc stattdessen die Funktion:

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

Welche Protokolle:

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!

Schlussfolgerung

Bei allen drei Optionen erhalten wir die gleiche Ausgabe wie bei einem Fehler:

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

Was zu verwenden ist

Leistungsaspekte sind hier nicht wichtig, da IO normalerweise dominiert. Ich würde es bevorzugen, da es genau das tut, was in einer vorwärtskompatiblen Weise angefordert wird:

logger.exception(error)

Logging-Level und -Outputs können angepasst werden, so dass sie leicht ausgeschaltet werden können, ohne den Code zu berühren. Und in der Regel ist es am effizientesten, nur das zu tun, was direkt benötigt wird.

7 Stimmen

Wie oben gesagt und auch für mich, traceback.print_exc() gibt nur den letzten Aufruf zurück: Wie kann man mehrere Ebenen des Stapels (und möglicherweise alle Ebenen) zurückgeben?

0 Stimmen

@geekobi Ich bin mir nicht sicher, worauf Sie hinauswollen. Ich zeige, dass wir den Traceback bis zum Einstiegspunkt des Programms/Interpreters erhalten. Was ist Ihnen nicht klar?

2 Stimmen

Was @geekobi damit sagen will, ist, dass traceback.print_exc() bei einem Catch und Re-Raise nur den Re-Raise-Stack zurückgibt, nicht den ursprünglichen Stack.

58voto

traceback.format_exception(exception_object)

Wenn Sie nur das Exception-Objekt haben, können Sie den Traceback als String von jedem Punkt des Codes in Python 3 mit erhalten:

import traceback

''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))

Vollständiges Beispiel:

#!/usr/bin/env python3

import traceback

def f():
    g()

def g():
    raise Exception('asdf')

try:
    g()
except Exception as e:
    exc_obj = e

tb_str = ''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
print(tb_str)

Ausgabe:

Traceback (most recent call last):
  File "./main.py", line 12, in <module>
    g()
  File "./main.py", line 9, in g
    raise Exception('asdf')
Exception: asdf

Dokumentation: https://docs.python.org/3.9/library/traceback.html#traceback.format_exception

Siehe auch: Extrahieren von Traceback-Informationen aus einem Ausnahmeobjekt

Getestet in Python 3.9

13 Stimmen

Warum ist die einzige Möglichkeit, dies in der Sprache zu tun, die doppelte Übergabe derselben Information (beide exc_obj y exc_obj.__traceback__ ), und ein irrelevantes drittes Argument None ?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X