Python日志模块logging使用指南:从基础配置到父子Logger关系详解
本文深入解析Python标准库logging模块的核心用法。通过实际案例演示如何同时向控制台和文件输出日志,详解getLogger、setLevel及addHandler等关键API。重点剖析Root Logger与子Logger的继承机制、Effective Level概念及消息传递流程,帮助开发者构建规范的日志系统。
Python日志模块logging使用指南:从基础配置到父子Logger关系详解
本文详细介绍Python中logging模块的具体使用方法,旨在为开发者提供实用的参考方案。
典型应用场景:控制台与文件双输出
一、典型应用场景
在开发过程中,通常需要构建一个日志系统,要求既能将日志信息输出到控制台以便实时查看,又能将日志持久化写入日志文件以供后续分析。
import logging
# 创建一个logger
logger = logging.getLogger('mylogger')
logger.setLevel(logging.DEBUG)
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log')
fh.setLevel(logging.DEBUG)
# 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# 定义handler的输出格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)
# 给logger添加handler
logger.addHandler(fh)
logger.addHandler(ch)
# 记录一条日志
logger.info('foorbar')
执行上述代码后,控制台和指定的日志文件中均会生成一条对应的日志记录。
2011-08-31 19:18:29,816 - mylogger - INFO - foorbar
logging模块核心API解析
二、logging模块核心API解析
基于上述示例,我们重点介绍几个最常用的API函数及其功能。
调用logging.getLogger([name])可以获取一个logger实例。若未指定name参数,则返回root logger。对于相同的name,系统始终返回同一个logger实例,确保name与logger实例之间是一一对应的关系。这一机制意味着无需在各模块间显式传递logger实例,只需知道name即可获取相同的logger对象。
Logger.setLevel(lvl)用于设置logger的日志级别,支持的级别包括:

NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL
若将logger的级别设置为INFO,则所有低于INFO级别的日志将被忽略不输出,而等于或高于INFO级别的日志则会正常输出。
logger.debug("foobar") # 不输出
logger.info("foobar") # 输出
logger.warning("foobar") # 输出
logger.error("foobar") # 输出
logger.critical("foobar") # 输出
Logger.addHandler(hdlr)允许logger雇佣handler来处理日志。常见的handler类型包括:StreamHandler(输出到控制台)和FileHandler(输出到文件)。此外,handler还可以独立设置自己的日志级别和输出格式。
logging.basicConfig([**kwargs])
该函数用于配置root logger,其源码逻辑较为直观。首先检查root logger是否已存在handler,若不存在,则自动创建一个StreamHandler并应用默认的formatter。
随后将该handler添加至root logger。如果调用logging.basicConfig([**kwargs])时检测到root logger已包含handler,则该函数不再执行任何操作。
Root Logger与Logger的父子层级关系
三、Root Logger与Logger的父子层级关系
前文多次提及root logger,实际上logger实例之间存在父子继承关系,root logger处于层级顶端,是所有其他logger的祖先。具体结构如下图所示:

root logger是默认的logger。若不手动创建logger实例,直接调用logging.debug()、logging.info()、logging.warning()、logging.error()或logging.critical()等函数,系统默认使用root logger。它支持自动创建,且为单实例模式。
通过调用logging.getLogger()或logging.getLogger("")即可获取root logger实例。
默认情况下,root logger的日志级别设置为logging.WARNING。
Logger的name命名方式可用于表示父子关系。例如:parent_logger = logging.getLogger('foo'),child_logger = logging.getLogger('foo.bar'),其中foo.bar是foo的子logger。
Effective Level是指logger的有效日志级别。若某个logger未显式设置level,则继承父logger的level;若父logger也未设置,则继续向上追溯,直至root logger(必定已设置level,默认为logging.WARNING)。当子logger收到消息时,不仅会分发给其自身的handler处理,还会将消息传递给所有祖先logger进行处理。
以下通过一个具体示例进行说明。
import logging
# 设置root logger
r = logging.getLogger()
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
r.addHandler(ch)
# 创建一个logger作为父亲
p = logging.getLogger('foo')
p.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(message)s')
ch.setFormatter(formatter)
p.addHandler(ch)
# 创建一个孩子logger
c = logging.getLogger('foo.bar')
c.debug('foo')
程序运行后的输出结果如下:
2011-08-31 21:04:29,893 - foo 2011-08-31 21:04:29,893 - DEBUG - foo
由此可见,子logger由于未配置任何handler,因此不直接处理消息。但它会将消息转发给父logger及root logger,最终导致两条日志被输出。
如需了解更多Python相关内容,建议参考本站专题:《Python日志操作技巧总结》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》及《Python文件与目录操作技巧汇总》。
希望本文的阐述能对大家的Python程序设计工作有所帮助。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









