Réponses:
À utiliser logging.exception
depuis le except:
gestionnaire / bloc pour consigner l'exception en cours avec les informations de trace, précédées d'un message.
import logging
LOG_FILENAME = '/tmp/logging_example.out'
logging.basicConfig(filename=LOG_FILENAME, level=logging.DEBUG)
logging.debug('This message should go to the log file')
try:
run_my_stuff()
except:
logging.exception('Got exception on main handler')
raise
Vous voyez maintenant le fichier journal, /tmp/logging_example.out
:
DEBUG:root:This message should go to the log file
ERROR:root:Got exception on main handler
Traceback (most recent call last):
File "/tmp/teste.py", line 9, in <module>
run_my_stuff()
NameError: name 'run_my_stuff' is not defined
logger = logging.getLogger('yourlogger')
vous devez écrire logger.exception('...')
pour que cela fonctionne ...
Les exc_info
options d' utilisation peuvent être meilleures, reste un avertissement ou un titre d'erreur:
try:
# coode in here
except Exception as e:
logging.error(e, exc_info=True)
exc_info=
s'appelle le kwarg; Merci!
logging.exception
Mon travail m'a récemment chargé de consigner tous les retraits / exceptions de notre application. J'ai essayé de nombreuses techniques que d'autres avaient mises en ligne comme celle ci-dessus, mais j'ai opté pour une approche différente. Remplacer traceback.print_exception
.
J'ai un article sur http://www.bbarrows.com/ Ce serait beaucoup plus facile à lire mais je vais le coller ici également.
Lorsque j'ai été chargé de consigner toutes les exceptions que notre logiciel pourrait rencontrer dans la nature, j'ai essayé un certain nombre de techniques différentes pour enregistrer nos traces d'exceptions python. Au début, j'ai pensé que le hook d'exception du système python, sys.excepthook, serait l'endroit idéal pour insérer le code de journalisation. J'essayais quelque chose de similaire à:
import traceback
import StringIO
import logging
import os, sys
def my_excepthook(excType, excValue, traceback, logger=logger):
logger.error("Logging an uncaught exception",
exc_info=(excType, excValue, traceback))
sys.excepthook = my_excepthook
Cela a fonctionné pour le thread principal, mais j'ai vite découvert que my sys.excepthook n'existerait pas sur les nouveaux threads démarrés par mon processus. C'est un problème énorme car presque tout se passe dans les threads de ce projet.
Après avoir cherché sur Google et lu beaucoup de documentation, les informations les plus utiles que j'ai trouvées provenaient du suivi des problèmes Python.
Le premier article sur le fil montre un exemple de travail du sys.excepthook
NON persistant entre les fils (comme indiqué ci-dessous). Apparemment, c'est un comportement attendu.
import sys, threading
def log_exception(*args):
print 'got exception %s' % (args,)
sys.excepthook = log_exception
def foo():
a = 1 / 0
threading.Thread(target=foo).start()
Les messages sur ce fil de discussion sur Python entraînent vraiment 2 hacks suggérés. Soit sous Thread
-classez et encapsulez la méthode run dans notre propre bloc try except afin de capturer et enregistrer les exceptions, soit dans le patch monkey threading.Thread.run
pour exécuter votre propre try except bloquer et enregistrer les exceptions.
La première méthode de sous-classification Thread
me semble moins élégante dans votre code car vous auriez à importer et utiliser votre Thread
classe personnalisée PARTOUT où vous vouliez avoir un fil de journalisation. Cela a fini par être un problème car j'ai dû rechercher toute notre base de code et remplacer tout normal Threads
par cette coutume Thread
. Cependant, ce que cela faisait était clair Thread
et il serait plus facile pour quelqu'un de diagnostiquer et de déboguer si quelque chose n'allait pas avec le code de journalisation personnalisé. Un thread de journalisation personnalisé peut ressembler à ceci:
class TracebackLoggingThread(threading.Thread):
def run(self):
try:
super(TracebackLoggingThread, self).run()
except (KeyboardInterrupt, SystemExit):
raise
except Exception, e:
logger = logging.getLogger('')
logger.exception("Logging an uncaught exception")
La deuxième méthode de patching de singe threading.Thread.run
est agréable car je pourrais l'exécuter une fois juste après __main__
et instrumenter mon code de journalisation dans toutes les exceptions. Le correctif de singe peut être ennuyeux à déboguer car il change la fonctionnalité attendue de quelque chose. Le correctif suggéré par le suivi des problèmes Python était:
def installThreadExcepthook():
"""
Workaround for sys.excepthook thread bug
From
http://spyced.blogspot.com/2007/06/workaround-for-sysexcepthook-bug.html
(https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1230540&group_id=5470).
Call once from __main__ before creating any threads.
If using psyco, call psyco.cannotcompile(threading.Thread.run)
since this replaces a new-style class method.
"""
init_old = threading.Thread.__init__
def init(self, *args, **kwargs):
init_old(self, *args, **kwargs)
run_old = self.run
def run_with_except_hook(*args, **kw):
try:
run_old(*args, **kw)
except (KeyboardInterrupt, SystemExit):
raise
except:
sys.excepthook(*sys.exc_info())
self.run = run_with_except_hook
threading.Thread.__init__ = init
Ce n'est que lorsque j'ai commencé à tester ma journalisation des exceptions que j'ai réalisé que tout allait mal.
Pour tester j'avais placé un
raise Exception("Test")
quelque part dans mon code. Cependant, encapsuler une méthode qui appelait cette méthode était un bloc try except qui imprimait le traçage et avalait l'exception. C'était très frustrant car j'ai vu le traçage apporter imprimé à STDOUT mais ne pas être journalisé. C'est alors que j'ai décidé qu'une méthode beaucoup plus simple de journalisation des retraits était simplement de corriger la méthode utilisée par tout le code python pour imprimer les retraits eux-mêmes, traceback.print_exception. J'ai fini avec quelque chose de similaire à ce qui suit:
def add_custom_print_exception():
old_print_exception = traceback.print_exception
def custom_print_exception(etype, value, tb, limit=None, file=None):
tb_output = StringIO.StringIO()
traceback.print_tb(tb, limit, tb_output)
logger = logging.getLogger('customLogger')
logger.error(tb_output.getvalue())
tb_output.close()
old_print_exception(etype, value, tb, limit=None, file=None)
traceback.print_exception = custom_print_exception
Ce code écrit la traceback dans un tampon de chaîne et le consigne dans la journalisation ERROR. J'ai un gestionnaire de journalisation personnalisé configuré l'enregistreur «customLogger» qui prend les journaux de niveau ERREUR et les renvoie à la maison pour analyse.
add_custom_print_exception
ne semble pas être sur le site auquel vous avez lié, et à la place, il y a un code final assez différent. Selon vous, lequel est le meilleur / le plus définitif et pourquoi? Merci!
logger.error(traceback.format_tb())
(ou format_exc () si vous voulez aussi les informations d'exception).
Vous pouvez enregistrer toutes les exceptions non interceptées sur le thread principal en affectant un gestionnaire à sys.excepthook
, peut-être en utilisant le exc_info
paramètre des fonctions de journalisation de Python :
import sys
import logging
logging.basicConfig(filename='/tmp/foobar.log')
def exception_hook(exc_type, exc_value, exc_traceback):
logging.error(
"Uncaught exception",
exc_info=(exc_type, exc_value, exc_traceback)
)
sys.excepthook = exception_hook
raise Exception('Boom')
Si votre programme utilise des threads, cependant, notez que les threads créés avec threading.Thread
ne se déclencheront passys.excepthook
lorsqu'une exception non interceptée se produit à l'intérieur, comme indiqué dans le numéro 1230540 sur le suivi des problèmes de Python. Certains hacks ont été suggérés pour contourner cette limitation, comme le monkey-patching Thread.__init__
pour écraser self.run
avec une run
méthode alternative qui enveloppe l'original dans un try
bloc et appelle sys.excepthook
de l'intérieur du except
bloc. Alternativement, vous pouvez simplement envelopper manuellement le point d'entrée pour chacun de vos threads dans try
/ except
yourself.
Les messages d'exception non capturés vont à STDERR, donc au lieu d'implémenter votre journalisation en Python lui-même, vous pouvez envoyer STDERR vers un fichier en utilisant le shell que vous utilisez pour exécuter votre script Python. Dans un script Bash, vous pouvez le faire avec la redirection de sortie, comme décrit dans le guide BASH .
Ajouter les erreurs au fichier, autre sortie au terminal:
./test.py 2>> mylog.log
Écraser le fichier avec une sortie STDOUT et STDERR entrelacée:
./test.py &> mylog.log
Ce que je cherchais:
import sys
import traceback
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback_in_var = traceback.format_tb(exc_traceback)
Voir:
Vous pouvez récupérer le traceback à l'aide d'un logger, à n'importe quel niveau (DEBUG, INFO, ...). Notez qu'en utilisant logging.exception
, le niveau est ERROR.
# test_app.py
import sys
import logging
logging.basicConfig(level="DEBUG")
def do_something():
raise ValueError(":(")
try:
do_something()
except Exception:
logging.debug("Something went wrong", exc_info=sys.exc_info())
DEBUG:root:Something went wrong
Traceback (most recent call last):
File "test_app.py", line 10, in <module>
do_something()
File "test_app.py", line 7, in do_something
raise ValueError(":(")
ValueError: :(
ÉDITER:
Cela fonctionne aussi (en utilisant python 3.6)
logging.debug("Something went wrong", exc_info=True)
Voici une version qui utilise sys.excepthook
import traceback
import sys
logger = logging.getLogger()
def handle_excepthook(type, message, stack):
logger.error(f'An unhandled exception occured: {message}. Traceback: {traceback.format_tb(stack)}')
sys.excepthook = handle_excepthook
{traceback.format_exc()}
au lieu de {traceback.format_tb(stack)}
?
peut-être pas aussi élégant, mais plus facile:
#!/bin/bash
log="/var/log/yourlog"
/path/to/your/script.py 2>&1 | (while read; do echo "$REPLY" >> $log; done)
Voici un exemple simple tiré de la documentation de python 2.6 :
import logging
LOG_FILENAME = '/tmp/logging_example.out'
logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG,)
logging.debug('This message should go to the log file')