Logging uncaught exceptions in Python
如何通过
我意识到这样做的最好方法是:
1 2 3 4 | try: raise Exception, 'Throwing a boring exception' except Exception, e: logging.exception(e) |
但是我的情况是这样的,如果在没有捕获到异常时自动调用
这是一个完整的小例子,其中还包括一些其他技巧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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的日志记录模块来格式化异常。
-
使用带有示例处理程序的自定义记录器。这个更改未处理的异常转到stdout而不是stderr,但是你可以将这种相同样式的各种处理程序添加到logger对象中。
正如Ned指出的那样,每次引发异常并且未被捕获时都会调用
作为一个稻草人的例子:
1 2 3 4 5 6 7 | >>> import sys >>> def foo(exctype, value, tb): ... print 'My Error Information' ... print 'Type:', exctype ... print 'Value:', value ... print 'Traceback:', tb ... |
覆盖
1 | >>> sys.excepthook = foo |
提交明显的语法错误(省略冒号)并获取自定义错误信息:
1 2 3 4 5 | >>> def bar(a, b) My Error Information Type: <type 'exceptions.SyntaxError'> Value: invalid syntax (<stdin>, line 1) Traceback: None |
有关
如果未捕获异常,则将调用方法
When an exception is raised and uncaught, the interpreter calls sys.excepthook with three arguments, the exception class, exception instance, and a traceback object. In an interactive session this happens just before control is returned to the prompt; in a Python program this happens just before the program exits. The handling of such top-level exceptions can be customized by assigning another three-argument function to sys.excepthook.
为什么不:
1 2 3 4 5 6 7 8 9 10 11 | 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() |
以下是
1 2 3 4 5 | $ 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 |
这是
1 2 3 4 5 | $ python tb.py Traceback (most recent call last): File"tb.py", line 11, in <module> None() TypeError: 'NoneType' object is not callable |
唯一的区别是前者在第一行的开头有
以Jacinda的答案为基础,但使用记录器对象:
1 2 3 4 5 6 7 8 9 | 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 |
将您的应用程序条目调用包装在
1 2 | if __name__ == '__main__': main() |
做这个:
1 2 3 4 5 6 | if __name__ == '__main__': try: main() except Exception as e: logger.exception(e) raise |
也许你可以在模块的顶部做一些事情,将stderr重定向到一个文件,然后在底部登录该文件
1 2 3 4 5 6 | 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的答案给了我很好的起点,但我的程序在第一个异常时崩溃了。
我带来了一个定制的(和/或)改进的解决方案,它默默地记录用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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() |