侧边栏壁纸
博主头像
一朵云的博客博主等级

拥抱生活,向阳而生。

  • 累计撰写 107 篇文章
  • 累计创建 28 个标签
  • 累计收到 7 条评论

目 录CONTENT

文章目录

Python -- logging模块日志管理

一朵云
2024-02-03 / 0 评论 / 0 点赞 / 68 阅读 / 7457 字

Python -- logging模块日志管理

简介:

logging 是 Python 标准库中的一个模块,它提供了灵活的事件日志记录功能。通过 logging 模块,开发者可以在程序中记录各种级别的日志信息,这对于调试、问题定位以及了解软件运行状态非常有用。相比于直接使用 print() 语句输出信息,logging 提供了更为强大和灵活的日志管理功能。

日志级别

Python 定义了6个日志级别(从低到高):

  • DEBUG:调试信息
  • INFO:普通信息
  • WARNING:警告信息
  • ERROR:错误信息
  • CRITICAL:严重错误

基础使用

import logging

logging.basicConfig(level=logging.INFO)
logging.debug('这是一条调试信息')  # 不会显示
logging.info('这是一条普通信息')   # 会显示
logging.warning('这是一条警告信息')  # 会显示

格式化输出

1、 % 格式化(推荐用于 logging)

常用格式字段:

  • %(asctime)s:时间
  • %(name)s:记录器名称
  • %(levelname)s:日志级别
  • %(message)s:日志消息
  • %(lineno)d:源代码行号
  • %(funcName)s:函数名

占位符类型:

可以自由组合不同类型的占位符:

占位符 说明 示例变量
%s 字符串 "Python"
%d 整数 42
%f 浮点数 3.14159
%.2f 保留2位小数的浮点数 3.141593.14

示例

logging.debug("进程 %s 用了 %d 秒,CPU 占用率 %.2f%%", "worker1", 5, 78.456)

特点

  • ✅ logging 模块原生优化(延迟求值)
  • ✅ 兼容所有 Python 版本
  • ❌ 功能相对简单

2、 str.format() 方法

logging.info("用户: {}, 年龄: {}".format(name, age))  # 立即求值
logging.info("用户: {name}, 年龄: {age}".format(name=name, age=age))  # 命名参数

特点

  • ✅ 支持命名参数和复杂格式化
  • ❌ 无条件立即求值(可能影响性能)

3、f-string (Python 3.6+)

logging.info(f"用户: {name}, 年龄: {age}")  # 最直观但立即求值

特点

  • ✅ 代码可读性最高
  • ❌ 无条件立即求值(性能敏感场景慎用)

4、字典格式化(结构化日志)

logging.info("用户数据: %s", {"name": name, "age": age})  # 适合 JSON 日志

特点

  • ✅ 适合机器解析的日志系统
  • ✅ 保持数据结构完整性

5、在 Pytest 中应用

# pytest.ini

# 开启日志输出
# 启用实时控制台日志输出
log_cli = true
log_cli_encoding = utf-8
# 全局默认日志等级
log_level = INFO
log_format = %(asctime)s [%(levelname)s] %(name)s:%(lineno)d - %(message)s
log_date_format = %Y-%m-%d %H:%M:%S
# 日志文件路径
log_file = ../logs/pytest.log
log_file_encoding = utf-8
# 文件日志级别(通常比控制台更详细)
log_file_level = DEBUG
log_file_format = %(asctime)s [%(levelname)s] %(filename)s:%(lineno)d - %(message)s
import logging


logger = logging.getLogger(__name__)


def test_1():

    logger.info("hhaa")
    assert 1 == 2

6、基于 Pytest 优化

对日志文件名增加日期区分

# pytest.ini
[pytest]
# 启用实时控制台日志输出
log_cli = true
log_cli_encoding = utf-8
log_cli_level = INFO
log_cli_format = %(asctime)s [%(levelname)s] %(name)s:%(lineno)d - %(message)s
log_cli_date_format = %Y-%m-%d %H:%M:%S

# 关闭原生 log_file(由代码控制)
# log_file = ../logs/pytest.log

# 全局默认日志等级
log_level = INFO

conftest.py

方案1:一天一个log,并且日志内容为“追加”模式,而不是覆盖!

# --------------------------
# 日志优化,对日志文件增加日期,FileHandler 是 追加写入
# --------------------------
def pytest_configure(config):
    # 创建 logs 目录
    log_dir = os.path.join(os.path.dirname(__file__), "logs")
    os.makedirs(log_dir, exist_ok=True)

    # 生成带日期的日志文件名:pytest_20250809.log
    today = datetime.now().strftime("%Y%m%d")
    log_file = os.path.join(log_dir, f"pytest_{today}.log")

    # 创建文件 handler
    file_handler = logging.FileHandler(log_file, encoding="utf-8", mode="a")
    file_handler.setLevel(logging.DEBUG)  # 文件记录更详细

    # 设置文件日志格式
    formatter = logging.Formatter(
        fmt="%(asctime)s [%(levelname)s] %(filename)s:%(lineno)d - %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S"
    )
    file_handler.setFormatter(formatter)

    # 添加到 root logger
    root_logger = logging.getLogger()
    root_logger.addHandler(file_handler)

方案2: 一次运行一个log,run1、run2......

# --------------------------
# 日志优化,对日志文件名增加日期
# --------------------------
def pytest_configure(config):
    # 创建 logs 目录
    log_dir = os.path.join(os.path.dirname(__file__), "logs")
    os.makedirs(log_dir, exist_ok=True)

    # 生成带日期的日志文件名:pytest_20250809.log
    today = datetime.now().strftime("%Y%m%d")

    base_name = f"pytest_{today}"
    # 正则匹配:pytest_20250809_run1.log, pytest_20250809_run2.log 等
    pattern = re.compile(rf"{base_name}_run(\d+)\.log$")
    # 扫描目录,找出所有匹配的 run 序号
    existing_runs = []
    for filename in os.listdir(log_dir):
        match = pattern.match(filename)
        if match:
            run_number = int(match.group(1))
            existing_runs.append(run_number)
    # 计算下一个序号
    next_run = max(existing_runs) + 1 if existing_runs else 1
    # 生成日志文件名
    log_file = os.path.join(log_dir, f"{base_name}_run{next_run}.log")

    # 创建文件 handler
    file_handler = logging.FileHandler(log_file, encoding="utf-8", mode="a")
    file_handler.setLevel(logging.DEBUG)  # 文件记录更详细

    # 设置文件日志格式
    formatter = logging.Formatter(
        fmt="%(asctime)s [%(levelname)s] %(filename)s:%(lineno)d - %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S"
    )
    file_handler.setFormatter(formatter)

    # 添加到 root logger
    root_logger = logging.getLogger()
    root_logger.addHandler(file_handler)
0

评论区