在Python中logging未捕获的exception

你如何导致通过logging模块输出未捕获的exception而不是stderr

我意识到做到这一点的最好方法是:

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

但是我的情况是这样的,如果logging.exception(...)在exception未被捕获的时候自动调用,那将是非常好的

正如Ned所指出的, sys.excepthookexception被引发和未被捕获时, sys.excepthook被调用。 这个的实际意义是,在你的代码中,你可以重写sys.excepthook的默认行为来做你想做的任何事情(包括使用logging.exception )。

作为一个稻草人的例子:

 >>> import sys >>> def foo(exctype, value, tb): ... print 'My Error Information' ... print 'Type:', exctype ... print 'Value:', value ... print 'Traceback:', tb ... 

覆盖sys.excepthook

 >>> sys.excepthook = foo 

提交明显的语法错误(省略冒号)并取回自定义错误信息:

 >>> def bar(a, b) My Error Information Type: <type 'exceptions.SyntaxError'> Value: invalid syntax (<stdin>, line 1) Traceback: None 

有关sys.excepthook更多信息: http : sys.excepthook

这里有一个完整的小例子,其中还包括一些其他的技巧:

 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") 
  • 忽略KeyboardInterrupt所以一个控制台的python程序可以用Ctrl + C退出。

  • 完全依靠python的日志logging模块来格式化exception。

  • 使用示例处理程序的自定义logging器。 这个将未处理的exception更改为stdout而不是stderr,但可以将相同样式的各种处理程序添加到logging器对象。

如果一个exception未被捕获, sys.excepthook方法将被调用: http : sys.excepthook

当引发exception并且未被捕获时,解释器调用带有三个参数的sys.excepthook,exception类,exception实例和一个跟踪对象。 在交互式会话中,这恰好在控制返回提示之前发生; 在一个Python程序中,这个就在程序退出之前发生。 可以通过为sys.excepthook分配另一个三参数函数来自定义这些顶级exception的处理。

为什么不:

 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() 

这是sys.excepthook的输出, sys.excepthook所示:

 $ 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 

这里是sys.excepthook的输出注释掉了:

 $ python tb.py Traceback (most recent call last): File "tb.py", line 11, in <module> None() TypeError: 'NoneType' object is not callable 

唯一的区别是前者有ERROR:root:Unhandled exception:在第一行的开头。

build立Jacinda的答案,但使用logging器对象:

 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 

try...except块中包装你的应用程序入口调用,以便能够捕获和logging(也许是重新提升)所有未捕获的exception。 例如,而不是:

 if __name__ == '__main__': main() 

做这个:

 if __name__ == '__main__': try: main() except Exception as e: logger.exception(e) raise 

也许你可以在模块的顶部做一些事情,把stderrredirect到一个文件,然后在底部login这个文件

 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() ) 

尽pipe@ gnu_lorien的回答给了我很好的起点,但是我的程序在第一个exception时崩溃了。

我提供了一个定制(和/或)改进的解决scheme,它静静地logging用@handle_error装饰的函数的exception。

 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()