Fangen Sie den vollständigen Python-Ausnahme-Traceback ab und drucken Sie ihn aus, ohne das Programm anzuhalten/zu beenden

Lesezeit: 11 Minuten

Chriscauleys Benutzeravatar
Chriscauley

Ich möchte Ausnahmen abfangen und protokollieren, ohne das Programm 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 try/exclusive die Ausnahme abfängt, und das tue ich auch nicht Ich möchte, dass es mein Programm beendet.

  • Keine vollständige Antwort, aber jemand möchte vielleicht wissen, dass Sie auf viele Informationen zugreifen können, die Sie untersuchen err.__traceback__ (zumindest in Python 3.x)

    – Vito Gentile

    25. Februar 2021 um 12:10 Uhr


  • Es scheint, dass ich der Einzige auf der Welt bin, der den Stapel drucken 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 herausfinden kann, wie er hierher gekommen ist!)).

    – Olivier Pons

    2. Juni 2021 um 8:23

  • Um das wahre Zen von Python zu verstehen, @PavelVlasov, muss man auch wissen, wann das Zen von Python nicht Zen ist. Vor der Aufklärung, den Stack-Traces folgend, nach der Aufklärung, den Stack-Traces folgend. Eines Tages wirst du es verstehen und Frieden finden, Grashüpfer. Kehren Sie nicht zur Korruption von Java zurück, aus der Sie gekommen sind.

    – NeilG

    28. April um 1:01


Voltings Benutzeravatar
volting

traceback.format_exc() oder sys.exc_info() wird mehr Informationen liefern, wenn Sie das wollen.

import traceback
import sys

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

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

    – weberc2

    28. August 2019 um 15:52 Uhr

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

    – droid192

    8. September 2019 um 18:11 Uhr

  • print(sys.exc_info()[2]) Erträge <traceback object at 0x0000028A79E6B2C8>.

    – Teepeemm

    14. Okt. 2020 um 14:23

  • print(traceback.format_exc()) ist besser als traceback.print_tb(exc.__traceback__). print(sys.exc_info()) gibt das gesamte Tupel zurück und sieht so aus (<class 'UnicodeDecodeError'>, UnicodeDecodeError('utf-8', b'\x81', 0, 1, 'invalid start byte'), <traceback object at 0x7f179d64ae00>) Also tatsächlich traceback.format_exc() ist wirklich überlegen, weil das druckt Traceback (most recent call last): File "<ipython-input-15-9e3d6e01ef04>", line 2, in <module> b"\x81".decode() UnicodeDecodeError: 'utf-8' codec can't decode byte 0x81 in position 0: invalid start byte

    – Markieren

    7. Mai 2021 um 20:47 Uhr


  • Entfernen Sie das exc_info() es funktioniert nicht.

    – usamec

    2. August 2022 um 12:26 Uhr

Benutzeravatar von Sylvain Leroux
Sylvain Leroux

Einige andere Antworten haben bereits darauf hingewiesen zurück verfolgen Modul.

Bitte beachten Sie das mit print_excIn einigen Einzelfällen erhalten Sie jedoch nicht das, 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 an 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 zurück verfolgen Eine Lösung besteht darin, das zwischenzuspeichern Ausnahmeinformationen wie zurückgegeben von exc_info in einer lokalen Variablen und zeigen Sie es mit an 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!

Dabei gibt es allerdings ein paar Fallstricke:

  • Aus dem Dokument von sys_info:

    Das Zuweisen des Traceback-Rückgabewerts zu einer lokalen Variablen in einer Funktion, die eine Ausnahme behandelt, führt zu einem Fehler zirkulärer Verweis. Dadurch wird verhindert, dass alles, was von einer lokalen Variablen in derselben Funktion oder vom Traceback referenziert wird, durch Garbage Collection erfasst wird. […] Wenn Sie den Traceback dennoch benötigen, löschen Sie ihn unbedingt nach der Verwendung (Am besten mit einem Versuch machen … schließlich Aussage)

  • aber aus demselben Dokument:

    Ab Python 2.2 werden solche Zyklen automatisch zurückgefordert Wenn die Garbage Collection aktiviert ist und sie nicht mehr erreichbar sind, bleibt es effizienter, die Erstellung von Zyklen zu vermeiden.


Zum anderen, indem wir Ihnen den Zugriff auf das Traceback ermöglichen verknüpft mit Eine Ausnahme liefert Python 3 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!")

