Erfassung von Python-Ausnahmemeldungen

520
import ftplib
import urllib2
import os
import logging
logger = logging.getLogger('ftpuploader')
hdlr = logging.FileHandler('ftplog.log')
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
hdlr.setFormatter(formatter)
logger.addHandler(hdlr)
logger.setLevel(logging.INFO)
FTPADDR = "some ftp address"

def upload_to_ftp(con, filepath):
    try:
        f = open(filepath,'rb')                # file to send
        con.storbinary('STOR '+ filepath, f)         # Send the file
        f.close()                                # Close file and FTP
        logger.info('File successfully uploaded to '+ FTPADDR)
    except, e:
        logger.error('Failed to upload to ftp: '+ str(e))

Dies scheint nicht zu funktionieren, ich erhalte einen Syntaxfehler. Was ist der richtige Weg, um alle Arten von Ausnahmen in einer Datei zu protokollieren?

Hellnar
quelle
2
Ihre Einrückung ist gebrochen. Und lassen Sie den ,nach except.
Sven Marnach
3
@SvenMarnach, wenn Sie das weglassen ,nach except, die Sie erhalten global name 'e' is not defined, die als falsche Syntax nicht viel besser ist.
Val
12
@Val: Sollte except Exception as eoder sein except Exception, e, abhängig von der Python-Version.
Sven Marnach
1
Wahrscheinlich liegt es irgendwo bei diesen 8 Antworten, aber wenn Sie eine Datei öffnen, sollte sich der geschlossene Teil niemals in der try-Anweisung befinden, sondern entweder in einer finally-Anweisung oder in einer with-Anweisung.
JC Rocamonde

Antworten:

733

Sie müssen definieren, welche Art von Ausnahme Sie abfangen möchten. Schreiben Sie also except Exception, e:statt except, e:einer allgemeinen Ausnahme (die sowieso protokolliert wird).

Eine andere Möglichkeit besteht darin, Ihren gesamten Try / Except-Code folgendermaßen zu schreiben:

try:
    with open(filepath,'rb') as f:
        con.storbinary('STOR '+ filepath, f)
    logger.info('File successfully uploaded to '+ FTPADDR)
except Exception, e: # work on python 2.x
    logger.error('Failed to upload to ftp: '+ str(e))

In Python 3.x und modernen Versionen von Python 2.x wird except Exception as eanstelle von except Exception, e:

try:
    with open(filepath,'rb') as f:
        con.storbinary('STOR '+ filepath, f)
    logger.info('File successfully uploaded to '+ FTPADDR)
except Exception as e: # work on python 3.x
    logger.error('Failed to upload to ftp: '+ str(e))
Eumiro
quelle
118
repr (e) gibt Ihnen die Ausnahme (und die Nachrichtenzeichenfolge); str (e) gibt nur die Nachrichtenzeichenfolge an.
Whitebeard
11
Als Alternative für die Protokollierungsausnahme können Sie logger.exception(e)stattdessen verwenden. Die Ausnahme wird mit Traceback auf derselben logging.ERROREbene protokolliert .
mbdevpl
1
@mbdevpl das scheint nicht wahr zu sein. Es scheint str () mit der Ausnahme aufzurufen
KevinOrr
6
except Exception, e:wirft mir in Python 3 einen Syntaxfehler zu. Wird dies erwartet?
Charlie Parker
27
@CharlieParker in Python3 schreibenexcept Exception as e:
Eumiro
282

Die Syntax wird in Python 3 nicht mehr unterstützt. Verwenden Sie stattdessen Folgendes.

try:
    do_something()
except BaseException as e:
    logger.error('Failed to do something: ' + str(e))
sjtaheri
quelle
2
Eigentlich sollten Sie logger.error verwenden ('Fehler beim Ausführen von% s', str (e)). Wenn Ihre Logger-Ebene über dem Fehler liegt, wird die Zeichenfolgeninterpolation nicht durchgeführt.
Avyfain
7
@avyfain - Du bist falsch. Die Anweisung logging.error('foo %s', str(e))wird immer ein eine Zeichenfolge konvertiert . Um das zu erreichen, was Sie möchten, würden Sie es verwenden logging.error('foo %s', e)- wodurch das Protokollierungsframework die Konvertierung durchführen kann (oder nicht).
Ron Dahlgren
1
Sie können in einer Python-REPL überprüfen (hier mit Python 3.5.2 und Ipython): siehe mein Kern hier
Ron Dahlgren
2
Als Alternative für die Protokollierungsausnahme können Sie logger.exception(e)stattdessen verwenden. Die Ausnahme wird mit Traceback auf derselben logging.ERROREbene protokolliert .
mbdevpl
11
Passen Sie auf except BaseExceptionund except Exceptionsind nicht auf dem gleichen Niveau. except Exceptionfunktioniert in Python3, wird aber KeyboardInterruptzum Beispiel nicht abgefangen (was sehr praktisch sein kann, wenn Sie Ihren Code unterbrechen möchten!), während es BaseExceptionkeine Ausnahmen abfängt . Unter diesem Link finden Sie die Hierarchie der Ausnahmen.
Jeannej
41

Aktualisierung auf etwas einfacheres für Logger (funktioniert sowohl für Python 2 als auch für Python 3). Sie benötigen kein Traceback-Modul.

import logging

logger = logging.Logger('catch_all')

