正在上一篇著作1万字详解 python logging日记模块 中,长远浅出的诠释了日记的基础道理与用法。但另有少许实质并无触及到,是以这篇著作动作上一篇著作的增加。
生气这两篇著作能助助你十足清楚日记模块的行使,正在名目中对日记的行使逛刃众余。上一篇还没看的倡导先浏览上一篇
1、为甚么子记载器没必要要修设日记等第也能够输出?
假如未正在记载器上显式修设级别,则行使其父记载器的级别动作其无效级别。假如父记载器也没有修设级别,则依此类推,探索父级的父级,直到找到鲜明修设了级其余记载器。根记载器默许下为 WARNING 级别
importloggingparent=logging.getLogger("parent")parent.setLevel(logging.INFO)parent.addHandler(logging.StreamHandler())child=logging.getLogger("parent.child")child.info("msg")
输出
msg
这里我没有给child修设日记等第,他会从父记载器查找日记级别,是以child也能够输出info级其余日记。对于记载器的经受瓜葛能够参考第一篇著作
2、为甚么偶然候日记会输出两次?
看上面例子:
importlogging#初始化日记,并修设日记级别(为root修设为DEBUG级别,联络合系StreamHandler,修设BASIC_FORMAT形式)logging.basicConfig(level=logging.DEBUG)#界说root记载器root=logging.getLogger()#界说child记载器child=logging.getLogger("child")console_handler=logging.StreamHandler()#给child绑定治理器child.addHandler(console_handler)#记载一条info日记child.info("childinfo")
输出
childinfoINFO:child:childinfo
代码中明显只记载了一越日记,却输出了两次,并且两次的日记形式不相似。这是由于 child 这个记载器增添了一个叫console_handler的治理器, 而root根记载器默许也带有本身的治理器(也是StreamHandler实例)
print(root.handlers)#[<StreamHandler<stderr>(NOTSET)>]
依照python中日记模块的治理机制,子记载器记载的音尘会主动鼓吹给父级记载器的联络合系的治理器。是以正在这个例子中,child记载的音尘除了会发给本身的handler外,依然鼓吹给root记载器的handler,所以终极输出了两次,流程图如下
logging-flow.png
假如不生气子记载器记载的音尘鼓吹给父级记载器,能够修设记载器的属性propagate为False,封闭鼓吹。
child.propagate=False
如许一来,终极输出到终真个日记就惟有child本身的治理器输出的记载
childinfo
设置治理器的最佳践诺是给顶级记载器设置治理器,再依照必要创修子记载器, 由于记载终极城市鼓吹给父记载器
importloggingparent=logging.getLogger("parent")parent.setLevel(logging.DEBUG)parent.addHandler(logging.StreamHandler())#没必要要给子记载器零丁设置handlerchild=logging.getLogger("parent.child")child.info("msg")
对付日记的流程治理,python官方文档画了一张更为过细的流程图,能够参考
logging_flow.png
第一次看推测有点晕,但先看我画的这张图再来看这张图,你就能懂了,为了简化我省去了过滤器以及不停轮回查找父级记载器的这个流程。
三、 为甚么我的pycharm中输出的日记是赤色?
不领略你的pycharm输出的日记不论是info新闻依然error新闻,横竖都是赤色,一看认为整屏都是失误。
把上面代码放正在Pycharm运转算作绩:
importlogginglogging.basicConfig(level=logging.DEBUG)logging.info("hello")
这是由于行使root记载器记载日记时,默许设置的handler是一个StreamHandler。
咱们翻开StreamHandler的源码
classStreamHandler(Handler):"""Ahandlerclasswhichwritesloggingrecords,appropriatelyformatted,toastream.Notethatthisclassdoesnotclosethestream,assys.stdoutorsys.stderrmaybeused."""terminator= def__init__(self,stream=None):"""Initializethehandler.Ifstreamisnotspecified,sys.stderrisused."""Handler.__init__(self)ifstreamisNone:stream=sys.stderrself.stream=stream
初始化这个Handler时,会收受一个stream的参数,假如不传,默许就行使的体例规范失误流(sys.stderr)输出,pycharm对失误流输出的字体款式做了赤色烘托,假如换成 sys.stdout 输出的就再也不赤色了。
importloggingimportsyshandler=logging.StreamHandler(stream=sys.stdout)logging.basicConfig(level=logging.DEBUG,handlers=[handler])#或许指定stream参数#logging.basicConfig(level=logging.DEBUG,stream=sys.stdout)logging.info("hello")
四、奈何天生以日期光阴定名的日记?
现实行使中,咱们会对日记实行归档存储,天天资成一份日记,假如哪天出了成绩,也容易定位,直接找到当天的日记文献就能够分解。咱们只要要给logger增添一个TimedRotatingFileHandler治理器就行。
file_handler=TimedRotatingFileHandler(‘logs/api.log),when="D",interval=1,backupCount=10,encoding="UTF-8",delay=False,utc=True)formatter=logging.Formatter(%(asctime)s-%(name)s-%(levelname)s-%(message)s)file_handler.setFormatter(formatter)file_handler.setLevel(logging.INFO)logger.addHandler(file_handler)
五、为甚么我日记设置后不失效?
或许跟标准的加载序次相合,看个例子
importlogginglogger=logging.getLogger()handler=logging.StreamHandler()logger.addHandler(handler)logger.info("hello1")logger.setLevel(logging.INFO)logger.info("hello2")
像下面的代码末了只输出了hello2,然而现实场景中,代码没这么简易,日常是正在a模块中的某个函数中初始化日记框架设置, 正在b模块外层创修了名字叫 logger_b的记载器,而后正在a中导入b模块时,这时日记设置还没初始化,末了招致logger_b的设置就成了默许设置。是以有或许显现日记不失效的状况。
所以最佳践诺是能尽早初始化日记设置就尽早提前。
文章推荐: