Python的logging是标准库,不需要额外安装。原文从创建记录器、设置级别、添加处理器、过滤器、格式器,到文件输出、日志轮转和实战案例展开,但基础、高级和实战部分有大量重复。按代码组织来看,logging的配置链条可以概括为:Logger接收日志调用,Handler决定输出位置,Filter做过滤,Formatter决定文本格式;级别在Logger和Handler上分别设置。理解这条链比逐段堆代码更便于排查问题。
基础配置通常先创建Logger,再设置级别,然后挂载StreamHandler、Filter和Formatter。原文示例的核心代码如下:- import logging
- logger = logging.getLogger('my_logger')
- logger.setLevel(logging.INFO)
- stream_handler = logging.StreamHandler()
- stream_handler.setLevel(logging.INFO)
- logger.addHandler(stream_handler)
- filter_ = logging.Filter('my_logger')
- stream_handler.addFilter(filter_)
- formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
- stream_handler.setFormatter(formatter)
- logger.info('This is an info message')
- logger.warning('This is a warning message')
复制代码 这里要注意,Filter('my_logger')是按记录器名称过滤,不是按级别过滤;级别由logger.setLevel或handler.setLevel控制。原文后面出现logging.Filter(logging.WARNING)并调用level_filter.setLevel(logging.WARNING)的写法,不符合标准库Filter的接口。若要限制WARNING以上输出,应设置Logger或Handler的级别。
多个处理器用于把同一份日志送到不同位置。原文先创建StreamHandler,再创建FileHandler或RotatingFileHandler。普通文件输出可用FileHandler('log.txt'),并设置handler级别与Formatter。文件轮转则使用RotatingFileHandler,原文参数为maxBytes=1024*1024、backupCount=5,表示单文件约1MB后轮转并保留5个备份。需要注意,RotatingFileHandler位于logging.handlers模块,原文写成logging.RotatingFileHandler('log.txt', ...)在实际运行中会报AttributeError。正确导入和参数如下:- import logging
- from logging.handlers import RotatingFileHandler
- logger = logging.getLogger('my_logger')
- logger.setLevel(logging.INFO)
- formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
- file_handler = RotatingFileHandler('log.txt', maxBytes=1024*1024, backupCount=5)
- file_handler.setLevel(logging.DEBUG)
- file_handler.setFormatter(formatter)
- logger.addHandler(file_handler)
复制代码 自定义时间格式可直接使用Formatter的datefmt参数,例如datefmt='%Y-%m-%d %H:%M:%S'。原文虽然导入了datetime,但Formatter本身已能控制asctime格式,不必再额外使用datetime。
原文还提到用with logging.basicConfig(handlers=[stream_handler], level=logging.INFO)作为上下文管理器,这也不是标准库行为:basicConfig返回None,不能用于with语句。实际做法是直接调用basicConfig,或像前面示例那样显式addHandler。
把原文4.1到4.6合并成一个实战流程时,要注意原文先添加FileHandler,又添加RotatingFileHandler,并且二者都指向log.txt。实际项目应二选一:普通文件输出用FileHandler,需要按大小轮转用RotatingFileHandler;同时挂两个指向同一文件的handler会造成重复写入,轮转时还可能产生文件句柄冲突。按原文参数合并后,可采用下面的结构:- import logging
- from logging.handlers import RotatingFileHandler
- logger = logging.getLogger('my_logger')
- logger.setLevel(logging.INFO)
- formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
- stream_handler = logging.StreamHandler()
- stream_handler.setLevel(logging.INFO)
- stream_handler.addFilter(logging.Filter('my_logger'))
- stream_handler.setFormatter(formatter)
- logger.addHandler(stream_handler)
- file_handler = RotatingFileHandler('log.txt', maxBytes=1024*1024, backupCount=5)
- file_handler.setLevel(logging.DEBUG)
- file_handler.setFormatter(formatter)
- logger.addHandler(file_handler)
- logger.info('This is an info message')
- logger.warning('This is a warning message')
复制代码 这段代码里Logger级别是INFO,因此即使file_handler设为DEBUG,DEBUG记录也不会通过Logger入口阈值。排查日志不输出时,可以按Logger级别、Handler级别、addHandler是否调用、Filter名称是否匹配、Formatter是否设置、文件权限和轮转参数逐项检查。对于轮转不生效,先确认导入的是logging.handlers.RotatingFileHandler,再检查maxBytes和backupCount是否符合预期。合理组织Logger、Handler和Formatter,可以让日志输出、文件落盘和轮转策略保持清晰,也便于后续维护。 |