高效日志应延迟格式化、按需执行,避免无条件拼接;使用占位符如logger.info("用户 %s 操作失败", user_id);统一Formatter确保格式一致;预置JSON格式支持结构化日志;禁用f-string等立即求值方式。

直接用字符串拼接写日志,看似简单,实则埋下性能隐患。关键不是“能不能拼”,而是“该不该在每次调用时都拼”。高效日志记录器的核心逻辑是:**延迟格式化、按需执行、避免冗余计算**。
避免无条件字符串拼接
像 logger.info("用户 " + str(user_id) + " 操作失败,耗时 " + str(elapsed) + "s") 这类写法,无论当前日志级别是否允许输出(比如生产环境只开 INFO,而这条在 DEBUG 级),拼接操作都会立即执行——生成中间字符串、触发 str() 调用、创建临时对象。这对高频服务会造成明显 CPU 和 GC 压力。
- 改用占位符方式:
logger.info("用户 %s 操作失败,耗时 %s s", user_id, elapsed) - logging 模块会在确认该条日志需要输出后,才真正执行格式化,跳过不满足级别的拼接开销
- 对复杂对象(如 dict、list),也适用:
logger.debug("请求参数: %s", request_data),而非str(request_data)
使用 Formatter 统一控制输出结构
日志的可读性与后续分析能力,取决于格式是否稳定、字段是否完整。靠每次手动拼接时间、模块名、行号,既易错又难维护。
- 定义标准格式器:
Formatter('%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s') - 关键字段说明:
%(asctime)s自动注入格式化时间;%(funcName)s和%(lineno)d精准定位代码位置;%(name)s支持按模块分级管理 - 所有 Handler(控制台、文件、轮转文件)复用同一个 Formatter,确保全系统日志风格一致
为结构化日志预置 JSON 格式支持
当需要对接 ELK、Loki 或云原生日志平台时,纯文本日志解析成本高。提前支持 JSON 输出,能显著提升可观测性效率。
- 自定义
JSONFormatter类,重写format()方法,将record中的关键字段转为字典再序列化 - 保留原始字段如
timestamp、level、message,同时可扩展业务字段(如trace_id、user_id) - 注意避免在 JSON 中直接写入不可序列化对象(如 datetime 实例),应先调用
self.formatTime(record)转为字符串
谨慎使用 f-string 或 format() 直接参与日志调用
f-string 在 Python 3.6+ 中性能优秀,但它和 .format() 一样,属于“立即求值”——只要代码走到这一行,就会执行变量转换和拼接,无法绕过日志级别判断。
- 错误示例:
logger.info(f"处理完成,共 {len(items)} 条")→ 即使日志被过滤,len(items)仍会执行 - 正确做法:
logger.info("处理完成,共 %d 条", len(items))→len()仅在日志实际输出时调用 - 若需动态构造复杂消息,可封装成惰性对象或使用 lambda(配合自定义 Filter),但多数场景用占位符已足够

















