захват сообщений об исключениях Python

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

Кажется, это не работает, я получаю синтаксическую ошибку, как правильно сделать это для записи всех видов исключений в файл

Hellnar
источник
2
Ваш отступ нарушен. И опустить ,после except.
Свен Марнач
3
@SvenMarnach, если вы опустите ,после except, вы получите global name 'e' is not defined, что не намного лучше, чем неправильный синтаксис.
Val
12
@Val: должно быть except Exception as eили except Exception, e, в зависимости от версии Python.
Свен Марнах
1
Вероятно, это где-то около этих 8 ответов, но когда вы открываете файл, закрывающая часть никогда не должна находиться внутри оператора try, но либо в операторе finally, либо в операторе with.
JC Rocamonde

Ответы:

734

Вы должны определить, какой тип исключения вы хотите поймать. Так что пишите except Exception, e:вместо except, e:общего исключения (оно все равно будет записано).

Другая возможность - написать весь код try / кроме этого:

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

в Python 3.x и современных версиях Python 2.x except Exception as eвместо 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
источник
118
repr (e) дает вам исключение (и строку сообщения); str (e) выдает только строку сообщения.
Белоус
11
В качестве альтернативы для регистрации исключений вы можете использовать logger.exception(e)вместо этого. Он будет регистрировать исключение с помощью traceback на том же logging.ERRORуровне.
mbdevpl
1
@mbdevpl это не похоже на правду. Кажется, он вызывает str () для исключения: ideone.com/OaCOpO
KevinOrr
6
except Exception, e:выдает синтаксическую ошибку мне в python 3. Это ожидается?
Чарли Паркер
27
@CharlieParker в Python3 writeexcept Exception as e:
eumiro
282

Синтаксис больше не поддерживается в Python 3. Вместо этого используйте следующее.

try:
    do_something()
except BaseException as e:
    logger.error('Failed to do something: ' + str(e))
sjtaheri
источник
2
На самом деле, вы должны использовать logger.error ('Не удалось что-то сделать:% s', str (e)). Таким образом, если ваш уровень ведения журнала выше ошибки, он не выполняет интерполяцию строк.
avyfain
7
@avyfain - Вы не правы. Инструкция logging.error('foo %s', str(e))всегда будет преобразована eв строку. Чтобы достичь того, что вы хотите, вы бы использовали logging.error('foo %s', e)- тем самым позволяя каркасу ведения журнала делать (или не делать) преобразование.
Рон Дальгрен
1
Вы можете проверить в python REPL (здесь с Python 3.5.2 и ipython): посмотрите мою суть здесь
Рон Дальгрен
2
В качестве альтернативы для регистрации исключений вы можете использовать logger.exception(e)вместо этого. Он будет регистрировать исключение с помощью traceback на том же logging.ERRORуровне.
mbdevpl
11
Остерегайтесь этого except BaseExceptionи except Exceptionне на одном уровне. except Exceptionработает в Python3, но, к примеру, он не перехватит KeyboardInterrupt(что может быть очень удобно, если вы хотите прервать ваш код!), тогда как BaseExceptionперехватывает любое исключение. Смотрите эту ссылку для иерархии исключений.
Жанна
41

Обновление этого до чего-то более простого для регистратора (работает как для Python 2 и 3). Вам не нужен модуль трассировки.

import logging

logger = logging.Logger('catch_all')

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

Это теперь старый способ (хотя все еще работает):

import sys, traceback

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

exc_value - это сообщение об ошибке.

berniey
источник
2
Это был бы мой предпочтительный метод. Полагаю, что простая запись строки полезна для регистрации, но если мне нужно что-то сделать с этой информацией, мне нужно больше, чем просто строка.
Сулиммеш
3
Вам не нужно импортировать traceback во втором примере, верно?
Старикофф
34

В некоторых случаях вы можете использовать e.message или e.messages . Но это работает не во всех случаях. В любом случае, более безопасно использовать str (e)

try:
  ...
except Exception as e:
  print(e.message)
Slipstream
источник
42
Проблема с этим есть, например, если вы except Exception as e, и eэто IOError, вы получите e.errno, e.filenameи e.strerror, но , видимо , нет e.message(по крайней мере , в Python 2.7.12). Если вы хотите перехватить сообщение об ошибке, используйте str(e), как в других ответах.
epalm
@epalm Что если вы поймаете ошибку IOError перед Exception?
Альберт Томпсон
@ HeribertoJuárez Зачем ловить особые случаи, когда вы можете просто привести его в строку?
HosseyNJF
25

Если вам нужен класс ошибок, сообщение об ошибке и трассировка стека (или некоторые из них), используйте sys.exec_info().

Минимальный рабочий код с некоторым форматированием:

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)

Что дает следующий вывод:

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

Функция sys.exc_info () предоставляет вам информацию о самом последнем исключении. Она возвращает кортеж (type, value, traceback).

tracebackявляется экземпляром объекта трассировки. Вы можете отформатировать трассировку с помощью предоставленных методов. Больше можно найти в документации по трассировке .

Кавинду Додандува
источник
3
Использование e.__class__.__name__ может также вернуть класс исключения.
Кенорб
19

Вы можете использовать logger.exception("msg")для регистрации исключений с помощью traceback:

try:
    #your code
except Exception as e:
    logger.exception('Failed: ' + str(e))
Питер
источник
По совпадению, e.msgэто строковое представление Exceptionкласса.
MarkHu
5
Или просто logger.exception(e).
mbdevpl
5

Вы можете попытаться указать тип BaseException явно. Тем не менее, это будет ловить только производные от BaseException. Хотя это включает в себя все предоставляемые реализацией исключения, возможно также вызвать произвольные классы старого стиля.

try:
  do_something()
except BaseException, e:
  logger.error('Failed to do something: ' + str(e))
Хейни Хоннасон
источник
4

Используйте str (ex) для печати execption

try:
   #your code
except ex:
   print(str(ex))
Нирадж Триведи
источник
2

для будущих борцов, в Python 3.8.2 (и, может быть, несколько версий до этого), синтаксис

except Attribute as e:
    print(e)
syter
источник
1

Используя str(e)или repr(e)для представления исключения, вы не получите фактическую трассировку стека, поэтому не полезно искать, где находится исключение.

После прочтения других ответов и документации по пакету журналирования следующие два способа отлично работают для печати реальной трассировки стека для упрощения отладки:

использовать logger.debug()с параметромexc_info

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

использование logger.exception()

или мы можем напрямую использовать logger.exception()для печати исключения.

try:
    # my code
exception SomeError as e:
    logger.exception(e)
jdhao
источник