pin_drop当前位置:知识文库 ❯ 图文

Python Formatter格式化详解 - 自定义日志输出格式

一、Formatter概述

Formatter 是 Python logging 模块中负责定义日志输出格式的核心组件。它将 LogRecord 对象中的信息按照指定的格式字符串转换为最终的日志文本。通过 Formatter,开发者可以精确控制日志中包含哪些信息(时间戳、级别、Logger名称、消息等)以及它们的排列方式。

每个 Handler 可以设置独立的 Formatter,实现不同输出目标的差异化格式。例如,控制台可以使用简洁格式方便阅读,而文件可以使用详细格式包含文件名、行号等信息便于排查问题。

小贴士

Formatter 是设置在 Handler 上的,不是设置在 Logger 上的。同一个 Logger 的不同 Handler 可以使用不同的 Formatter,这是实现"控制台简洁、文件详细"输出策略的关键。

二、Formatter语法与参数

创建 Formatter 的基本语法:

代码示例

import logging

# 创建格式化器
formatter = logging.Formatter(
    fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
    style='%'
)

# 设置到Handler
handler = logging.StreamHandler()
handler.setFormatter(formatter)

Formatter 构造函数接受以下参数:

参数 类型 默认值 说明
fmt str '%(message)s' 格式字符串,定义日志输出格式
datefmt str None 时间格式字符串,同 strftime
style str '%' 格式化风格:'%'、'{'、'$'
validate bool True 是否验证格式字符串(Python 3.8+)

三、常用LogRecord属性

格式字符串中可以使用的 LogRecord 属性:

属性 格式写法 说明 示例输出
asctime %(asctime)s 可读时间 2026-06-15 10:30:00
name %(name)s Logger名称 my_app
levelname %(levelname)s 级别名称 INFO
levelno %(levelno)d 级别数值 20
message %(message)s 日志消息 用户登录成功
filename %(filename)s 文件名 app.py
lineno %(lineno)d 行号 42
funcName %(funcName)s 函数名 process_request
module %(module)s 模块名 app
pathname %(pathname)s 完整路径 /path/to/app.py
process %(process)d 进程ID 12345
thread %(thread)d 线程ID 67890
created %(created)f 时间戳(浮点) 1718438400.123456

四、代码示例

示例1:常用格式配置

以下示例展示了如何配置简洁格式和详细格式,分别用于控制台和文件输出:

代码示例

import logging

logger = logging.getLogger("fmt_demo")
logger.setLevel(logging.DEBUG)

# 简洁格式(控制台用)
simple_fmt = logging.Formatter(
    fmt='[%(levelname)s] %(message)s'
)

