import logging模块
注意:root默认的等级是warning。即如果使用root打印日志,必须将等级设置成大于或者等级此等级才能成功打印日志,否则日志不会被传递到logger中。(切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!切记!!!)
logging是一个包,其实当你使用
import logging
这个语句的时候加载的就是_init.py里面的代码,加载成功,系统会自动创建root的logger。也就是系统在加载的时候已经创建了root的logger。并且会在加载的时候创建logger管理器。用户管理logger相关的操作信息。
logging.warning解析
当你使用
logging.warning("this is a message")
的时候系统使用的root的logger,并非你自己自定义的logger信息。
logging模块的源码如下:
def warning(msg, *args, **kwargs):
"""
Log a message with severity 'WARNING' on the root logger. If the logger has
no handlers, call basicConfig() to add a console handler with a pre-defined
format.
"""
if len(root.handlers) == 0:
basicConfig()
root.warning(msg, *args, **kwargs)
源码解析:
当调用logging模块的warning的时候,会判断当前的root的logger是否存在handlers,如果不存在就会调用
basicConfig给root设置一个handler和formatter,然后在执行root.warning函数,打印日志信息。
如果您已经设置了root的 handlers,则直接执行root.warning打印日志信息。
logger.warning解析
核心源码:
def callHandlers(self, record):
"""
Pass a record to all relevant handlers.
Loop through all handlers for this logger and its parents in the
logger hierarchy. If no handler was found, output a one-off error
message to sys.stderr. Stop searching up the hierarchy whenever a
logger with the "propagate" attribute set to zero is found - that
will be the last logger whose handlers are called.
"""
c = self
found = 0
while c:
for hdlr in c.handlers:
found = found + 1
if record.levelno >= hdlr.level:
hdlr.handle(record)
if not c.propagate:
c = None #break out
else:
c = c.parent
if (found == 0):
if lastResort:
if record.levelno >= lastResort.level:
lastResort.handle(record)
elif raiseExceptions and not self.manager.emittedNoHandlerWarning:
sys.stderr.write("No handlers could be found for logger"
" \"%s\"\n" % self.name)
self.manager.emittedNoHandlerWarning = True
源码解析:
此处会自动判断当前到logger是否存在handlers,如果存在继续判断父级别是否存在,如果都存在并且self.propagate的值为1或者true,则父级别也会打印此日志。否则只有当前级别打印日志,
当然你也可以手动设置
logger.propagate=0或者False。这样日志就只会在当前的logger中打印,并不会自动传递到父级别
下面是测试代码
# -*- coding: utf-8 -*-
"""
@Time : 2020/1/6 12:04 下午
@Auth : charles.chai
@File :testlogger.py.py
@IDE :PyCharm
@Motto:ABC(Always Be Coding)
"""
import logging
class demo:
def __init__(self):
pass
def getlogger11(self, name):
logger = logging.getLogger(name)
logger.setLevel(level=logging.INFO)
handlers = logging.StreamHandler()
fmt = logging.Formatter(fmt="%(asctime)s %(name)s [%(levelname)s] %(message)s")
handlers.setFormatter(fmt=fmt)
logger.addHandler(handlers)
return logger
def no_handler(self,name):
logger=logging.getLogger(name)
handlers=logging.StreamHandler()
logger.addHandler(handlers)
return logger
if __name__ == '__main__':
t=demo()
logger1=t.getlogger11("test1")
logger2=t.no_handler("test1.test2")
logger2.propagate=1
logger2.warning("logger2.warning")
logging.warning("tee")
下面是运行结果:
logger2.warning
2020-01-12 15:13:06,311 test1.test2 [WARNING] logger2.warning
Process finished with exit code 0
查看是否能打印日志的判断源码如下:
def isEnabledFor(self, level):
"""
Is this logger enabled for level 'level'?
"""
if self.disabled:
return False
try:
return self._cache[level]
except KeyError:
_acquireLock()
if self.manager.disable >= level:
is_enabled = self._cache[level] = False
else:
is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
_releaseLock()
return is_enabled
//getEffectiveLevel返回当前的loggerlevel的等级,如果当前logger未设置等级,则使用父级别的等级,作为返回值,如果父级别也没有设置,则直接往上找,直到找到root的级别。并且返回。
def getEffectiveLevel(self):
"""
Get the effective level for this logger.
Loop through this logger and its parents in the logger hierarchy,
looking for a non-zero logging level. Return the first one found.
"""
logger = self
while logger:
if logger.level:
return logger.level
logger = logger.parent
return NOTSET
源码解析:
调用打印日志时都会自动传入一个等级,将传入的此等级跟当前logger设置的等级进行判断,是否>=当前的等级,如果是,则打印,否则不打印。