学习 python logging(6): 用代码定义 Logger 的流程

在之前的章节有介绍,我们有三种方式去定义 Logger, 这一节来看一下用代码来定义的实际过程。

logging.getLogger :

1 定义如下:

def getLogger(name=None):
    """
    Return a logger with the specified name, creating it if necessary.

    If no name is specified, return the root logger.
    """
    if name:
        return Logger.manager.getLogger(name)
    else:
        return root

可以看到,实际上调用了 Logger.manager.getLogger(name)Logger 中 的 manager 这一类变量是什么? 在 logging.__init__.py这个文件中,有声明:

root = RootLogger(WARNING)
Logger.root = root
Logger.manager = Manager(Logger.root)

接下来看 Manager.

2. Manager

Manager 的声明如下:

class Manager(object):
    """
    There is [under normal circumstances] just one Manager instance, which
    holds the hierarchy of loggers.
    """
    def __init__(self, rootnode):
        """
        Initialize the manager with the root node of the logger hierarchy.
        """
        self.root = rootnode
        self.disable = 0
        self.emittedNoHandlerWarning = False
        self.loggerDict = {}
        self.loggerClass = None
        self.logRecordFactory = None

可以注释来看, Manager 其实是保存了logger的层级信息。

再看 Manager.getLogger():

    def getLogger(self, name):
        """
        Get a logger with the specified name (channel name), creating it
        if it doesn't yet exist. This name is a dot-separated hierarchical
        name, such as "a", "a.b", "a.b.c" or similar.

        If a PlaceHolder existed for the specified name [i.e. the logger
        didn't exist but a child of it did], replace it with the created
        logger and fix up the parent/child references which pointed to the
        placeholder to now point to the logger.
        """
        rv = None
        if not isinstance(name, str):
            raise TypeError('A logger name must be a string')
        _acquireLock()
        try:
            if name in self.loggerDict:
                rv = self.loggerDict[name]
                if isinstance(rv, PlaceHolder):
                    ph = rv
                    rv = (self.loggerClass or _loggerClass)(name)
                    rv.manager = self
                    self.loggerDict[name] = rv
                    self._fixupChildren(ph, rv)
                    self._fixupParents(rv)
            else:
                rv = (self.loggerClass or _loggerClass)(name)
                rv.manager = self
                self.loggerDict[name] = rv
                self._fixupParents(rv)
        finally:
            _releaseLock()
        return rv
  1. 从注释中可以看出: getLogger 的作用是:根据 name 来获取 Logger, 如果已经有对应的 Logger 了,就直接取用已有的,如果没有,就生成一个。关于 name, 可以是以 . 分割以分出父子层级关系。在 getLogger 中,会修正层级关系。

  2. 代码中 self.loggerDict 用来存储 nameLogger 实例的关系。

  3. 代码中加了线程的 RLock 锁,说明是线程安全的。

这样就获取了一个 Logger 实例。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章