将函数添加到sys.excepthook

时间:2011-12-07 12:41:44

标签: python coding-style exception-handling

说我有类似的东西,它会向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 个答案:

答案 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