在Python中logging未捕获的exception
你如何导致通过logging
模块输出未捕获的exception而不是stderr
?
我意识到做到这一点的最好方法是:
try: raise Exception, 'Throwing a boring exception' except Exception, e: logging.exception(e)
但是我的情况是这样的,如果logging.exception(...)
在exception未被捕获的时候自动调用,那将是非常好的 。
正如Ned所指出的, sys.excepthook
exception被引发和未被捕获时, 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()