Registro de excepciones no detectadas en Python

¿Cómo se producen excepciones no detectadas para la salida a través del módulo de logging lugar de a stderr ?

Me doy cuenta de que la mejor manera de hacer esto sería:

 try: raise Exception, 'Throwing a boring exception' except Exception, e: logging.exception(e) 

Pero mi situación es tal que sería muy bueno si logging.exception(...) se invocara automáticamente siempre que no se logging.exception(...) una excepción.

Como señaló Ned, sys.excepthook se invoca cada vez que se produce una excepción y no se captura. La implicación práctica de esto es que en su código puede anular el comportamiento predeterminado de sys.excepthook para hacer lo que quiera (incluido el uso de logging.exception ).

Como ejemplo de un 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 

Cometa el error de syntax obvio (omita los dos puntos) y recupere la información de error personalizada:

 >>> def bar(a, b) My Error Information Type:  Value: invalid syntax (, line 1) Traceback: None 

Para obtener más información sobre sys.excepthook : http://docs.python.org/library/sys.html#sys.excepthook

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 progtwig de consola de python pueda salir con Ctrl + C.

  • Confíe completamente en el módulo de registro de Python para formatear la excepción.

  • Utilice un registrador personalizado con un controlador de ejemplo. Este cambia la excepción no controlada para ir a stdout en lugar de stderr, pero podría agregar todo tipo de controladores en este mismo estilo al objeto logger.

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 produce una excepción y no se captura, 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 a la solicitud; en un progtwig de Python esto sucede justo antes de que el progtwig salga. El manejo de tales excepciones de nivel superior se puede personalizar asignando otra función de tres argumentos a sys.excepthook.

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  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  None() TypeError: 'NoneType' object is not callable 

La única diferencia es que la primera tiene ERROR:root:Unhandled exception: al principio de la primera línea.

Para basarse en la respuesta de Jacinda, pero utilizando 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 

Envuelva la llamada de entrada de la aplicación en un try...except bloque para que pueda detectar y registrar (y quizás volver a boost) 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 

Tal vez usted podría hacer algo en la parte superior de un módulo que redirige 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() ) 

Aunque la respuesta de @gnu_lorien me dio un buen punto de partida, mi progtwig se bloquea 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()