Python logging模块日志级别解析及函数内配置问题咨询
一、日志级别(Levels)说明
Python Logging模块定义了5个从低到高的日志级别,用于区分日志的重要程度:
- DEBUG:最详细的调试信息,多用于开发阶段记录变量值、函数执行流程等细节
- INFO:确认程序按预期运行的常规信息,比如服务启动完成、数据加载成功
- WARNING:提示潜在问题,但程序仍可正常运行,比如内存占用过高、使用已废弃API
- ERROR:程序功能异常,部分逻辑无法执行,比如文件读取失败、数据库连接错误
- CRITICAL:严重错误,程序可能无法继续运行,比如系统资源耗尽、核心组件崩溃
默认情况下,日志系统只会输出WARNING级别及以上的日志。
二、能否通过自定义函数配置Logging?
完全可以。自定义配置函数是Logging模块的常用实践,能把日志配置逻辑封装复用,还可灵活设置日志级别、处理器(Handler)、输出格式(Formatter)等。你写的setuplogging()就是典型的自定义配置函数,通过它可以创建日志器、添加控制台/文件处理器、定义输出格式。
三、测试代码相关疑问
a. 为何调用配置函数后需添加logging = logging.getLogger(__name__),主脚本末尾的日志语句才生效?
你一开始导入的logging是Python的logging模块本身,直接调用logging.info()这类方法时,实际使用的是根日志器(root logger)。而setuplogging()函数里配置的是__name__对应的子日志器(当前脚本专属的日志器)。
根日志器默认级别为WARNING,且没有添加你自定义的控制台和文件处理器——如果不重新赋值logging = logging.getLogger(__name__),主脚本末尾的logging.info()会因级别不够被过滤,logging.warning()也只会用根日志器的默认处理器输出,不会走你配置的格式和处理器。重新赋值后,后续日志调用才会使用你配置好的子日志器,语句才能按预期生效。
b. 日志输出重复的原因是什么?
主要源于日志传播机制:子日志器默认会把日志传播给父日志器(根日志器)。当你第一次调用logging.warning('This is a trial of basic logging')时,根日志器会自动创建一个默认的控制台处理器(StreamHandler)。之后你的子日志器输出日志时,会先通过自己添加的c_handler输出一次,再把日志传播给根日志器,根日志器的默认处理器会再输出一次,最终导致重复。
另外如果setuplogging()函数被多次调用,每次都会给同一个子日志器添加新处理器,也会引发重复输出,但你的代码里只调用了一次,所以核心原因是日志传播。
你的测试代码
def setuplogging(): # logging_example #import logging # When setting up logging, define the level using capitals because logging.debug is seen as a function, logging.DEBUG is the level id. # Create a custom logger logger = logging.getLogger(__name__) #The variable __name__ contains the dotted name of the current module. logger.setLevel(logging.DEBUG) #WARM is default # Create handlers c_handler = logging.StreamHandler() f_handler = logging.FileHandler('E:\data\computing\software\programming\scripts\LOGFILE.log') c_handler.setLevel(logging.DEBUG) f_handler.setLevel(logging.DEBUG) # Create formatters and add it to handlers c_format = logging.Formatter('%(name)s - %(levelname)s - %(message)s') f_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') c_handler.setFormatter(c_format) f_handler.setFormatter(f_format) # Add handlers to the logger logger.addHandler(c_handler) logger.addHandler(f_handler) logger.info('def This is a test of an info message') logger.warning('def This is a warning') logger.error('def This is an error') import logging logging.warning('This is a trial of basic logging') setuplogging() logging = logging.getLogger(__name__) logging.info('Script This is a test of an info message') logging.warning('Script This is a warning') logging.error('Script This is an error')
内容的提问来源于stack exchange,提问作者Davy

