przechwytywanie wiadomości wyjątku python

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

Wydaje się, że to nie działa, pojawia się błąd składniowy, jaki jest prawidłowy sposób rejestrowania wszelkiego rodzaju wyjątków w pliku

Hellnar
źródło
2
Twoje wcięcie jest zepsute. I pomiń ,później except.
Sven Marnach
3
@ SvvenMarnach, jeśli pominiesz ,później except, otrzymasz global name 'e' is not defined, co nie jest dużo lepsze niż zła składnia.
Val
12
@Val: Powinien być except Exception as elub except Exception, e, w zależności od wersji Python.
Sven Marnach,
1
Prawdopodobnie jest to gdzieś w pobliżu tych 8 odpowiedzi, ale kiedy otwierasz plik, zamknięta część nigdy nie powinna znajdować się w instrukcji try, ale albo w instrukcji last, albo w instrukcji with.
JC Rocamonde

Odpowiedzi:

733

Musisz zdefiniować typ wyjątku, który chcesz złapać. Napisz więc except Exception, e:zamiast except, e:ogólnego wyjątku (który i tak zostanie zarejestrowany).

Inną możliwością jest napisanie w ten sposób całego kodu try / oprócz:

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

w Pythonie 3.xi współczesnych wersjach Pythona 2.x except Exception as ezamiast 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
źródło
118
repr (e) daje ci wyjątek (i ciąg komunikatu); str (e) daje tylko ciąg komunikatu.
białobrody
11
logger.exception(e)Zamiast tego można użyć wyjątku dla rejestrowania wyjątku . Rejestruje wyjątek za pomocą traceback na tym samym logging.ERRORpoziomie.
mbdevpl,
1
@mbdevpl to nie wydaje się prawdą. Wygląda na to, że wywołuje str () z wyjątkiem: ideone.com/OaCOpO
KevinOrr
6
except Exception, e:zgłasza mi błąd składniowy w Pythonie 3. Czy jest to oczekiwane?
Charlie Parker,
27
@CharlieParker w piśmie Python3except Exception as e:
eumiro
281

Składnia nie jest już obsługiwana w Pythonie 3. Zamiast tego użyj następujących.

try:
    do_something()
except BaseException as e:
    logger.error('Failed to do something: ' + str(e))
sjtaheri
źródło
2
Właściwie powinieneś użyć logger.error ('Coś nie udało się zrobić:% s', str (e)) W ten sposób, jeśli twój poziom rejestratora jest powyżej błędu, nie interpoluje łańcucha.
avyfain
7
@avyfain - Jesteś w błędzie. Instrukcja logging.error('foo %s', str(e))zawsze będzie konwertowana ena ciąg. Aby osiągnąć to, czego oczekujesz, użyłbyś logging.error('foo %s', e)- pozwalając w ten sposób ramce rejestrowania wykonać (lub nie) konwersję.
Ron Dahlgren,
1
Możesz sprawdzić w REPL Pythona (tutaj z Pythonem 3.5.2 i ipython): zobacz moją treść tutaj
Ron Dahlgren
2
logger.exception(e)Zamiast tego można użyć wyjątku dla rejestrowania wyjątku . Rejestruje wyjątek za pomocą traceback na tym samym logging.ERRORpoziomie.
mbdevpl,
11
Uważaj na to except BaseExceptioni except Exceptionnie są na tym samym poziomie. except Exceptiondziała w Pythonie 3, ale KeyboardInterruptna przykład nie wyłapuje (co może być bardzo wygodne, jeśli chcesz mieć możliwość przerwania kodu!), ale BaseExceptionprzechwytuje każdy wyjątek. Zobacz ten link, aby uzyskać hierarchię wyjątków.
jeannej
41

Aktualizacja tego do czegoś prostszego dla programu rejestrującego (działa zarówno dla Pythona 2, jak i 3). Nie potrzebujesz modułu śledzenia.

import logging

logger = logging.Logger('catch_all')

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

