capture de message d'exception 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))

Cela ne semble pas fonctionner, j'obtiens une erreur de syntaxe, quelle est la bonne façon de le faire pour enregistrer toutes sortes d'exceptions dans un fichier

Hellnar
la source
2
Votre indentation est rompue. Et omettez l' ,après except.
Sven Marnach
3
@SvenMarnach, si vous omettez ce qui ,suit except, vous obtiendrez global name 'e' is not defined, ce qui n'est pas beaucoup mieux qu'une mauvaise syntaxe.
Val
12
@Val: Devrait être except Exception as eou except Exception, e, selon la version de Python.
Sven Marnach
1
C'est probablement quelque part autour de ces 8 réponses, mais lorsque vous ouvrez un fichier, la partie close ne doit jamais être à l'intérieur de l'instruction try, mais soit dans une instruction finally, soit enveloppée par une instruction with.
JC Rocamonde

Réponses:

734

Vous devez définir le type d'exception que vous souhaitez intercepter. Écrivez donc except Exception, e:au lieu de except, e:pour une exception générale (qui sera enregistrée de toute façon).

Une autre possibilité consiste à écrire l'intégralité de votre code try / except de cette façon:

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

dans Python 3.x et les versions modernes de Python 2.x utilisent except Exception as eau lieu de 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
la source
118
repr (e) vous donne l'exception (et la chaîne de message); str (e) ne donne que la chaîne de message.
whitebeard
11
Comme alternative à l'exception de journalisation, vous pouvez utiliser à la logger.exception(e)place. Il enregistrera l'exception avec traceback au même logging.ERRORniveau.
mbdevpl
1
@mbdevpl, cela ne semble pas être vrai. Il semble appeler str () à l'exception: ideone.com/OaCOpO
KevinOrr
6
except Exception, e:me renvoie une erreur de syntaxe en python 3. Est-ce attendu?
Charlie Parker
27
@CharlieParker en écriture Python3except Exception as e:
eumiro
282

La syntaxe n'est plus prise en charge dans python 3. Utilisez plutôt ce qui suit.

try:
    do_something()
except BaseException as e:
    logger.error('Failed to do something: ' + str(e))
sjtaheri
la source
2
En fait, vous devez utiliser logger.error ('Impossible de faire quelque chose:% s', str (e)) De cette façon, si le niveau de votre enregistreur est supérieur à l'erreur, il ne fait pas l'interpolation de chaîne.
avyfain
7
@avyfain - Vous vous trompez. L'instruction logging.error('foo %s', str(e))sera toujours convertie een chaîne. Pour réaliser ce que vous êtes, vous utiliseriez logging.error('foo %s', e)- permettant ainsi au cadre de journalisation de faire (ou non) la conversion.
Ron Dahlgren
1
Vous pouvez vérifier dans un REPL python (ici avec Python 3.5.2 et ipython): voir mon essentiel ici
Ron Dahlgren
2
Comme alternative à l'exception de journalisation, vous pouvez utiliser à la logger.exception(e)place. Il enregistrera l'exception avec traceback au même logging.ERRORniveau.
mbdevpl
11
Méfiez-vous de cela except BaseExceptionet except Exceptionne sont pas au même niveau. except Exceptionfonctionne en Python3, mais il n'interceptera pas KeyboardInterruptpar exemple (ce qui peut être très pratique si vous voulez être en mesure d'interrompre votre code!), alors qu'il BaseExceptionintercepte toute exception. Voir ce lien pour la hiérarchie des exceptions.
jeannej
41

Mise à jour de quelque chose de plus simple pour l'enregistreur (fonctionne pour python 2 et 3). Vous n'avez pas besoin de module de traceback.

import logging

logger = logging.Logger('catch_all')

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

C'est maintenant l'ancienne méthode (bien qu'elle fonctionne toujours):

import sys, traceback

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

exc_value est le message d'erreur.

berniey
la source
2
Ce serait ma méthode préférée. Le simple fait d'imprimer la chaîne est utile pour la journalisation, je suppose, mais si j'ai besoin de faire quoi que ce soit avec ces informations, j'ai besoin de plus qu'une simple chaîne.
sulimmesh
3
Vous n'avez pas besoin d '«importer traceback» dans le deuxième exemple, non?
starikoff
34

Il existe certains cas où vous pouvez utiliser l' e.message ou les e.messages .. Mais cela ne fonctionne pas dans tous les cas. Quoi qu'il en soit, le plus sûr est d'utiliser le str (e)

try:
  ...
except Exception as e:
  print(e.message)
Slipstream
la source
42
Le problème est, par exemple, si vous except Exception as eet eest un IOError, vous obtenez e.errno, e.filenameet e.strerror, mais apparemment pas e.message(au moins en Python 2.7.12). Si vous souhaitez capturer le message d'erreur, utilisez str(e), comme dans les autres réponses.
epalm
@epalm Que faire si vous interceptez l'IOError avant l'exception?
Albert Thompson,
@ HeribertoJuárez Pourquoi attraper des cas spéciaux alors que vous pouvez simplement le caster en chaîne?
HosseyNJF
25

Si vous voulez la classe d'erreur, le message d'erreur et la trace de pile (ou certains d'entre eux), utilisez sys.exec_info().

Code de travail minimal avec une mise en forme:

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)

Ce qui donne la sortie suivante:

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

La fonction sys.exc_info () vous donne des détails sur l'exception la plus récente. Il renvoie un tuple de (type, value, traceback).

tracebackest une instance de l'objet traceback. Vous pouvez formater la trace avec les méthodes fournies. Plus d'informations peuvent être trouvées dans la documentation traceback .

Kavindu Dodanduwa
la source
3
L'utilisation e.__class__.__name__ peut également renvoyer la classe d'exception.
kenorb
19

Vous pouvez utiliser logger.exception("msg")pour la journalisation des exceptions avec traceback:

try:
    #your code
except Exception as e:
    logger.exception('Failed: ' + str(e))
Peter
la source
Par coïncidence, e.msgest la représentation sous forme de chaîne de la Exceptionclasse.
MarkHu
5
Ou tout simplement logger.exception(e).
mbdevpl
5

Vous pouvez essayer de spécifier explicitement le type BaseException. Cependant, cela ne capturera que les dérivés de BaseException. Bien que cela comprenne toutes les exceptions fournies par l'implémentation, il est également possible d'élever des classes arbitraires à l'ancienne.

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

Utilisez str (ex) pour imprimer l'exception

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

pour les futurs lutteurs, en python 3.8.2 (et peut-être quelques versions avant cela), la syntaxe est

except Attribute as e:
    print(e)
syter
la source
1

En utilisant str(e)ou repr(e)pour représenter l'exception, vous n'obtiendrez pas la trace de pile réelle, il n'est donc pas utile de trouver où se trouve l'exception.

Après avoir lu les autres réponses et le doc du package de journalisation, les deux méthodes suivantes fonctionnent très bien pour imprimer la trace de la pile réelle pour un débogage plus facile:

utiliser logger.debug()avec paramètreexc_info

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

utilisation logger.exception()

ou nous pouvons directement utiliser logger.exception()pour imprimer l'exception.

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