VeighNa量化社区
你的开源社区量化交易平台
Member
avatar
加入于:
帖子: 11
声望: 0

这是我写的装饰器类

class Logger:
    def __init__(self, name: str = '', filename: str = '', level=logging.INFO, mode: str = 'a', stream: bool = True, file: bool = True):
        pass

    def __call__(self, func):
    """call 接收的是函数的参数"""
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            logger = self.set_logger(func)
            setattr(func, 'logger', logger)
            return func(*args, **kwargs)
        return wrapper


    def set_logger(self, func):  # 通用的logger设置
        pass

现在我应用于各个类中是正常的

@Logger()
class Other:
      self.logger.info("hihi")    这是正常的,这个logger的设置已经在装饰器中设置好了。

但是,我把它应用于函数中就不行了。

@Logger()
def my_func():
   logger.info("0000")  这里就不行了。  装饰器没法为这个函数设置这个属性。怎么办?

现在想到的土方法只能是在函数外面另建立一个空类,然后函数的logger使用该空类的logger

Member
加入于:
帖子: 7
声望: 0

我在项目中也碰到了一个日志输出的问题,我是基于以前vnpy的日志引擎做了下修改,

@singleton  #自己写的单例装饰器
class LogEngine:
    """日志引擎"""
    # 日志级别
    LEVEL_DEBUG = logging.DEBUG
    LEVEL_INFO = logging.INFO
    LEVEL_WARN = logging.WARN
    LEVEL_ERROR = logging.ERROR
    LEVEL_CRITICAL = logging.CRITICAL

    def __init__(self, fileName=''):
        """
        初始化日志引擎
        :param fileName: 日志文件名,主要是测试用
        """


        self.logger = logging.getLogger()

        # 设置日志格式
        # self.formatter = logging.Formatter('%(asctime)s  %(levelname)s: %(message)s')
        self.formatter = logging.Formatter(
            '%(asctime)s  %(levelname)s: %(module)s.%(funcName)s %(lineno)d line   %(message)s')

        self.consoleHandler = None
        self.fileHandler = None

        # 设置日志级别
        self.setLogLevel()

        # 设置输出
        if globalSetting['logConsole']:
            self.addConsoleHandler()
        if globalSetting['logFile']:
            self.addFileHandler(fileName)
        # 添加NullHandler防止无handler的错误输出
        nullHandler = logging.NullHandler()
        self.logger.addHandler(nullHandler)

        self.initFunc()

        # 日志级别函数映射
        self.levelFunctionDict = {
            self.LEVEL_DEBUG: self.debug,
            self.LEVEL_INFO: self.info,
            self.LEVEL_WARN: self.warn,
            self.LEVEL_ERROR: self.error,
            self.LEVEL_CRITICAL: self.critical,
        }

    def setLogLevel(self,level=globalSetting["logLevel"]):
        """设置日志级别"""
        levelDict = {
            "debug": self.LEVEL_DEBUG,
            "info": self.LEVEL_INFO,
            "warn": self.LEVEL_WARN,
            "error": self.LEVEL_ERROR,
            "critical": self.LEVEL_CRITICAL,
        }

        self.level = levelDict.get(level, self.LEVEL_CRITICAL)
        # handler内输出级别可以单独设置,但是级别必须高于日志级别


        self.logger.setLevel(self.level)

    def addConsoleHandler(self):
        if not globalSetting["logActive"]:
            # 如果配置文件里没有开启日志记录,则不开启日志记录
            return
        """添加终端输出"""
        if not self.consoleHandler:
            self.consoleHandler = logging.StreamHandler()
            self.consoleHandler.setLevel(self.level)
            self.consoleHandler.setFormatter(self.formatter)
            self.logger.addHandler(self.consoleHandler)

    def delConsoleHandler(self):
        """移除终端显示"""
        if self.consoleHandler:
            self.logger.removeHandler(self.consoleHandler)
            self.consoleHandler = None


    def addFileHandler(self, filename=''):
        """添加文件输出"""
        if not globalSetting["logActive"]:
            # 如果配置文件里没有开启日志记录,则不开启日志记录
            return
        if not self.fileHandler:
            if not filename:
                filename = 'ft_' + datetime.now().strftime('%Y%m%d') + '.log'
            # filepath = getTempPath(filename)
            filepath = getLogPath(filename)
            self.fileHandler = logging.FileHandler(filepath)
            self.fileHandler.setLevel(self.level)
            self.fileHandler.setFormatter(self.formatter)
            self.logger.addHandler(self.fileHandler)

    def delFileHandler(self):
        """移除文件输出"""
        if self.fileHandler:
            self.logger.removeHandler(self.fileHandler)
            self.fileHandler = None

    def initFunc(self):
        """初始化各种记录方法"""
        self.debug = self.logger.debug
        self.info = self.logger.info
        self.warn = self.logger.warning
        self.error = self.logger.error
        self.critical = self.logger.critical
        self.exception = self.logger.exception
logger = LogEngine()

用的时候 就把它当一个模块使用 from *** import logger
logger.info(msg)

关于你的方法我做了下实验:

def func1():
    pass

setattr(func1,'b',1)

print(func1.b)

def func2():
    print(func2.b)

setattr(func2,'b',2)

func2()

def func3():
    print(b)

setattr(func3,'b',3)

func3()

func 1和2 是可以的
func3 就报错
不知道你的函数 采用:

@Logger()
def my_func():
   my_func.logger.info("0000")

