Respuestas:
Use logging.exception
desde el except:
controlador / bloque para registrar la excepción actual junto con la información de rastreo, precedida por un mensaje.
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
Ahora mirando el archivo de registro /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')
usted, debe escribir logger.exception('...')
para que esto funcione ...
Las exc_info
opciones de uso pueden ser mejores, sigue siendo advertencia o título de error:
try:
# coode in here
except Exception as e:
logging.error(e, exc_info=True)
exc_info=
se llama el kwarg; ¡Gracias!
logging.exception
Mi trabajo recientemente me encargó registrar todas las trazas / excepciones de nuestra aplicación. Probé numerosas técnicas que otros habían publicado en línea, como la anterior, pero me decidí por un enfoque diferente. Primordial traceback.print_exception
.
Tengo un escrito en http://www.bbarrows.com/ Eso sería mucho más fácil de leer, pero también lo pegaré aquí.
Cuando tuve la tarea de registrar todas las excepciones que nuestro software podría encontrar en la naturaleza, probé varias técnicas diferentes para registrar nuestros rastreos de excepciones de Python. Al principio pensé que el gancho de excepción del sistema python, sys.excepthook, sería el lugar perfecto para insertar el código de registro. Estaba intentando algo similar a:
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
Esto funcionó para el hilo principal, pero pronto descubrí que my sys.excepthook no existiría en ningún hilo nuevo que mi proceso comenzó. Este es un gran problema porque casi todo sucede en subprocesos en este proyecto.
Después de buscar en Google y leer mucha documentación, la información más útil que encontré fue del rastreador de problemas de Python.
La primera publicación en el hilo muestra un ejemplo funcional de que sys.excepthook
NO persiste en los hilos (como se muestra a continuación). Aparentemente este es el comportamiento esperado.
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()
Los mensajes en este hilo de Python Issue realmente resultan en 2 hacks sugeridos. Puede subclasificar Thread
y envolver el método de ejecución en nuestro propio intento, excepto el bloque para capturar y registrar excepciones o el parche de mono threading.Thread.run
para ejecutar en su propio intento, excepto bloquear y registrar las excepciones.
El primer método de subclasificación Thread
me parece menos elegante en su código, ya que tendría que importar y usar su Thread
clase personalizada EN TODAS PARTES donde quisiera tener un hilo de registro. Esto terminó siendo una molestia porque tuve que buscar en toda nuestra base de código y reemplazar todo lo normal Threads
con esta costumbre Thread
. Sin embargo, estaba claro qué Thread
estaba haciendo esto y sería más fácil para alguien diagnosticar y depurar si algo salía mal con el código de registro personalizado. Un hilo de registro personalizado podría verse así:
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")
El segundo método de parchear mono threading.Thread.run
es bueno porque podría ejecutarlo una vez justo después __main__
e instrumentar mi código de registro en todas las excepciones. Sin embargo, los parches de mono pueden ser molestos para depurar, ya que cambia la funcionalidad esperada de algo. El parche sugerido del rastreador de problemas de Python fue:
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
No fue hasta que comencé a probar mi registro de excepciones cuando me di cuenta de que estaba haciendo todo mal.
Para probar había colocado un
raise Exception("Test")
en algún lugar de mi código Sin embargo, envolver un método que llamó a este método fue un intento, excepto el bloque que imprimió el rastreo y se tragó la excepción. Esto fue muy frustrante porque vi que el rastreo se traía impreso a STDOUT pero no se registraba. Entonces decidí que un método mucho más fácil de registrar los rastreos era simplemente parchear el método que todo el código de Python usa para imprimir los mismos rastreos, traceback.print_exception. Terminé con algo similar a lo siguiente:
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
Este código escribe el rastreo en un Búfer de cadena y lo registra en ERROR de registro. Tengo un controlador de registro personalizado que configura el registrador 'customLogger' que toma los registros de nivel de ERROR y los envía a casa para su análisis.
add_custom_print_exception
no parece estar en el sitio al que se vinculó, y en su lugar hay un código final bastante diferente allí. ¿Cuál dirías que es mejor / más final y por qué? ¡Gracias!
logger.error(traceback.format_tb())
(o format_exc () si también desea la información de excepción).
Puede registrar todas las excepciones no detectadas en el hilo principal asignando un controlador a sys.excepthook
, quizás utilizando el exc_info
parámetro de las funciones de registro 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 los hilos de los usos del programa, sin embargo, a continuación, tenga en cuenta que los hilos creados usando threading.Thread
voluntad no de disparo sys.excepthook
cuando se produce una excepción no capturada dentro de ellos, como se señala en Edición 1.230.540 de seguimiento de incidencias de Python. Se han sugerido algunos hacks para evitar esta limitación, como parches de mono Thread.__init__
para sobrescribir self.run
con un run
método alternativo que envuelve el original en un try
bloque y llama sys.excepthook
desde dentro del except
bloque. Alternativamente, puede ajustar manualmente el punto de entrada para cada uno de sus hilos en try
/ except
usted mismo.
Los mensajes de excepción no capturados van a STDERR, por lo que, en lugar de implementar su registro en Python, podría enviar STDERR a un archivo utilizando el shell que esté utilizando para ejecutar su script Python. En un script Bash, puede hacer esto con la redirección de salida, como se describe en la guía BASH .
Agregue errores al archivo, otra salida al terminal:
./test.py 2>> mylog.log
Sobrescribir archivo con salida STDOUT y STDERR intercalada:
./test.py &> mylog.log
Lo que estaba buscando:
import sys
import traceback
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback_in_var = traceback.format_tb(exc_traceback)
Ver:
Puede obtener el rastreo utilizando un registrador, en cualquier nivel (DEPURACIÓN, INFORMACIÓN, ...). Tenga en cuenta que usando logging.exception
, el nivel es 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: :(
EDITAR:
Esto también funciona (usando Python 3.6)
logging.debug("Something went wrong", exc_info=True)
Aquí hay una versión que usa 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()}
lugar de {traceback.format_tb(stack)}
?
tal vez no tan elegante, pero más fácil:
#!/bin/bash
log="/var/log/yourlog"
/path/to/your/script.py 2>&1 | (while read; do echo "$REPLY" >> $log; done)
Aquí hay un ejemplo simple tomado de la documentación 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')