在 Python 中使用自定义跟踪记录异常

问题描述 投票:0回答:1

我正在开发一个Python程序,我需要记录所有异常(使用clickhouse上的自定义记录器),包括它们的上下文,以帮助调试。我没有简单地记录导致问题的最终函数,而是实现了一个 CustomException 类来存储整个异常路径,包括调用哪个 API、执行的 CRUD 操作以及任何相关参数等详细信息。

这是实现的简化版本:

class ExceptionSnippet:
    def __init__(self, file_name, func_name, msg, error_level):
        self.file_name = file_name
        self.func_name = func_name
        self.msg = msg
        self.error_level = error_level

class CustomException(BaseException):
    error_code: int
    value: Any
    traces: list[ExceptionSnippet] = []

    def __init__(self, arg=None):
        if isinstance(arg, CustomException):
            self.error_code = arg.error_code
            self.value = arg.value
            self.traces = arg.traces

虽然硬编码这个例外,但一切正常。但将其添加到所有 CRUD 函数中似乎有点结束了。

为了跨多个函数自动执行此异常日志记录过程,我创建了一个名为 auto_logger 的装饰器。该装饰器包装整个函数,拦截任何异常,并将它们添加到 CustomException 实例中。

def auto_logger(file_name, func_name, error_code):
    def decorator(func):
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except CustomException as ex:
                ex.traces.append(
                    ExceptionSnippet(
                        file_name, func_name, ex.traces[-1].func_name, 'trace'
                    ))
                raise ex
                # Handle CustomException
            except Exception as ex:
                error = CustomException()
                error.error_code = error_code
                error.traces.append(ExceptionSnippet(
                    file_name, func_name, ex.args[0], 'error'
                ))
                raise error 
        return wrapper
    return decorator

我遇到的问题是,将此装饰器应用于函数后,ex.traces 列表似乎保留了以前的异常,导致意外的行为。这是一个示例日志:

api/foo - crud_foo.change_bar - ERROR - Error validating bar [Error Code: 69420]
api/foo - crud_foo.change_bar - DEBUG - "some value"
api/foo - crud_foo.change_bar - TRACE - crud_foo.change_bar
api/foo - /prefix/change_bar - TRACE - change_bar 

第二次通话后:

api/foo - crud_foo.change_password - ERROR - Ошибка валидации пароля [Error Code: 69420]
api/foo - crud_foo.change_password - DEBUG - "some value"
api/foo - crud_foo.change_password - TRACE - change_password
api/foo - crud_foo.change_password - ERROR - Ошибка валидации пароля [Error Code: 69420]
api/foo - crud_foo.change_password - DEBUG - "some value"
api/foo - crud_foo.change_password - TRACE - change_password
api/foo - /prefix/change_bar - TRACE - change_bar 

其他调用也会发生同样的情况,成堆的旧日志位于新调用下方。

任何关于为什么 ex.traces 列表会累积以前的异常的见解将不胜感激。

实现装饰器后,异常开始堆积。我尝试删除

ex
error
。 我尝试重新初始化记录器(毕竟这不是问题)。

只有重新加载我的服务器才会将其返回到一个跟踪、第二个函数调用,之后仍然收集异常。

我希望有一些方法可以刷新内存,或者有一个装饰器可以在每次使用后重新初始化被装饰的函数或装饰器本身。

python exception logging python-decorators traceback
1个回答
0
投票

问我自己的问题:

except CustomException as ex
在装饰器中保留旧的
ex.traces
的原因是
wrapper
随着程序启动而初始化,并在整个生命周期中保持静态值。附加
ex.traces
会保留旧痕迹,因为它没有重新初始化。

__init__
期间我应该写
self.traces = []

class CustomException(BaseException):
    error_code: int
    value: Any
    traces: list[ExceptionSnippet] = []

    def __init__(self, arg=None):
    self.traces = []    # new
        if isinstance(arg, CustomException):
            self.error_code = arg.error_code
            self.value = arg.value
            self.traces = arg.traces

以前这不是问题,因为

try: ... except: ...
是函数的一部分,每次调用都会初始化 CustomException。

没想到会有这样的效果。对我来说是一个惊喜...

© www.soinside.com 2019 - 2024. All rights reserved.