Benutzeravatar von dimo414
dimo414

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

traceback.print_stack()

Es ist nicht erforderlich, manuell eine Ausnahme auszulösen, nur um sie erneut abzufangen.

  • Das Traceback-Modul macht genau das – es löst eine Ausnahme aus und fängt sie ab.

    – pappig

    7. November 2015 um 19:08

  • Die Ausgabe erfolgt übrigens standardmäßig an STDERR. Erscheint nicht in meinen Protokollen, weil es woanders umgeleitet wurde.

    – mpen

    11. Dezember 2018 um 0:18

  • @pppery Ich kann es mit Python 3.8 nicht sehen. Und die Sache mit try Und catch ist, dass nicht der vollständige Traceback angezeigt wird, sondern nur von raise Zu except.

    – x-yuri

    25. Juni 2020 um 19:12 Uhr


Russland muss Putins Benutzer-Avatar entfernen
Russland muss Putin absetzen

Wie drucke ich den vollständigen Traceback aus, ohne das Programm anzuhalten?

Wenn Sie Ihr Programm bei einem Fehler nicht anhalten möchten, 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 einigermaßen komplizierten Stacktrace zu erstellen, um zu zeigen, dass wir den vollständigen Stacktrace erhalten:

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

def do_something_that_might_error():
    raise_error()

Drucken

Zu drucken Den vollständigen Traceback verwenden Sie traceback.print_exc Methode:

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

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

Eine bewährte Vorgehensweise besteht jedoch darin, einen Logger für Ihr Modul einzurichten. Es kennt den Namen des Moduls und kann Ebenen ändern (neben anderen Attributen, z. B. Handlern).

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

In diesem Fall möchten Sie das logger.exception Funktion stattdessen:

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 möchten Sie einfach nur die Zeichenfolge, in diesem Fall möchten Sie die traceback.format_exc Funktion stattdessen:

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!

Abschluss

Und für alle drei Optionen sehen wir, dass wir die gleiche Ausgabe erhalten 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

Leistungsbedenken spielen hier keine Rolle, da IO normalerweise dominiert. Ich würde es vorziehen, da es genau das tut, was angefordert wird, und zwar auf vorwärtskompatible Weise:

logger.exception(error)

Protokollierungsstufen und -ausgaben können angepasst werden, sodass das Ausschalten einfach ist, ohne den Code zu berühren. Und normalerweise ist es am effizientesten, das zu tun, was direkt benötigt wird.

Anthonys Benutzeravatar
Antonius

Erstens nicht verwenden printFür die Protokollierung gibt es eine stabile, bewährte und durchdachte Lösung stdlib Modul, um das zu tun: logging. Du auf jeden Fall sollen Verwenden Sie es stattdessen.

Zweitens: Lassen Sie sich nicht dazu verleiten Durcheinander mit unabhängigen Tools, wenn es einen nativen und einfachen Ansatz gibt. Hier ist es:

log = logging.getLogger(__name__)

try:
    call_code_that_fails()
except MyError:
    log.exception('Any extra info you want to see in your logs')

Das ist es. Sie sind jetzt fertig.

Erklärung für alle, die sich dafür interessieren, wie die Dinge unter der Haube funktionieren

Was log.exception ist eigentlich nur ein Anruf log.error (d. h. Ereignis mit Level protokollieren ERROR) Und Drucken Sie dann den Traceback aus.

Warum ist es besser?

Nun, hier sind einige Überlegungen:

  • es ist nur Rechts;
  • es ist unkompliziert;
  • es ist einfach.

Warum sollte niemand verwenden traceback oder Logger anrufen mit exc_info=True oder sich die Hände schmutzig machen sys.exc_info?

Naja, einfach so! Sie alle dienen unterschiedlichen Zwecken. Zum Beispiel, traceback.print_excDie Ausgabe unterscheidet sich ein wenig von den vom Interpreter selbst erstellten Tracebacks. Wenn Sie es verwenden, verwirren Sie jeden, der Ihre Protokolle liest, und er wird mit dem Kopf darüber stoßen.

Vorbeigehen exc_info=True Anrufe zu protokollieren ist einfach unangemessen. AberDies ist nützlich, wenn Sie behebbare Fehler erkennen und diese protokollieren möchten (z. B. mithilfe von INFO Ebene) auch mit Tracebacks, weil log.exception erzeugt Protokolle nur einer Ebene – ERROR.

