具有通用记录器类mixin和类继承的Python日志记录 [英] Python Logging with a common logger class mixin and class inheritance

查看:85
本文介绍了具有通用记录器类mixin和类继承的Python日志记录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个Python日志记录类,该类可以作为一种常用的日志记录配置方式继承,但又要从父类单独控制基类的日志记录级别.这类似于如何在多个模块中使用python登录 . Vinay Sajip的 answer 非常接近使用LogMixin.下面是我稍加修改的版本.

I would like to create a Python logging class that can be inherited as a common means of logging configuration, yet seperately control the logging level of the base class from the parent. This is similar to How to use python logging in multiple modules. The answer by Vinay Sajip to use a LogMixin is very close. Below is my slightly modified version.

我的大多数课程都继承了较小的课程.例如:

Most of my classes inherit smaller classes. For example:

文件名:LogMixin.py

filename: 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)

文件名:Base.py

filename: Base.py

from LogMixin import LogMixin
class Base(LogMixin):
    def __init__(self):
        self.logger.debug("Debug Base")
    def run_base(self):
        self.logger.debug("Debug Running Base")
        self.logger.info("Info Running Base")
if __name__ == '__main__':
    my_base = Base()
    my_base.run_base()         

文件名:Parent.py

filename: Parent.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()

文件名:log_config.yaml

filename: log_config.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
...

我从通用日志记录配置中受益.但是,我希望对Base和Parent的日志级别进行独立控制.使用上面的配置文件,我得到:

I get the benefits of the common logging configuration. However, I'd like independent control of the log levels for both Base and Parent. With the config file above, I get:

$ 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

我知道为什么得到这个,我只有一个记录器父母".但是,总的来说,我希望获得以下信息:

I understand why I get this, I only have one logger "Parent". However, in general, I'd rather get the following:

$ 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

(注意,没有与Base.py相关的DEBUG).
甚至更好:

(notice no DEBUG related to Base.py).
Or even better:

$ 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

(请注意,名称为Parent.Base,所以我可以看到继承.) 一个简单的LogMixin类有可能吗?

(Notice the name is Parent.Base so I can see the inheritance.) Is this possible with a single simple LogMixin class?

推荐答案

A 元类会更合适.定义类后,它将获得自己的记录器.名称修饰可确保每个类使用其自己的记录器.

A metaclass would be more appropriate. When a class is defined it will get its own logger. Name mangling ensures each class uses its own logger.

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()

结果:

ERROR:Base:init base
ERROR:Base:func base
ERROR:Base.Parent:func parent

这种方法在混入过程中还有其他好处.

This approach has a few additional benifites over mix in.

  • 每个类的记录器都是在类定义时创建的,并可以通过直接属性引用进行访问.避免属性和getLogger调用
  • 子类只需要继承基类,无需记住添加MixIn

我已经简化了示例以演示关键概念.应该可以跨文件使用,也可以与配置文件一起使用.

I've simplified the example to demonstrate the key concept. Should work across files and with a config file.

这篇关于具有通用记录器类mixin和类继承的Python日志记录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