def catchEverythingInLog():
    try:
        ... do something ...
    except Exception as e:
        logger.error(e, exc_info=True)
        ... exception handling ...

Dies ist jetzt der alte Weg (obwohl immer noch funktioniert):

import sys, traceback

def catchEverything():
    try:
        ... some operation(s) ...
    except:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        ... exception handling ...

exc_value ist die Fehlermeldung.

berniey
quelle
2
Dies wäre meine bevorzugte Methode. Ich nehme an, nur das Drucken der Zeichenfolge ist nützlich für die Protokollierung, aber wenn ich mit diesen Informationen etwas anfangen muss, brauche ich mehr als nur eine Zeichenfolge.
Sulimmesh
3
Sie müssen im zweiten Beispiel kein Traceback importieren, oder?
Starikoff
34

In einigen Fällen können Sie die e.message oder e.messages verwenden . Dies funktioniert jedoch nicht in allen Fällen. Umso sicherer ist es, die str (e) zu verwenden.

try:
  ...
except Exception as e:
  print(e.message)
Windschatten
quelle
42
Das Problem dabei ist, zum Beispiel, wenn Sie except Exception as e, und eist ein IOError, Sie erhalten e.errno, e.filenameund e.strerror, aber anscheinend nicht e.message(zumindest in Python 2.7.12). Wenn Sie die Fehlermeldung erfassen möchten, verwenden Sie str(e)wie in den anderen Antworten.
Epalm
@epalm Was ist, wenn Sie den IOError vor der Ausnahme abfangen?
Albert Thompson
@ HeribertoJuárez Warum Sonderfälle fangen, während Sie sie einfach in eine Schnur umwandeln können?
HosseyNJF
25

Wenn Sie die Fehlerklasse, die Fehlermeldung und den Stack-Trace (oder einige davon) möchten, verwenden Sie sys.exec_info().

Minimaler Arbeitscode mit einigen Formatierungen:

import sys
import traceback

try:
    ans = 1/0
except BaseException as ex:
    # Get current system exception
    ex_type, ex_value, ex_traceback = sys.exc_info()

    # Extract unformatter stack traces as tuples
    trace_back = traceback.extract_tb(ex_traceback)

    # Format stacktrace
    stack_trace = list()

    for trace in trace_back:
        stack_trace.append("File : %s , Line : %d, Func.Name : %s, Message : %s" % (trace[0], trace[1], trace[2], trace[3]))

    print("Exception type : %s " % ex_type.__name__)
    print("Exception message : %s" %ex_value)
    print("Stack trace : %s" %stack_trace)

Welches gibt die folgende Ausgabe:

Exception type : ZeroDivisionError
Exception message : division by zero
Stack trace : ['File : .\\test.py , Line : 5, Func.Name : <module>, Message : ans = 1/0']

Die Funktion sys.exc_info () gibt Ihnen Details zur letzten Ausnahme. Es wird ein Tupel von zurückgegeben (type, value, traceback).

tracebackist eine Instanz eines Traceback-Objekts. Sie können den Trace mit den bereitgestellten Methoden formatieren. Weitere Informationen finden Sie in der Traceback-Dokumentation .

Kavindu Dodanduwa
quelle
3
Mit e.__class__.__name__ kann kann auch die Ausnahmeklasse zurückgegeben werden.
Kenorb
19

Sie können logger.exception("msg")zum Protokollieren von Ausnahmen mit Traceback Folgendes verwenden:

try:
    #your code
except Exception as e:
    logger.exception('Failed: ' + str(e))
Peter
quelle
Zufällig e.msgist die Zeichenfolgendarstellung der ExceptionKlasse.
MarkHu
5
Oder einfach logger.exception(e).
mbdevpl
5

Sie können versuchen, den BaseException-Typ explizit anzugeben. Dies fängt jedoch nur Ableitungen von BaseException ab. Dies schließt zwar alle von der Implementierung bereitgestellten Ausnahmen ein, es ist jedoch möglicherweise auch möglich, beliebige Klassen alten Stils auszulösen.

try:
  do_something()
except BaseException, e:
  logger.error('Failed to do something: ' + str(e))
Heini Høgnason
quelle
4

Verwenden Sie str (ex), um die Ausführung zu drucken

try:
   #your code
except ex:
   print(str(ex))
Niraj Trivedi
quelle
2

Für die zukünftigen Kämpfer ist in Python 3.8.2 (und vielleicht ein paar Versionen davor) die Syntax

except Attribute as e:
    print(e)
Syter
quelle
1

Wenn Sie str(e)oder verwenden repr(e), um die Ausnahme darzustellen, erhalten Sie nicht den tatsächlichen Stack-Trace. Daher ist es nicht hilfreich zu ermitteln, wo sich die Ausnahme befindet.

Nachdem Sie andere Antworten und das Protokollierungsprotokoll gelesen haben, können Sie auf folgende Weise den eigentlichen Stack-Trace drucken, um das Debuggen zu vereinfachen:

Verwendung logger.debug()mit dem Parameterexc_info

try:
    # my code
exception SomeError as e:
    logger.debug(e, exc_info=True)

verwenden logger.exception()

oder wir können direkt verwenden logger.exception(), um die Ausnahme zu drucken.

try:
    # my code
exception SomeError as e:
    logger.exception(e)
jdhao
quelle