# 详细格式(文件用)
detailed_fmt = logging.Formatter(
    fmt='%(asctime)s [%(levelname)s] %(name)s (%(filename)s:%(lineno)d) - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)

# 应用到Handler
console = logging.StreamHandler()
console.setFormatter(simple_fmt)
logger.addHandler(console)

logger.info("简洁格式输出")
logger.warning("只显示级别和消息")

输出结果:

代码示例

[INFO] 简洁格式输出
[WARNING] 只显示级别和消息

示例2:自定义Formatter子类

通过继承 Formatter 类,可以实现自定义的格式化逻辑,例如带颜色的终端输出:

代码示例

import logging

class ColorFormatter(logging.Formatter):
    """带颜色的格式化器(适用于终端)"""

    COLORS = {
        'DEBUG': '\033[36m',     # 青色
        'INFO': '\033[32m',      # 绿色
        'WARNING': '\033[33m',   # 黄色
        'ERROR': '\033[31m',     # 红色
        'CRITICAL': '\033[35m',  # 紫色
    }
    RESET = '\033[0m'

    def format(self, record):
        color = self.COLORS.get(record.levelname, '')
        record.levelname = f"{color}{record.levelname}{self.RESET}"
        return super().format(record)

# 使用自定义格式化器
logger = logging.getLogger("color_demo")
logger.setLevel(logging.DEBUG)

handler = logging.StreamHandler()
formatter = ColorFormatter('[%(levelname)s] %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)

logger.debug("调试信息(青色)")
logger.info("普通信息(绿色)")
logger.warning("警告信息(黄色)")
logger.error("错误信息(红色)")
logger.critical("严重错误(紫色)")

输出结果(终端中会显示对应颜色):

代码示例

[DEBUG] 调试信息(青色)
[INFO] 普通信息(绿色)
[WARNING] 警告信息(黄色)
[ERROR] 错误信息(红色)
[CRITICAL] 严重错误(紫色)

示例3:不同风格格式化

Python 3.2+ 支持三种格式化风格,以下是 % 风格和 { 风格的对比:

代码示例

import logging

logger = logging.getLogger("style_demo")
logger.setLevel(logging.INFO)

# % 风格(默认)
handler1 = logging.StreamHandler()
handler1.setFormatter(logging.Formatter(
    fmt='[%风格] %(asctime)s %(levelname)s %(message)s',
    datefmt='%H:%M:%S'
))

# { 风格
handler2 = logging.StreamHandler()
handler2.setFormatter(logging.Formatter(
    fmt='[{风格] {asctime} {levelname} {message}',
    style='{',
    datefmt='%H:%M:%S'
))

logger.addHandler(handler1)
logger.addHandler(handler2)

logger.info("对比不同格式化风格")

输出结果:

代码示例

[%风格] 10:30:00 INFO 对比不同格式化风格
[{风格] 10:30:00 INFO 对比不同格式化风格

五、格式化风格对比

对比项 %风格 {风格 $风格 自定义Formatter
语法 %(name)s {name} $name Python代码
兼容性 默认 Python 3.2+ Python 3.2+ 所有版本
灵活性 最高
性能 取决于实现
适用场景 通用 偏好format 偏好Template 特殊需求

六、实际应用场景

  • 差异化格式:控制台使用简洁格式方便阅读,文件使用详细格式包含文件名、行号等信息便于排查。

  • JSON格式日志:自定义 Formatter 输出 JSON 格式的日志,便于 ELK 等日志收集系统解析和检索。

  • 彩色终端输出:自定义带颜色的 Formatter,在终端中不同级别使用不同颜色,提高日志可读性。

七、注意事项与最佳实践

注意1Formatter 是设置在 Handler 上的,不是设置在 Logger 上的。同一个 Logger 的不同 Handler 可以使用不同的 Formatter。

注意2datefmt 只影响 %(asctime)s 的格式,不影响 %(created)s 等其他时间属性。

注意3:自定义 Formatter 子类时,重写 format() 方法应注意不要修改 record 的原始数据,或者在格式化后恢复原始数据,避免影响其他 Handler。

提示:生产环境推荐使用包含时间戳、级别、Logger名称和消息的标准格式,如 %(asctime)s [%(levelname)s] %(name)s: %(message)s

八、常见问题FAQ

常见问题

Formatter 应该设置在 Logger 上还是 Handler 上?

Formatter 应该设置在 Handler 上,而不是 Logger 上。每个 Handler 可以设置独立的 Formatter,这使得同一个 Logger 可以通过不同的 Handler 以不同格式输出日志。例如,控制台 Handler 使用简洁格式,文件 Handler 使用详细格式。

datefmt 参数是如何工作的?

datefmt 参数使用与 Python time.strftime() 相同的格式字符串,仅影响 %(asctime)s 的输出格式。常用的格式包括 %Y-%m-%d %H:%M:%S。如果未指定 datefmt,asctime 默认包含毫秒。

如何输出 JSON 格式的日志?

可以通过自定义 Formatter 子类实现 JSON 格式输出。在 format() 方法中,将 record 对象的属性提取为字典,使用 json.dumps() 转换为 JSON 字符串。这种方式非常适合与 ELK、Splunk 等日志收集系统配合使用。

三种格式化风格(%、{、$)应该选择哪种?

推荐使用默认的 % 风格,因为它是 logging 模块的默认风格,文档和社区示例最多,兼容性最好。{ 风格和 $ 风格需要显式指定 style 参数。对于新项目,% 风格是最佳选择。

如何在日志格式中包含自定义属性?

可以通过 logging.LoggerAdapter 或 Logger.extra 参数传递自定义属性。在格式字符串中使用 %(自定义属性名)s 即可引用。例如:logger.info("消息", extra={"user_id": 123}),格式字符串中用 %(user_id)s 引用。

九、练习题

练习目标

通过以下练习,巩固对 Formatter 格式化器的理解和实践能力:

练习1

创建一个 Formatter,格式为 时间 | 级别 | 文件:行号 | 消息,应用到 StreamHandler 并记录几条日志。

练习2

自定义一个 JSONFormatter,继承 logging.Formatter,将日志格式化为 JSON 字符串,包含 time、level、name、message 四个字段。

练习3

分别使用 % 风格和 { 风格创建格式相同的 Formatter,对比两种风格的语法差异,并验证输出是否一致。


标签: Python logging Formatter 日志格式化 LogRecord 自定义格式化

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: Python Handler处理器详解 - logging模块多目标日志输出 下一篇: Python FileHandler详解 - 日志文件输出与持久化

poll相关推荐