说我有类似的东西,它会向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”属性以避免双重注册)
有推荐的方法吗?
答案 0 :(得分:3)
您可以在注册处理程序之前检查sys.excepthook
是否仍然是内置函数:
>>> import sys, types
>>> isinstance(sys.excepthook, types.BuiltinFunctionType)
True
>>> sys.excepthook = lambda x: x
>>> isinstance(sys.excepthook, types.BuiltinFunctionType)
False
答案 1 :(得分:2)
如果您将问题中的代码放入模块中,可以多次导入,但只会在第一次执行。
答案 2 :(得分:1)
如果使orig_excepthook
具有默认值的参数,则默认值在定义时固定一次。因此,对register_handler
的重复调用不会更改orig_excepthook
。
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()
register_handler()
register_handler()
undefined()
只生成一次log.critical
的调用。
答案 3 :(得分:1)
拥有模块级别“已经注册了钩子”变量似乎是最简单,最可靠的方法。
其他可能的解决方案会在某些(相当模糊)的情况下落空 -
如果应用程序注册了自定义sys.excepthook
,则检查excepthook
是否为内置函数将失败,在函数定义时存储原始excepthook
将使clobber随后注册异常函数。
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
答案 4 :(得分:0)
您应该使用sys.__excepthook__
[1]。
该对象在程序开始时包含sys.excepthook
[2]的原始值。
即
import sys
import logging
def register_handler():
log = logging.getLogger(__name__)
def error_catcher(*exc_info):
log.critical("Unhandled exception", exc_info=exc_info)
sys.__excepthook__(*exc_info)
sys.excepthook = error_catcher
参考:
1. https://docs.python.org/3/library/sys.html#sys.excepthook
2. https://docs.python.org/3/library/sys.html#sys.excepthook