跳转至

Python 日志

核心构成

logging 主要由四个核心组件构成,共同完成日志的记录和输出。

  1. Logger (记录器)

  2. 作用: 这是我们与日志系统交互的主要入口。代码中通过调用 Logger 的方法(如 logger.info(), logger.error())来产生日志记录。

  3. 获取方式: logging.getLogger(name)
  4. 层级关系: Logger 是有层级结构的,类似 Python 的包名。子 logger 会将日志消息传递给父 logger 的处理器(handler),可使用logger.propagte=False关闭传递。

  5. Handler (处理器)

  6. 作用: 决定日志记录最终被发送到哪里。它可以是控制台、文件、网络套接字等。

  7. 常见类型:
    • StreamHandler: 输出到控制台。
    • FileHandler: 输出到文件。
    • RotatingFileHandler: 输出到文件,并按大小自动分割旧日志。
    • TimedRotatingFileHandler: 输出到文件,并按时间自动分割旧日志。
  8. 配置: 可以为 Handler 设置独立的日志级别(Level),只处理达到该级别的日志。

  9. Formatter (格式化器)

  10. 作用: 定义最终输出的日志消息的格式、结构和内容。

  11. 配置: 通过一个格式字符串来定义,其中包含多个占位符。
  12. 常用占位符:

    • %(asctime)s: 日志记录的创建时间,如 2025-09-19 03:17:37,123
    • %(levelname)s: 日志级别(DEBUG, INFO, WARNING, ERROR, CRITICAL)。
    • %(name)s: Logger 的名字。
    • %(message)s: 我们代码中实际传递的日志消息。
    • %(filename)s: 文件名。
    • %(lineno)d: 行号。
  13. Level (级别)

  14. 作用: 用于标记日志消息的重要性或严重程度。只有当日志消息的级别 大于或等于 Logger 和 Handler 设置的级别时,才会被处理。

  15. 级别从低到高:
    • DEBUG: 调试:最详细的日志
    • INFO: 信息:非报错,记录有用的信息,如关键条件分支等(如:开始调用外部厂商接口)
    • WARN/WARNING: 警告:应关注并适时解决,并不会导致业务故障(如:缓存应当存在,但是程序也可以创建新的缓存)
    • ERROR: 错误:业务故障,程序知道怎么回事,可处理(中断/容错)
    • FATAL: 致命错误:业务故障,程序不知道怎么处理,错误原因不明,导致中断
    • CRITICAL: 关键故障:业务故障,应当优先人工干预

代码示例

import logging
import os

# 1. 设置日志级别
# 从环境变量 "LOG_LEVEL" 获取级别,如果不存在,则默认为 "DEBUG"
LOG_LEVEL = os.getenv("LOG_LEVEL") or "DEBUG"


def setup_logger(name="default") -> logging.Logger:
    """初始化logger"""
    # 2. 获取 Logger 实例
    # logging.getLogger(name) 会获取一个指定名称的 logger
    # 如果多次用同一个名字调用,会返回同一个实例
    logger = logging.getLogger(name)

    # 3. 设置 Logger 的级别
    # logger.setLevel() 设置了这个 logger 会处理的最低级别
    logger.setLevel(LOG_LEVEL.upper())

    # 4. 防止重复添加 Handler
    # logger.handlers 是一个列表,存储了所有关联的 handler
    # 这个判断确保了即使多次调用 setup_logger(),也只会添加一次 handler
    if not logger.handlers:
        # 5. 创建 Handler
        # StreamHandler() 会将日志输出到控制台
        handler = logging.StreamHandler()

        # 6. 创建 Formatter
        # 定义了日志的输出格式:时间 [级别] logger名: 消息
        formatter = logging.Formatter(
            "%(asctime)s [%(levelname)s] %(name)s: %(message)s"
        )

        # 7. 将 Formatter 关联到 Handler
        handler.setFormatter(formatter)

        # 8. 将 Handler 关联到 Logger
        # 一个 logger 可以有多个 handler,比如同时输出到控制台和文件
        logger.addHandler(handler)

    return logger


if __name__ == "__main__":
    # 9. 使用配置好的 Logger
    # 调用函数获取一个名为 "default" 的 logger 实例
    logger = setup_logger()

    # 10. 产生不同级别的日志
    # 因为 LOG_LEVEL 默认为 "DEBUG",所以所有级别的日志都会被显示
    logger.debug("debug")
    logger.info("info")
    logger.warning("warning")
    logger.error("error")

运行结果:

如果直接运行这个脚本,由于 LOG_LEVEL 默认为 DEBUG,会看到所有级别的日志:

2025-09-19 03:17:37,123 [DEBUG] default: debug
2025-09-19 03:17:37,123 [INFO] default: info
2025-09-19 03:17:37,123 [WARNING] default: warning
2025-09-19 03:17:37,123 [ERROR] default: error

如果在终端中设置环境变量,比如LOG_LEVEL=WARN python test.py,或在WINDOWS的POWERSHELL中$env:LOG_LEVEL="WARN"; python test.py, 那么只有 WARN 及以上级别的日志才会被显示:

2025-09-19 03:17:37,456 [WARNING] default: warning
2025-09-19 03:17:37,456 [ERROR] default: error