Mon travail a récemment chargé de me connecter tous les retraçage/exceptions à partir de notre application. J'ai essayé de nombreuses techniques que d'autres avaient mis en ligne tel que celui ci-dessus, il s'installe sur une approche différente. Primordial traceback.print_exception
.
J'ai une écriture à http://www.bbarrows.com/ ce serait beaucoup plus facile à lire, mais Malade de le coller dans ici.
Lorsqu'ils sont chargés d'enregistrer toutes les exceptions que notre logiciel peut rencontrer dans la nature, j'ai essayé un certain nombre de techniques différentes pour vous connecter à notre python exception retraçage. Au début, je pensais que le python exception système de crochet, sys.excepthook serait l'endroit idéal pour insérer le code d'enregistrement. J'ai essayé 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
Il a travaillé pour le thread principal, mais j'ai vite constaté que le mon sys.excepthook n'existerait pas sur tous les nouveaux threads mon processus a commencé. C'est un énorme problème parce que la plupart de tout ce qui se passe dans les fils dans ce projet.
Après une recherche sur google et lire beaucoup de documentation renseignements les plus utiles que j'ai trouvé était de l'Python bug tracker.
Le premier post sur le thread montre un exemple de travail de l' sys.excepthook
PAS de persistance dans les threads (voir ci-dessous). Apparemment, c'est le 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 Python Problème de thread vraiment de résultat dans les 2 a suggéré de hacks. Soit la sous-classe Thread
et envelopper la méthode run dans notre propre essayer à l'exception de bloc dans le but de les attraper et de les consigner les exceptions ou monkey patch threading.Thread.run
à exécuter dans votre propre essayer à l'exception de bloquer les journaux et les exceptions.
La première méthode de sous-classement d' Thread
me semble être moins élégant dans votre code que vous auriez à l'importation et l'utilisation de votre coutume Thread
de la classe PARTOUT où vous voulais avoir un thread de journalisation. Cela a fini par être embêtant car j'ai dû chercher l'intégralité de notre base de code et de le remplacer tout à fait normal Threads
avec cette coutume Thread
. Cependant, il était clair que ce Thread
, et serait plus facile pour quelqu'un diagnostic et de débogage si quelque chose n'allait pas avec le custom logging code. Un custome thread de journalisation pourrait 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 monkey patching threading.Thread.run
est agréable parce que je pouvais juste l'exécuter une fois à droite après l' __main__
et l'instrument de mon code d'enregistrement dans toutes les exceptions. Monkey patching peut être gênant pour déboguer bien que l'évolution de la fonctionnalité attendue de quelque chose. L'proposé un patch à partir de l'Python outil de suivi a été:
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
Il n'était pas jusqu'à ce que j'ai commencé à tester mes enregistrement d'exception, j'ai réalisé que j'étais dans l'erreur.
Pour tester j'avais placé un
raise Exception("Test")
quelque part dans mon code. Cependant, l'enveloppant d'une méthode qui a appelé cette méthode a été d'essayer sauf bloc imprimé assurer la traçabilité et d'ingestion de l'exception. C'était très frustrant parce que j'ai vu le traceback apporter affichée sur la sortie standard, mais n'étant pas connecté. Il a été ensuite, j'ai décidé que la méthode la plus simple de l'enregistrement de l'retraçage était juste pour monkey patch la méthode que tous les code python utilise pour imprimer le retraçage eux-mêmes, traceback.print_exception.
Je me suis retrouvé avec quelque chose de similaire à la suivante:
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 le traceback à un Tampon de Chaîne et les journaux à la journalisation des ERREURS. J'ai un custom logging gestionnaire a mis sur pied la customLogger' enregistreur qui prend le niveau d'ERREUR de journaux et de les envoyer à la maison pour l'analyse.