setlevel - Registrando excepciones no detectadas en Python
python logging example to file (8)
Aquí hay un pequeño ejemplo completo que también incluye algunos otros trucos:
import sys
import logging
logger = logging.getLogger(__name__)
handler = logging.StreamHandler(stream=sys.stdout)
logger.addHandler(handler)
def handle_exception(exc_type, exc_value, exc_traceback):
if issubclass(exc_type, KeyboardInterrupt):
sys.__excepthook__(exc_type, exc_value, exc_traceback)
return
logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
sys.excepthook = handle_exception
if __name__ == "__main__":
raise RuntimeError("Test unhandled")
Ignore KeyboardInterrupt para que un programa de consola python pueda salir con Ctrl + C.
Confíe totalmente en el módulo de registro de Python para formatear la excepción.
Use un registrador personalizado con un controlador de ejemplo. Éste cambia la excepción no controlada para ir a stdout en lugar de a stderr, pero puede agregar todo tipo de manejadores en este mismo estilo al objeto logger.
¿Cómo se causan excepciones no detectadas a la salida a través del módulo de logging
lugar de stderr
?
Me doy cuenta de que la mejor manera de hacerlo sería:
try:
raise Exception, ''Throwing a boring exception''
except Exception, e:
logging.exception(e)
Pero mi situación es tal que sería realmente agradable si logging.exception(...)
se invoca automáticamente cada vez que una excepción no se logging.exception(...)
.
Aunque la respuesta de @gnu_lorien me dio un buen punto de partida, mi programa falla en la primera excepción.
Vine con una solución personalizada (y / o) mejorada, que registra silenciosamente Excepciones de funciones que están decoradas con @handle_error
.
import logging
__author__ = ''ahmed''
logging.basicConfig(filename=''error.log'', level=logging.DEBUG)
def handle_exception(exc_type, exc_value, exc_traceback):
import sys
if issubclass(exc_type, KeyboardInterrupt):
sys.__excepthook__(exc_type, exc_value, exc_traceback)
return
logging.critical(exc_value.message, exc_info=(exc_type, exc_value, exc_traceback))
def handle_error(func):
import sys
def __inner(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception, e:
exc_type, exc_value, exc_tb = sys.exc_info()
handle_exception(exc_type, exc_value, exc_tb)
finally:
print(e.message)
return __inner
@handle_error
def main():
raise RuntimeError("RuntimeError")
if __name__ == "__main__":
for _ in xrange(1, 20):
main()
Como señaló Ned, sys.excepthook
se invoca cada vez que se sys.excepthook
una excepción y no se detecta. La consecuencia práctica de esto es que en su código puede anular el comportamiento predeterminado de sys.excepthook
para hacer lo que desee (incluido el uso de logging.exception
).
Como ejemplo de hombre de paja:
>>> import sys
>>> def foo(exctype, value, tb):
... print ''My Error Information''
... print ''Type:'', exctype
... print ''Value:'', value
... print ''Traceback:'', tb
...
Anular sys.excepthook
:
>>> sys.excepthook = foo
Confirme el error de sintaxis obvio (omita los dos puntos) y obtenga información de error personalizada:
>>> def bar(a, b)
My Error Information
Type: <type ''exceptions.SyntaxError''>
Value: invalid syntax (<stdin>, line 1)
Traceback: None
Para obtener más información acerca de sys.excepthook
: http://docs.python.org/library/sys.html#sys.excepthook
El método sys.excepthook
se invocará si no se sys.excepthook
una excepción: http://docs.python.org/library/sys.html#sys.excepthook
Cuando se genera una excepción y no se detecta, el intérprete llama a sys.excepthook con tres argumentos, la clase de excepción, la instancia de excepción y un objeto de rastreo. En una sesión interactiva, esto sucede justo antes de que se devuelva el control al aviso; en un programa de Python esto sucede justo antes de que el programa salga. El manejo de tales excepciones de nivel superior se puede personalizar asignando otra función de tres argumentos a sys.excepthook.
Envuelva la llamada de entrada de la aplicación en un try...except
bloque para que pueda capturar y registrar (y quizás volver a subir) todas las excepciones no detectadas. Por ejemplo, en lugar de:
if __name__ == ''__main__'':
main()
Hacer esto:
if __name__ == ''__main__'':
try:
main()
except Exception as e:
logger.exception(e)
raise
Para construir sobre la respuesta de Jacinda, pero usando un objeto logger:
def catchException(logger, typ, value, traceback):
logger.critical("My Error Information")
logger.critical("Type: %s" % typ)
logger.critical("Value: %s" % value)
logger.critical("Traceback: %s" % traceback)
# Use a partially applied function
func = lambda typ, value, traceback: catchException(logger, typ, value, traceback)
sys.excepthook = func
Por qué no:
import sys
import logging
import traceback
def log_except_hook(*exc_info):
text = "".join(traceback.format_exception(*exc_info))
logging.error("Unhandled exception: %s", text)
sys.excepthook = log_except_hook
None()
Aquí está la salida con sys.excepthook
como se ve arriba:
$ python tb.py
ERROR:root:Unhandled exception: Traceback (most recent call last):
File "tb.py", line 11, in <module>
None()
TypeError: ''NoneType'' object is not callable
Aquí está la salida con el sys.excepthook
comentado:
$ python tb.py
Traceback (most recent call last):
File "tb.py", line 11, in <module>
None()
TypeError: ''NoneType'' object is not callable
La única diferencia es que el primero tiene ERROR:root:Unhandled exception:
al comienzo de la primera línea.
Tal vez podrías hacer algo en la parte superior de un módulo que redireccione stderr a un archivo, y luego registrar ese archivo en la parte inferior
sock = open(''error.log'', ''w'')
sys.stderr = sock
doSomething() #makes errors and they will log to error.log
logging.exception(open(''error.log'', ''r'').read() )