學習 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 實例。

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