Python 3.12 logging - 07 - LogRecord
LogRecord的基本概念
LogRecord 是 Python logging 模块中代表一条日志事件的数据容器。简单来说,它就像一张“记录单”,每当程序调用日志方法(如 logger.info())时,logging 会自动创建一个 LogRecord 对象,并把所有相关信息都装进去,包括:日志消息内容、日志级别(DEBUG/INFO 等)、产生日志的时间戳、源代码位置(文件名、行号、函数名)、当前线程/进程 ID、异常信息(如果有)、其他自定义属性(通过 extra 添加)。
这个“记录单”随后会被传递给日志处理器(Handler)和格式化器(Formatter),最终被转换成我们看到的输出文本。
一、LogRecord类机制解析
LogRecord是logging模块的核心类,用于封装日志事件的所有信息。每次记录事件时,系统都会生成LogRecord实例。其包含与所记录事件相关的全部信息。
传递的主要信息位于msg和args中,通过str(msg) % args组合形成记录的消息字段,实际的消息格式化在 getMessage() 中完成。
其核心机制包括:
1. 动态属性管理
- 属性存储:通过
__init__动态存储字段(如msg,levelname等) - 延迟格式化:如
message属性在访问时通过getMessage(),解析msg与args - 默认属性集:包含多个字段信息(如
name,pathname,lineno,exc_info,sinfo等)
2. 工厂模式
通过logging.makeLogRecord(dict)工厂方法创建实例:
record_dict ={"name":"demo","level":20,"pathname":"/app/main.py","msg":"User %s logged in","args":("Alice",)} record = logging.makeLogRecord(record_dict)3. 关键方法
getMessage():合并msg与args生成最终日志消息
defgetMessage(self):""" Return the message for this LogRecord. Return the message for this LogRecord after merging any user-supplied arguments with the message. 如果存在 args, 则使用 % 运算符进行格式化,并返回最终消息字符串。 当 args 为空元组或空字典或None时,也为假,不进行格式化)。 该方法在格式化器(Formatter)中被调用,用于获取消息部分 """ msg =str(self.msg)if self.args: msg = msg % self.args return msg 二、LogRecord生命周期
- 创建:由
Logger.log()调用Logger.makeRecord()生成 - 处理:经由
Filter、Formatter等组件 - 输出:通过
Handler写入目标(文件/网络等)
三、完整Demo实现
import logging import logging.config import time classCustomLogRecord(logging.LogRecord):"""扩展LogRecord以添加自定义字段"""def__init__(self,*args,**kwargs):super().__init__(*args,**kwargs) self.custom_id =hash(time.time())# 添加唯一IDdefcustom_record_factory(name, level, fn, lno, msg, args, exc_info, func=None, sinfo=None,**kwargs):"""自定义LogRecord工厂函数""" record = CustomLogRecord(name, level, fn, lno, msg, args, exc_info, func, sinfo)return record # 定义一个过滤器,为记录添加默认的custom_fieldclassDefaultCustomFieldFilter(logging.Filter):def__init__(self, default_value="d"):super().__init__() self.default_value = default_value deffilter(self, record):ifnothasattr(record,'custom_field'): record.custom_field = self.default_value returnTrue# 返回True表示记录通过# 配置日志系统 logging_config ={"version":1,"formatters":{"detailed":{"format":"[%(asctime)s][%(levelname)s][%(name)s]-[ID=%(custom_id)s]-%(message)s # custom:%(custom_field)s","datefmt":"%Y-%m-%d %H:%M:%S"}},"handlers":{"console":{"class":"logging.StreamHandler","formatter":"detailed","level":"DEBUG","filters":["default_custom_field"]}},"loggers":{"demo":{"handlers":["console"],"level":"DEBUG"}},"filters":{"default_custom_field":{"()": DefaultCustomFieldFilter,"default_value":""}}}defmain():# 应用配置并设置自定义工厂 logging.config.dictConfig(logging_config) logging.setLogRecordFactory(custom_record_factory) logger = logging.getLogger("demo")# 标准日志记录 logger.info("Service started")# 添加自定义字段 logger.debug("Debug with extra", extra={"custom_field":"debug_value"})# 异常处理示例try:1/0except Exception as e: logger.error("Math error occurred", exc_info=True)if __name__ =="__main__": main()四、关键输出解析
执行上述代码将输出:
五、性能优化建议
- 避免冗余计算:在
Filter中尽早过滤低级别日志
总结:LogRecord作为日志系统的核心载体,通过灵活的属性和工厂机制支持深度定制。结合Python 3.12的优化特性(如PEP 657精确错误定位),可构建高性能、可扩展的日志架构。实际开发中应善用extra参数和自定义工厂实现业务级日志增强。
本篇博客中,如有存在偏差或是错误的地方,请私信我哈,欢迎指正。