用于非稳定函数的python日志异常装饰器

时间:2013-04-17 19:34:30

标签: python logging decorator

我想在问题函数中记录异常(html解析可变页面),所以我认为最好的解决方案是这里某种装饰器,它将异常记录到文件中,具有时间,异常类型,代码和函数调用中的异常行参数,有些像:

@exception_catch(log_path='example.log')
def example(x,y):
    raise Exception('123')

解决此类任务的最佳做法是什么,或者为此可能是好的python库?

2 个答案:

答案 0 :(得分:2)

不是将路径传递给文件,而是传递记录器。这样,装饰者的用户可以决定他是否想要记录到文件或控制台,或者其他什么。记录器还将确定记录消息的格式。

您可能还需要exception参数来定义要捕获的异常或异常类型。 (下面,exception可以使用ExceptionExceptions元组。


import logging

def catch_exception(exception=Exception, logger=logging.getLogger(__name__)):
    def deco(func):
        def wrapper(*args, **kwargs):
            try:
                result = func(*args, **kwargs)
            except exception as err:
                logger.exception(err)
            else:
                return result
        return wrapper
    return deco

@catch_exception()
def example(x,y):
    raise Exception('123')

logging.basicConfig(filename='/tmp/error.log', level=logging.DEBUG,
                    datefmt='%Y-%m-%d %H:%M:%S',
                    format='%(asctime)s %(module)s %(levelname)s: %(message)s')

example(1,2)

答案 1 :(得分:2)

你可能想做unutbu建议,因为它更灵活,最终也很简单。但是,如果您对logging的额外细节感到不知所措,请按以下步骤操作:

def exception_catch(log_path):
    def deco(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except Exception as e:
                with open(log_path, 'a') as log:
                    log.write('{} {} {} {} {}\n'.format(datetime.datetime.now(), 
                                                        type(e), e, args, kwargs))
                # This will return None on error, of course
        return wrapper
    return deco

当然,您可以将任何内容放入format,包括来自上述任何范围的任何局部变量。您要求的唯一棘手的一点是“代码中的异常行”。对于2.x与3.x的详细信息略有不同(请参阅traceback模块了解您需要知道的大部分内容),但这里有一个3.x示例,可以准确地提供您所要求的内容:

except Exception as e:
    filename, line, func, text = traceback.extract_stack(limit=1)[0]
    with open(log_path, 'a') as log:
        log.write('time: {} type: {} line: {} args: {}\n'.format(
            datetime.datetime.now(), 
            type(e),
            line,
            args))