向sys.excepthook添加函数
假设我有这样的代码,它会把未处理的错误发送到 logging.critical()
:
import sys
def register_handler():
orig_excepthook = sys.excepthook
def error_catcher(*exc_info):
import logging
log = logging.getLogger(__name__)
log.critical("Unhandled exception", exc_info=exc_info)
orig_excepthook(*exc_info)
sys.excepthook = error_catcher
这个方法是有效的:
import logging
logging.basicConfig()
register_handler()
undefined() # logs, then runs original excepthook
但是如果 register_handler()
被调用多次,就会导致多个 error_catcher
被依次调用,这样日志信息就会出现好几次。
我能想到一些方法来解决这个问题,但都不是特别好(比如检查 sys.excepthook
是否是 error_catcher 函数,或者在模块中使用一个 "have_registered" 属性来避免重复注册)。
有没有推荐的解决方案呢?
5 个回答
3
如果你把问题中的代码放到一个模块里,你可以多次导入这个模块,但它的代码只会在第一次导入的时候执行。
4
你可以先检查一下 sys.excepthook
是否还是一个内置函数,然后再注册你的处理程序:
>>> import sys, types
>>> isinstance(sys.excepthook, types.BuiltinFunctionType)
True
>>> sys.excepthook = lambda x: x
>>> isinstance(sys.excepthook, types.BuiltinFunctionType)
False
2
在模块级别设置一个“钩子是否已经注册”的变量,似乎是最简单、最可靠的方法。
其他可能的解决方案在某些(相对不常见的)情况下会出问题——如果一个应用程序注册了自定义的 excepthook
,那么检查 sys.excepthook
是否是内置函数就会失败;在函数定义时存储原始的 excepthook
会覆盖后面注册的 excepthook
函数。
import sys
_hook_registered = False
def register_handler(force = False):
global _hook_registered
if _hook_registered and not force:
return
orig_excepthook = sys.excepthook
def error_catcher(*exc_info):
import logging
log = logging.getLogger(__name__)
log.critical("Unhandled exception", exc_info=exc_info)
orig_excepthook(*exc_info)
sys.excepthook = error_catcher
_hook_registered = True