2011-12-07 95 views
4

说我有这样的事情,这将unhanded例外logging.critical()添加功能sys.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() 

undefined() # logs, then runs original excepthook 

但是,如果register_handler()被多次调用,多error_catcher在一个链中被调用,并且日志消息出现好几次..

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

是否有推荐的方法来执行此操作?

回答

1

拥有一个模块级别的“钩子已经注册”变量似乎是这样做的最简单和最可靠的方式。

另一可能的解决方案将下降在某些(相当模糊)的情况下 - 检查所述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 
3

你可以只检查是否sys.excepthook仍然是内置功能注册您的处理程序之前:

>>> import sys, types 
>>> isinstance(sys.excepthook, types.BuiltinFunctionType) 
True 
>>> sys.excepthook = lambda x: x 
>>> isinstance(sys.excepthook, types.BuiltinFunctionType) 
False 
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

+0

黑魔法的东西,但我喜欢它:) –