2011-12-07 122 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

黑魔法的東西,但我喜歡它:) –