在之前的章节有介绍,我们有三种方式去定义 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
实例。