这种方式行不行

Member
avatar
加入于:
帖子: 9
声望: 1

你的代码存在两个问题~~

  1. 类装饰器和函数装饰器是不同的东西。你应该分清楚自己到底是想写类修饰器,还是想写函数修饰器。
  2. 类里面的非静态函数可以访问到self,所以你可以用self.logger访问到专属于这个类的logger。
    但是全局函数并不可以访问到self,全局函数只能访函数参数,局部变量和全局变量。你要让第二个函数访问到logger,logger就应该是全局变量。
Member
avatar
加入于:
帖子: 11
声望: 0

q275343119 wrote:

我在项目中也碰到了一个日志输出的问题,我是基于以前vnpy的日志引擎做了下修改,

@singleton  #自己写的单例装饰器
class LogEngine:
    """日志引擎"""
    # 日志级别
    LEVEL_DEBUG = logging.DEBUG
    LEVEL_INFO = logging.INFO
    LEVEL_WARN = logging.WARN
    LEVEL_ERROR = logging.ERROR
    LEVEL_CRITICAL = logging.CRITICAL

    def __init__(self, fileName=''):
        """
        初始化日志引擎
        :param fileName: 日志文件名,主要是测试用
        """


        self.logger = logging.getLogger()

        # 设置日志格式
        # self.formatter = logging.Formatter('%(asctime)s  %(levelname)s: %(message)s')
        self.formatter = logging.Formatter(
            '%(asctime)s  %(levelname)s: %(module)s.%(funcName)s %(lineno)d line   %(message)s')

        self.consoleHandler = None
        self.fileHandler = None

        # 设置日志级别
        self.setLogLevel()

        # 设置输出
        if globalSetting['logConsole']:
            self.addConsoleHandler()
        if globalSetting['logFile']:
            self.addFileHandler(fileName)
        # 添加NullHandler防止无handler的错误输出
        nullHandler = logging.NullHandler()
        self.logger.addHandler(nullHandler)

        self.initFunc()

        # 日志级别函数映射
        self.levelFunctionDict = {
            self.LEVEL_DEBUG: self.debug,
            self.LEVEL_INFO: self.info,
            self.LEVEL_WARN: self.warn,
            self.LEVEL_ERROR: self.error,
            self.LEVEL_CRITICAL: self.critical,
        }

    def setLogLevel(self,level=globalSetting["logLevel"]):
        """设置日志级别"""
        levelDict = {
            "debug": self.LEVEL_DEBUG,
            "info": self.LEVEL_INFO,
            "warn": self.LEVEL_WARN,
            "error": self.LEVEL_ERROR,
            "critical": self.LEVEL_CRITICAL,
        }

        self.level = levelDict.get(level, self.LEVEL_CRITICAL)
        # handler内输出级别可以单独设置,但是级别必须高于日志级别


        self.logger.setLevel(self.level)

    def addConsoleHandler(self):
        if not globalSetting["logActive"]:
            # 如果配置文件里没有开启日志记录,则不开启日志记录
            return
        """添加终端输出"""
        if not self.consoleHandler:
            self.consoleHandler = logging.StreamHandler()
            self.consoleHandler.setLevel(self.level)
            self.consoleHandler.setFormatter(self.formatter)
            self.logger.addHandler(self.consoleHandler)

    def delConsoleHandler(self):
        """移除终端显示"""
        if self.consoleHandler:
            self.logger.removeHandler(self.consoleHandler)
            self.consoleHandler = None


    def addFileHandler(self, filename=''):
        """添加文件输出"""
        if not globalSetting["logActive"]:
            # 如果配置文件里没有开启日志记录,则不开启日志记录
            return
        if not self.fileHandler:
            if not filename:
                filename = 'ft_' + datetime.now().strftime('%Y%m%d') + '.log'
            # filepath = getTempPath(filename)
            filepath = getLogPath(filename)
            self.fileHandler = logging.FileHandler(filepath)
            self.fileHandler.setLevel(self.level)
            self.fileHandler.setFormatter(self.formatter)
            self.logger.addHandler(self.fileHandler)

    def delFileHandler(self):
        """移除文件输出"""
        if self.fileHandler:
            self.logger.removeHandler(self.fileHandler)
            self.fileHandler = None

    def initFunc(self):
        """初始化各种记录方法"""
        self.debug = self.logger.debug
        self.info = self.logger.info
        self.warn = self.logger.warning
        self.error = self.logger.error
        self.critical = self.logger.critical
        self.exception = self.logger.exception
logger = LogEngine()

用的时候 就把它当一个模块使用 from *** import logger
logger.info(msg)

关于你的方法我做了下实验:

def func1():
    pass

setattr(func1,'b',1)

print(func1.b)

def func2():
    print(func2.b)

setattr(func2,'b',2)

func2()

def func3():
    print(b)

setattr(func3,'b',3)

func3()

func 1和2 是可以的
func3 就报错
不知道你的函数 采用:

@Logger()
def my_func():
   my_func.logger.info("0000")

这种方式行不行

Member
avatar
加入于:
帖子: 11
声望: 0

要是能够把一个函数再包裹一层,变为一个类应该就可以了。
有搜到三言两语的,不知道是不是,看不懂。

© 2015-2022 上海韦纳软件科技有限公司
备案服务号:沪ICP备18006526号

沪公网安备 31011502017034号

【用户协议】
【隐私政策】
【免责条款】