如何通过 logging 模块而不是 stderr 导致未捕获的异常输出?
logging
stderr
我意识到这样做的最好方法是:
try: raise Exception, 'Throwing a boring exception' except Exception, e: logging.exception(e)
但是我的情况是这样的,如果在没有捕获到异常的情况下自动调用 logging.exception(...) ,那将是非常好的 .
logging.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: .
ERROR:root:Unhandled exception:
以Jacinda的答案为基础,但使用 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
将您的应用程序条目调用包装在 try...except 块中,这样您就可以捕获并记录(并可能重新引发)所有未捕获的异常 . 例如 . 代替:
try...except
if __name__ == '__main__': main()
做这个:
if __name__ == '__main__': try: main() except Exception as e: logger.exception(e) raise
正如Ned指出的那样,每次引发异常并且未被捕获时都会调用 sys.excepthook . 这样做的实际意义是,在您的代码中,您可以覆盖 sys.excepthook 的默认行为,以执行您想要的任何操作(包括使用 logging.exception ) .
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://docs.python.org/library/sys.html#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的日志记录模块来格式化异常 .
将自定义 Logger 与示例处理程序一起使用 . 这个更改未处理的异常以转到stdout而不是stderr,但是您可以将相同样式的各种处理程序添加到logger对象 .
如果未捕获异常,将调用方法 sys.excepthook :http://docs.python.org/library/sys.html#sys.excepthook
当引发异常并且未被捕获时,解释器使用三个参数调用sys.excepthook,异常类,异常实例和回溯对象 . 在交互式会话中,这发生在控制返回到提示之前;在Python程序中,这发生在程序退出之前 . 可以通过为sys.excepthook分配另一个三参数函数来自定义这种顶级异常的处理 .
也许你可以在模块的顶部做一些事情,将stderr重定向到一个文件,然后在底部登录该文件
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() )
虽然@ gnu_lorien的答案给了我很好的起点,但我的程序在第一个异常时崩溃了 .
我带来了一个定制的(和/或)改进的解决方案,它可以自动记录用 @handle_error 修饰的函数的异常 .
@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()
8 回答
为什么不:
如上所示,这是
sys.excepthook
的输出:这是
sys.excepthook
注释掉的输出:唯一的区别是前者在第一行的开头有
ERROR:root:Unhandled exception:
.以Jacinda的答案为基础,但使用 Logger 对象:
将您的应用程序条目调用包装在
try...except
块中,这样您就可以捕获并记录(并可能重新引发)所有未捕获的异常 . 例如 . 代替:做这个:
正如Ned指出的那样,每次引发异常并且未被捕获时都会调用
sys.excepthook
. 这样做的实际意义是,在您的代码中,您可以覆盖sys.excepthook
的默认行为,以执行您想要的任何操作(包括使用logging.exception
) .作为一个稻草人的例子:
覆盖
sys.excepthook
:提交明显的语法错误(省略冒号)并获取自定义错误信息:
有关
sys.excepthook
的更多信息:http://docs.python.org/library/sys.html#sys.excepthook这是一个完整的小例子,其中还包括一些其他技巧:
忽略KeyboardInterrupt,以便控制台python程序可以使用Ctrl C退出 .
完全依靠python的日志记录模块来格式化异常 .
将自定义 Logger 与示例处理程序一起使用 . 这个更改未处理的异常以转到stdout而不是stderr,但是您可以将相同样式的各种处理程序添加到logger对象 .
如果未捕获异常,将调用方法
sys.excepthook
:http://docs.python.org/library/sys.html#sys.excepthook也许你可以在模块的顶部做一些事情,将stderr重定向到一个文件,然后在底部登录该文件
虽然@ gnu_lorien的答案给了我很好的起点,但我的程序在第一个异常时崩溃了 .
我带来了一个定制的(和/或)改进的解决方案,它可以自动记录用
@handle_error
修饰的函数的异常 .