我试图用以下内容包装我的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
所以我的mapper / reducer函数看起来像:
@log_exceptions_to_sentry(SENTRY_ID, False)
def my_mapper_fn(item):
logging.info(item)
但它似乎不起作用。没有装饰器,我会找到INFO
item
的日志。但是,如果我放置装饰器,看起来映射器/缩减器功能根本不会被调用。
我希望能够轻松记录我的功能可能存在的任何错误,以便我可以修复它们,因为尝试通过AppEngine的日志追踪MapReduce几乎是不可能的。
我可以使用try ... except
块包装整个函数体,但装饰器会更干净。
答案 0 :(得分:0)
我相信装饰器结构存在问题。在partuclar,我想你想要替换
try:
return fn(*args, **kwargs)
与
try:
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_id
和raise_exception
,请将装饰器包装在另一个装饰器中。我们的想法是,在定义基本装饰器时,sentry_id
,raise_exception
和function
将提前定义并包含在其范围内。这应该看起来像
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)
答案 1 :(得分:0)
我不知道SENTRY_ID
或Client
是什么,因为您没有发布它。所以我自己做了。完全使用您的代码,一切似乎都按预期工作。我不确定你所看到的是什么行不通。
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