1

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

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

解决此类任务的最佳实践是什么,或者可能是好的 Python 库?

4

2 回答 2

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,包括来自上述任何范围的任何局部变量。您要求的唯一棘手的一点是“代码中的异常行”。traceback2.x 与 3.x 的详细信息略有不同(有关您需要了解的大部分内容,请参阅模块),但这里有一个 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))    
于 2013-04-17T20:11:48.103 回答
2

与其传递文件的路径,不如传递一个记录器。这样,装饰器的用户可以决定是否要登录到文件或控制台,或其他任何东西。记录器还将确定记录消息的格式。

您可能还需要一个exception参数来定义要捕获的异常类型。(下面,exception可以Exception采用Exceptions.


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)
于 2013-04-17T19:45:19.303 回答