Python日志记录使用一个公共的logger类mixin和类inheritan

2024-10-02 00:22:50 发布

您现在位置:Python中文网/ 问答频道 /正文

我想创建一个Python日志类,它可以作为日志配置的一种常见方式继承,但可以从父类中单独控制基类的日志级别。这类似于How to use python logging in multiple modules。vinaysajip使用LogMixin的answer非常接近。下面是我稍微修改过的版本。在

我的大多数类继承较小的类。例如:

文件名:LogMixin.py在

import logging, logging.config
import yaml
class LogMixin(object):
    __loggerConfigured = False
    @property
    def logger(self):
        if not self.__loggerConfigured:
            with open('log_config.yaml', 'rt') as f:
                config = yaml.load(f.read())
                logging.config.dictConfig(config)
            self.__loggerConfigured = True
        name = '.'.join([self.__class__.__name__])
        return logging.getLogger(name)

文件名:基准.py在

^{pr2}$

文件名:父级.py在

from Base import Base
class Parent(Base):
    def __init__(self):
        self.logger.debug("Debug Parent")
    def run_parent(self):
        self.logger.debug("Debug Running Parent")
        self.logger.info("Info Running Parent")

if __name__ == '__main__':
    my_parent = Parent()
    my_parent.run_base()
    my_parent.run_parent()

文件名:日志_配置.yaml在

---
version: 1
disable_existing_loggers: False

# Configuring the default (root) logger is highly recommended
root:
    level: WARNING
    handlers: [console]

# Configuration for logger set with logging.getLogger(NAME)
loggers:
    Base:
        level: INFO
        handlers: [console]
        propagate: no
    Parent:
        level: DEBUG
        handlers: [console]
        propagate: no

formatters:
    simple:
        format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"

handlers:
    console:
        class: logging.StreamHandler
        formatter: simple
        stream: ext://sys.stdout
...

我得到了常见日志记录配置的好处。但是,我想独立控制基本和父级的日志级别。通过上面的配置文件,我得到:

$ python Base.py                 
2015-03-16 00:06:23,716 - Base - INFO - Info Running Base
$ python Parent.py                
2015-03-16 00:06:19,682 - Parent - DEBUG - Debug Parent
2015-03-16 00:06:19,682 - Parent - DEBUG - Debug Running Base
2015-03-16 00:06:19,682 - Parent - INFO - Info Running Base
2015-03-16 00:06:19,682 - Parent - DEBUG - Debug Running Parent
2015-03-16 00:06:19,682 - Parent - INFO - Info Running Parent

我明白为什么我得到这个,我只有一个记录“父母”。不过,总的来说,我宁愿得到以下信息:

$ python Base.py                 
2015-03-16 00:06:23,716 - Base - INFO - Info Running Base
$ python Parent.py                
2015-03-16 00:06:19,682 - Parent - DEBUG - Debug Parent
2015-03-16 00:06:19,682 - Base - INFO - Info Running Base
2015-03-16 00:06:19,682 - Parent - DEBUG - Debug Running Parent
2015-03-16 00:06:19,682 - Parent - INFO - Info Running Parent

无调试相关通知基准.py).
甚至更好:

$ python Base.py                 
2015-03-16 00:06:23,716 - Base - INFO - Info Running Base
$ python Parent.py                
2015-03-16 00:06:19,682 - Parent - DEBUG - Debug Parent
2015-03-16 00:06:19,682 - Parent.Base - INFO - Info Running Base
2015-03-16 00:06:19,682 - Parent - DEBUG - Debug Running Parent
2015-03-16 00:06:19,682 - Parent - INFO - Info Running Parent

(注意名字是父级。基所以我可以看到遗产。) 用一个简单的LogMixin类就可以做到吗?在


Tags: namepydebugselfinfoconfigbaselogging
1条回答
网友
1楼 · 发布于 2024-10-02 00:22:50

一个metaclass更合适。当一个类被定义时,它将得到它自己的记录器。名称损坏确保每个类使用自己的记录器。在

import logging
import sys

logging.basicConfig(stream=sys.stdout)

class MetaBase(type):
    def __init__(cls, *args):
        super().__init__(*args)

        # Explicit name mangling
        logger_attribute_name = '_' + cls.__name__ + '__logger'

        # Logger name derived accounting for inheritance for the bonus marks
        logger_name = '.'.join([c.__name__ for c in cls.mro()[-2::-1]])

        setattr(cls, logger_attribute_name, logging.getLogger(logger_name))

class Base(metaclass=MetaBase):
    def __init__(self):
        self.__logger.error('init base')

    def func_base(self):
        self.__logger.error('func base')

class Parent(Base):
    def func_parent(self):
        self.__logger.error('func parent')

p = Parent()
p.func_base()
p.func_parent()

结果:

^{pr2}$

这种方法有一些额外的好处。在

  • 类记录器是在类定义中创建的,并通过直接的属性引用进行访问。避免属性和getLogger调用
  • 不需要记住只需要添加子类就可以继承

我已经简化了这个例子来演示这个关键概念。应该可以跨文件和配置文件工作。在

相关问题 更多 >

    热门问题