To jest teraz stary sposób (choć nadal działa):

import sys, traceback

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

exc_value to komunikat o błędzie.

Berniey
źródło
2
To byłaby moja preferowana metoda. Wydaje mi się, że po prostu wydrukowanie ciągu jest przydatne do logowania, ale jeśli muszę coś zrobić z tymi informacjami, potrzebuję czegoś więcej niż tylko łańcucha.
sulimmesh
3
Nie musisz „importować śledzenia” w drugim przykładzie, prawda?
starikoff,
35

W niektórych przypadkach można użyć e.message lub e.messages .. Ale to nie działa we wszystkich przypadkach. W każdym razie bardziej bezpieczne jest użycie str (e)

try:
  ...
except Exception as e:
  print(e.message)
Slipstream
źródło
42
Problem z tym jest, na przykład, jeśli except Exception as ei eto IOError, można uzyskać e.errno, e.filenamei e.strerror, ale najwyraźniej nie ma e.message(przynajmniej w Pythonie 2.7.12). Jeśli chcesz uchwycić komunikat o błędzie, użyj str(e), jak w innych odpowiedziach.
epalm
@epalm Co się stanie, jeśli złapiesz IOError przed wyjątkiem?
Albert Thompson
@ HeribertoJuárez Po co łapać specjalne przypadki, podczas gdy możesz po prostu rzucić je na sznurek?
HosseyNJF
25

Jeśli chcesz mieć klasę błędu, komunikat o błędzie i dane śledzenia stosu (lub niektóre z nich), użyj sys.exec_info().

Minimalny działający kod z pewnym formatowaniem:

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)

Co daje następujące dane wyjściowe:

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

Funkcja sys.exc_info () podaje szczegółowe informacje na temat ostatniego wyjątku. Zwraca krotkę (type, value, traceback).

tracebackjest instancją obiektu traceback. Możesz sformatować ślad za pomocą podanych metod. Więcej można znaleźć w dokumentacji śledzenia .

Kavindu Dodanduwa
źródło
3
Użycie e.__class__.__name__ może również zwrócić klasę wyjątków.
kenorb
19

Możesz użyć logger.exception("msg")do rejestrowania wyjątku z funkcją śledzenia:

try:
    #your code
except Exception as e:
    logger.exception('Failed: ' + str(e))
Piotr
źródło
Przypadkowo e.msgjest ciągiem reprezentującym Exceptionklasę.
MarkHu
5
Lub po prostu logger.exception(e).
mbdevpl,
5

Możesz spróbować jawnie określić typ wyjątku BaseException. Będzie to jednak wychwytywać tylko pochodne wyjątku BaseException. Chociaż obejmuje to wszystkie wyjątki dostarczone w ramach implementacji, możliwe jest również podniesienie dowolnych klas starego stylu.

try:
  do_something()
except BaseException, e:
  logger.error('Failed to do something: ' + str(e))
Heini Høgnason
źródło
4

Użyj str (ex), aby wydrukować wykonanie

try:
   #your code
except ex:
   print(str(ex))
Niraj Trivedi
źródło
2

dla przyszłych walczących, w Pythonie 3.8.2 (i może kilka wcześniejszych wersjach), składnia jest następująca

except Attribute as e:
    print(e)
syter
źródło
1

Używając str(e)lub repr(e)do reprezentowania wyjątku, nie otrzymasz rzeczywistego śladu stosu, więc nie jest pomocne ustalenie, gdzie jest wyjątek.

Po przeczytaniu innych odpowiedzi i dokumentacji pakietu rejestrowania, następujące dwa sposoby świetnie sprawdzają się, aby wydrukować rzeczywiste dane śledzenia stosu w celu łatwiejszego debugowania:

użyj logger.debug()z parametremexc_info

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

posługiwać się logger.exception()

lub możemy bezpośrednio użyć logger.exception()do wydrukowania wyjątku.

try:
    # my code
exception SomeError as e:
    logger.exception(e)
jdhao
źródło