2014-05-01 24 views
4

我試圖總結我的映射器/減速功能的東西,如:在MapReduce mapper/reducer函數中使用裝飾器?

def log_exceptions_to_sentry(sentry_id, raise_exception): 
    def decorator(fn): 
     def wrapper(*args, **kwargs): 
      try: 
       return fn(*args, **kwargs) 
      except Exception, e: 
       client = Client(sentry_id) 
       client.captureException(
        exc_info=sys.exc_info()) 
       if raise_exception: 
        raise e 
     return wrapper 
    return decorator 

所以我的映射器/減速功能樣子:

@log_exceptions_to_sentry(SENTRY_ID, False) 
def my_mapper_fn(item): 
    logging.info(item) 

但它似乎並沒有工作。沒有裝飾者,我會發現INFO日誌item。但是,如果我把裝飾器,似乎映射器/減速器功能根本不會被調用。

我希望能夠輕鬆記錄我的函數可能有的任何錯誤,所以我可以修復它們,因爲試圖通過AppEngine的日誌追蹤MapReduce幾乎是不可能的。

我可以用try ... except塊封裝整個函數體,但是裝飾器會更乾淨。

+0

不要說'養e'只說'raise',否則拋出異常一個新的回溯。 – Daniel

+1

不要在decorator-call後面加上:這是一個語法錯誤 – Daniel

+0

糟糕,謝謝Daniel。 – john2x

回答

0

我相信你有一個裝飾器結構的問題。在partuclar,我想你想與

try: 
    fn(*args, **kwargs) 

我錯過了一些功能來測試它來取代

try: 
    return fn(*args, **kwargs) 

,但你可以在這裏看到的簡化裝飾的例子,如果你想運行一個:http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/

嘗試這樣的事情,以確保您的代碼工作,然後嘗試後更復雜的參數化版本:

sentry_id = id 
raise_exception = 1 

def basic_decorator(function): 
    global sentry_id, raise_exception 
    def wrapper(*args,**kwargs): 
     try: 
      function(*args,**kwargs) 
     except Exception, e: 
      client = Client(sentry_id) 
      client.captureException(exc_info=sys.exc_info()) 
      if raise_exception: 
       raise 
    return wrapper 

@basic_decorator 
def my_mapper_fn(item): 
    logging.info(item) 

要參數化sentry_idraise_exception,請將裝飾器包裝在另一個裝飾器中。這個想法是,當定義基本裝飾器時,將提前定義sentry_id,raise_exceptionfunction,並將其包含在其範圍內。這應該是這個樣子

def log_exceptions_to_sentry(sentry_id,raise_exception=1): 
    def basic_decorator(function): 
     def wrapper(*args, **kwargs): 
      try: 
       function(*args,**kwargs) 
      except Exception, e: 
       client = Client(sentry_id) 
       client.captureException(exc_info=sys.exc_info()) 
       if raise_exception: 
        raise 

     return wrapper 
    return basic_decorator 

@log_exceptions_to_sentry(SENTRY_ID,RAISE_EXCEPTION) 
def my_mapper_fn(item): 
    logging.info(item) 
+0

因此,在你的例子中,你如何從'x = my_mapper_fn(item)'得到返回值?在你的情況下,x將永遠是None,因爲你沒有返回'fn(* args,** kwargs)'的值。 – snapshoe

+0

@snapshoe,你是對的。我試圖從問題中顯示'logging.info'示例,該示例不使用返回值。並非Python中的所有函數都使用return語句。 無論如何,裝飾器結構的工作原理是讓你可以定義你想要的任何基礎函數。 – statueofmike

+0

@ john2x,我的例子是否適合你? – statueofmike

0

我不知道是什麼SENTRY_IDClient是,因爲你沒有張貼。所以我做了我自己的。確切地使用你的代碼,一切似乎按預期工作。我不確定你所看到的是不正確的。

SENTRY_ID = 1 
class Client(object): 
    def __init__(self, sentry_id): pass 
    def captureException(self, **kwargs): 
     print('captureException, ', kwargs['exc_info']) 

def log_exceptions_to_sentry(sentry_id, raise_exception): 
    def decorator(fn): 
     def wrapper(*args, **kwargs): 
      try: 
       return fn(*args, **kwargs) 
      except Exception as e: 
       client = Client(sentry_id) 
       client.captureException(
        exc_info=sys.exc_info()) 
       if raise_exception: 
        raise e 
     return wrapper 
    return decorator 

def fn(item): 
    logging.debug(item) 
    logging.info(item) 
    logging.error(item) 

@log_exceptions_to_sentry(SENTRY_ID, False) 
def my_mapper_fn(item): 
    logging.debug(item) 
    logging.info(item) 
    logging.error(item) 
    return 1 

@log_exceptions_to_sentry(SENTRY_ID, False) 
def my_mapper_fn2(item): 
    raise Exception() 

logging.basicConfig(
    level = logging.INFO, 
    format = '%(levelname)s:%(name)s:%(message)s', 
    #format = '%(message)s', 
) 

x = fn({'a':1}) 
print(x) 
x = my_mapper_fn({'b':2}) 
print(x) 
x = my_mapper_fn2({'c':3}) 
print(x) 

輸出:

INFO:root:{'a': 1} 
ERROR:root:{'a': 1} 
None 
INFO:root:{'b': 2} 
ERROR:root:{'b': 2} 
1 
captureException, (<type 'exceptions.Exception'>, Exception(), <traceback object at 0x1813cf8>) 
None 
+0

嗯我試過這個,它也可以在控制檯上運行,它只是在通過AppEngine MapReduce庫運行時無法正常工作。此外,mapper/reducer功能「yield」值,而不是「返回」它們。 – john2x