Und Sie sollten es auf jeden Fall vermeiden, sich damit anzulegen sys.exc_info so viel wie du kannst. Es ist einfach keine öffentliche Schnittstelle, sondern eine interne – Sie dürfen Verwenden Sie es, wenn Sie genau wissen, was Sie tun. Es ist nicht nur zum Drucken von Ausnahmen gedacht.

  • Es funktioniert auch nicht so wie es ist. Das ist es nicht. Ich bin jetzt noch nicht fertig: Diese Antwort verschwendet nur Zeit.

    – A. Rager

    27. April 2019 um 16:07 Uhr


  • Ich würde auch hinzufügen, dass Sie es einfach tun können logging.exception(). Es ist nicht erforderlich, eine Protokollinstanz zu erstellen, es sei denn, Sie haben besondere Anforderungen.

    – Shital Shah

    18. Mai 2019 um 6:35 Uhr

  • Ich finde diese Antwort irgendwie lächerlich. Es ist voll von „Tu das/Tu das nicht, nur weil“, ohne zu erklären, warum. Ihre Punkte in „Warum ist es besser?“ bedeutet praktisch, dass alle dasselbe sagen: „weil es so ist.“ Was ich nicht hilfreich finde. Du hast es zumindest ein wenig erklärt.

    – Brechen

    18. Dezember 2020 um 1:28

  • Gute Informationen (ich wusste nichts davon logging.exception), aber etwas herablassend. Ich denke, das liegt eher an der Sprachbarriere als an böswilliger Absicht.

    – rjh

    5. September 2021 um 14:49 Uhr


  • Was dieser Typ gesagt hat. In meiner Firma feuern wir jeden, der sich per Printprotokoll anmeldet. /S

    – Omni

    14. Januar 2022 um 12:33 Uhr

traceback.format_exception(exception_object)

Wenn Sie nur das Ausnahmeobjekt haben, können Sie den Traceback als String von jedem Punkt des Codes in Python 3 abrufen mit:

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)

Ausgang:

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: Traceback-Informationen aus einem Ausnahmeobjekt extrahieren

Getestet in Python 3.9

  • Es funktioniert auch nicht so wie es ist. Das ist es nicht. Ich bin jetzt noch nicht fertig: Diese Antwort verschwendet nur Zeit.

    – A. Rager

    27. April 2019 um 16:07 Uhr


  • Ich würde auch hinzufügen, dass Sie es einfach tun können logging.exception(). Es ist nicht erforderlich, eine Protokollinstanz zu erstellen, es sei denn, Sie haben besondere Anforderungen.

    – Shital Shah

    18. Mai 2019 um 6:35 Uhr

  • Ich finde diese Antwort irgendwie lächerlich. Es ist voll von „Tu das/Tu das nicht, nur weil“, ohne zu erklären, warum. Ihre Punkte in „Warum ist es besser?“ bedeutet praktisch, dass alle dasselbe sagen: „weil es so ist.“ Was ich nicht hilfreich finde. Du hast es zumindest ein wenig erklärt.

    – Brechen

    18. Dezember 2020 um 1:28

  • Gute Informationen (ich wusste nichts davon logging.exception), aber etwas herablassend. Ich denke, das liegt eher an der Sprachbarriere als an böswilliger Absicht.

    – rjh

    5. September 2021 um 14:49 Uhr


  • Was dieser Typ gesagt hat. In meiner Firma feuern wir jeden, der sich per Printprotokoll anmeldet. /S

    – Omni

    14. Januar 2022 um 12:33 Uhr

Neurons Benutzeravatar
Neuron

Zusätzlich zur Antwort von Aaron Hall, wenn Sie protokollieren, es aber nicht verwenden möchten logging.exception() (da es auf der ERROR-Ebene protokolliert wird), können Sie eine niedrigere Ebene verwenden und bestehen exc_info=True. z.B

try:
    do_something_that_might_error()
except Exception:
    logging.info('General exception noted.', exc_info=True)

  • Dies ist auch nützlich, wenn es um einen erkannten Protokollierungsfehler geht, z. B. wenn es Ihnen aus irgendeinem Grund nicht gelungen ist, ein tatsächliches Logger-Objekt zu erstellen.

    – Mike Nagetier

    21. Dezember 2021 um 17:09 Uhr

1453400cookie-checkFangen Sie den vollständigen Python-Ausnahme-Traceback ab und drucken Sie ihn aus, ohne das Programm anzuhalten/zu beenden

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy