创建日志记录 Class 包装器

Creating a Logging Class Wrapper

我正在尝试编写一个快速装饰器来管理各种功能的日志记录 returns。我不是很精通装饰器,所以你能提供的任何帮助都会很有帮助!

from functools import update_wrapper
from typing import Any, Optional
from logging import getLogger
from time import perf_counter
from datetime import datetime

class logger:

    def __init__(self, func:callable, response:str = "debug"):
        self.logger = getLogger()
        self.func = func
        self.response = response

        update_wrapper(self, func)

    def __call__(self, *args, **kwargs):
        return getattr(self, self.response)

    def debug(self, *args, **kwargs):
        self.logger.debug(f"Running {__name__} with id: {id(self)} at {datetime.now()}")
        start = perf_counter()
        value = self.func(*args, **kwargs)
        end = perf_counter()
        self.logger.debug(f"""Completed {__name__} with id: {id(self)} at {datetime.now()}.
            Total Time to run: {end - start:.6f}s""")
        return value

    def info(self, *args, **kwargs):
        self.logger.info(f"Running {__name__} at {datetime.now()}.")
        return self.func(*args, **kwargs)

@logger(response="debug")
def stuff(x):
    return x*x

stuff(2)

我收到的错误是:

TypeError: __init__() missing 1 required positional argument: 'func',

很明显,它不喜欢所需的可调用对象和响应要求。但是,我在所有其他基于 class 的装饰器设置中看到 func 需要作为 __init__ 的一部分被调用,而且我还看到您可以传递装饰器附加信息。我在这里做错了什么?

编辑:

getattr(self, self.response) 的目的是让 __call__ 返回的函数是 debuginfo 日志记录的函数。这允许我利用装饰器@logging 进行日志记录和调试,但根据装饰器中指定的响应值(即@logging(response="info"))产生两个不同的结果。

解决方案:

class logger:

    def __init__(self, response:str = "debug"):
        self.logger = getLogger()
        self.response = response

    def __call__(self, func:callable):
        update_wrapper(self, func)
        self.func = func
        return getattr(self, self.response)

    def debug(self, *args, **kwargs):
        self.logger.debug(f"Running {self.func.__name__} (type:{type(self.func)}) with id: {id(self)} at {datetime.now()}")
        start = perf_counter()
        value = self.func(*args, **kwargs)
        end = perf_counter()
        self.logger.debug(f"""Completed {self.func.__name__} with id: {id(self)} at {datetime.now()}.
            Total Time to run: {end - start:.6f}s""")
        return value

    def info(self, *args, **kwargs):
        self.logger.info(f"Running {self.func.__name__} at {datetime.now()}.")
        return self.func(*args, **kwargs)

我不知道您的代码应该做什么,尤其是(对我而言)不清楚应该将哪种参数传递给 getattr(self, self.response)(*args, **kwargs)。我这么说是为了了解装饰器的正确工作流程。

所以你的代码永远不会工作。这里有一些可能的装饰示例:

__call__方式:@logger(response="debug")

class logger_1:

    def __init__(self, response:str = "debug"):
       print(response)

    def __call__(self, func):
        self.func = func
        return self # ? depends on what are you doing

    def debug(self, *args, **kwargs):
        # ...

    def info(self, *args, **kwargs):
        #... 

@logger_1(response="debug")
def stuff(x):
    return x*x

更“抽象”的层次:@logger(response="debug").('some_parameter').debug_method

class logger_2:

    def __init__(self, response:str = "debug"):
       print(response)

    def __call__(self, *args, **kwargs):
       self.updated_response = getattr(self, self.response)(*args, **kwargs) # just an example
       return self

    def debug_method(self, func):
       self.func = func
       # ...
       return func

    def debug(self, *args, **kwargs):
        # ...

    def info(self, *args, **kwargs):
        #... 

@logger_2(response="debug")('some_parameter').debug_method
def stuff(x):
    return x*x

注意: logger_2(response="debug").('some_parameter').debug_method 没有接受参数,因为它等待目标函数 stuff

的“馈送”

这些是约束工作流的语法示例,因此在设计装饰器时需要小心