向sys.excepthook添加功能

dbr*_*dbr 5 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
Run Code Online (Sandbox Code Playgroud)

有用:

import logging
logging.basicConfig()

register_handler()

undefined() # logs, then runs original excepthook
Run Code Online (Sandbox Code Playgroud)

但是,如果register_handler()多次error_catcher调用,则会在一个链中调用多个,并且记录消息会出现多次。

我可以想到几种方法,但是没有一种方法特别好(例如检查sys.excepthookerror_catcher函数是否是该函数,或者在模块上使用“ have_registered”属性以避免重复注册)

有推荐的方法吗?

dbr*_*dbr 2

拥有模块级“钩子已经注册”变量似乎是最简单、最可靠的方法。

其他可能的解决方案在某些(相当模糊)的情况下会失败 -sys.excepthook如果应用程序注册了一个自定义函数,则检查是否是内置函数将失败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
Run Code Online (Sandbox Code Playgroud)