在之前的章節有介紹,我們有三種方式去定義 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
-
從註釋中可以看出:
getLogger
的作用是:根據name
來獲取Logger
, 如果已經有對應的Logger
了,就直接取用已有的,如果沒有,就生成一個。關於name
, 可以是以.
分割以分出父子層級關係。在getLogger
中,會修正層級關係。 -
代碼中
self.loggerDict
用來存儲name
和Logger
實例的關係。 -
代碼中加了線程的
RLock
鎖,說明是線程安全的。
這樣就獲取了一個 Logger
實例。