2015-05-07 30 views
2

我正在使用Google App Engine(GAE)上的python statsd library。不幸的是,當使用套接字時,GAE可能不時地增加ApplicationError: 4 Unknown error.。該錯誤是apiproxy_errors.ApplicationError如果裝飾器函數在庫中,我不能修改,我應該如何捕獲裝飾器函數中可引發的異常?

statsd客戶端已經設置爲捕獲socket.error,但不是插座可以在GAE上引發的ApplicationErrorhttps://github.com/jsocol/pystatsd/blob/master/statsd/client.py#L13

Timer__call__方法允許將其用作裝飾,像這樣::

 
from statsd import StatsClient 

statsd = StatsClient() 

@statsd.timer('myfunc') 
def myfunc(a, b): 
    """Calculate the most complicated thing a and b can do.""" 

我具體地說timer,它返回的Timer實例工作沒有簡單的修改Timer.__call__方法本身的能力,也簡單地趕上ApplicationError

我該如何編寫一個包裝或附加裝飾器,它仍然允許像@my_timer_wrapper('statsd_timer_name')這樣的乾淨裝飾,但是會捕獲可能在包裝/裝飾的timer方法中出現的其他異常?

這是在我的代碼庫中的基礎模塊,將在許多地方使用(無論我們想要什麼時間)。因此,雖然this SO answer可能工作,但我真的希望避免強制在我的代碼庫中使用@statsclient.timer自己在try-except塊中定義它們。

我想在做類似的以下內容:

 
def my_timer_wrapper(wrapped_func, *args, **kwargs): 
    @functools.wraps(wrapped_func) 
    class Wat(object): 
    def __call__(self, *args, **kwargs): 
     timer_instance = stats_client.timer(*args, **kwargs) 
     try: 
     return timer_instance.__call__(wrapped_func)(*args, **kwargs) 
     except Exception: 
     logger.warning("Caught exception", exc_info=True) 
     def foo(): 
      pass 
     return foo 

    return Wat() 

這將然後像使用:

 
@my_timer_wrapper('stastd_timer_name') 
def timed_func(): 
    do_work() 

是否有更好或更Python的方式?

+0

看起來像那個類可以用作上下文管理器,而不是在try/except中換行。 –

+0

你可以猴子補丁statsd。在appengine_config.py中執行修補,因此只需在代碼庫中執行一次即可。 –

回答

0

它看起來像是一個「儘可能簡單」的情況 添加額外嘗試的新裝飾器/您的計時器裝飾器周圍除外。

唯一的事情是,要被定義爲需要需要 2級嵌套函數參數的裝飾,幾乎總是讓他們 看起來很複雜,即使他們並不:

from functools import wraps 

def shielded_timer(statsd, 
        exceptions=(apiproxy_errors.ApplicationError), 
        name=None): 

    def decorator(func): 
     timer_decorator = statsd.timer(name or func.__name__) 
     new_func = timer_decorator(func) 
     @wraps(func) 
     def wrapper(*args, **kw): 
      try: 
       return new_func(*args, **kw) 
      except BaseException as error: 
       if isinstance (error, exceptions): 
        # Expected error (ApplicationError by default) ocurred 
        pass 
       else: 
        raise 
     return wrapper 
    return decorator 



##################### 
statsd = StatsClient() 
@shielded_timer(statsd) 
def my_func(a,b): 
    ... 

正如你可以看到它很容易,甚至可以包含額外的細節 - 在這種情況下,我已經在裝飾時配置了想要的異常,並且可以選擇在調用statsd.timer的 中自動使用裝飾函數的名稱。

相關問題