昔我往昔头像
关注

pytest日志问题排查记录

pytest 日志不打印问题排查与修复记录

一、问题现象

在执行 pytest -s test_http_client_request.py 时,HTTPClient 发出的请求没有任何日志输出,但代码中明明写了 logger.info(...)


二、修改前的代码(问题代码)

import requests
import logging

# 1、初始化日志 
logging.basicConfig(level=logging.INFO)          # ❌ 在 pytest 下无效
logger = logging.getLogger(__name__)
# 2. 创建格式器
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
# 3. 创建并配置控制台处理器 (输出到屏幕)
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
# ❌ 缺少 logger.setLevel(...)
# ❌ 缺少 logger.propagate = False

看起来"什么都有",但实际运行起来一条 INFO 日志都打不出来


三、为什么不能打印日志(三个原因)

原因 1:logging.basicConfig() 在 pytest 下是空操作

logging.basicConfig() 有一个前置条件:只有当 root logger 没有任何 handler 时,它才会生效

而 pytest 启动时会先给 root logger 挂上自己的 LogCaptureHandler,所以当代码执行到 basicConfig(level=logging.INFO) 时——root logger 已经有 handler 了,这一行直接被跳过,root logger 的 level 没有被改成 INFO。

原因 2:logger 没有显式设置 level

logger = logging.getLogger(__name__)   # level 默认是 NOTSET

NOTSET 意味着继承父级 logger 的 level,一路往上找到 root logger。而 pytest 把 root logger 的 level 设成了 WARNING,所以:

logger.info("...")
    ↓
logger.level = NOTSET → 继承 root
    ↓
root.level = WARNING(pytest 设的)
    ↓
INFO < WARNING → 被过滤 ❌

INFO 级别的日志在 logger 这一层就被丢弃了,根本到不了 handler。

原因 3:-s 只管 stdout/stderr,不管 logging

很多人以为 pytest -s 能让所有输出都显示出来。实际上:

标志作用
-s禁用 pytest 对 stdout/stderr 的捕获
logging 插件pytest 独立的日志处理系统,-s 不影响它

即使 handler 收到了日志,pytest 的 logging 插件也可能把它拦截,不会直接打到控制台。


四、做了哪些修改

修改后的代码

import requests
import logging

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)           # ✅ 新增:显式设置 level
logger.propagate = False                # ✅ 新增:禁止冒泡到 root logger
# 2. 创建格式器
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
# 3. 创建并配置控制台处理器 (输出到屏幕)
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
# ✅ 删除了无效的 logging.basicConfig(level=logging.INFO)

改动汇总

改动操作原因
删除 logging.basicConfig(level=logging.INFO)删除pytest 下是空操作,留着会误导
新增 logger.setLevel(logging.INFO)新增显式设置 level,不再依赖 root logger,确保 INFO 能通过第一道关卡
新增 logger.propagate = False新增阻止日志冒泡到 root logger,避免被 pytest 的日志插件拦截或重复处理

五、为什么这么修改

5.1 为什么 setLevel 是关键

Python logging 的 level 检查是两级过滤

logger.info("msg")
    ↓
【第一级】logger.level 检查 ← 大多数人不了解这一级
    ↓ 通过
【第二级】handler.level 检查
    ↓ 通过
输出

之前代码两级都没显式设置,全靠继承,而继承到的是 pytest 设的 WARNING。现在第一级显式设为 INFO,日志就能通过:

logger.info("msg")
    ↓
logger.level = INFO → 放行 ✅
    ↓
handler.level = NOTSET(默认全放行) → 放行 ✅
    ↓
输出到控制台 ✅

5.2 为什么 propagate = False 是必要的

默认情况下 propagate = True,日志记录在走完自己 logger 的 handler 后,还会继续向上传递给 root logger 的 handler。而 pytest 给 root logger 挂的 handler 是用来捕获日志的(用于测试报告中的日志展示),会导致:

  • 日志被重复打印(自己的 handler 打一次,root 的 handler 再打一次)
  • 或者被 pytest 的日志系统拦截,看不到实时输出

设为 False 后,日志只走自己的 handler,干净、可控


六、修改后的效果

执行 pytest -s test_http_client_request.py,日志正常输出:

test_http_client_request.py
2026-09-16 10:30:15,123 - INFO - [POST] http://xxx/api/v1/auth/login
2026-09-16 10:30:15,456 - INFO - Status: 200
.
2026-09-16 10:30:15,789 - INFO - [POST] http://xxx/api/v1/auth/login
2026-09-16 10:30:16,012 - INFO - Status: 200
.
2026-09-16 10:30:16,345 - INFO - [POST] http://xxx/api/v1/auth/login
2026-09-16 10:30:16,678 - INFO - Status: 200
.
======================================================= 3 passed in 1.56s =======================================================

七、核心知识点总结

一句话记住:Python logging 的 level 检查发生在 logger 上,不在 handler 上。

  • basicConfig() 只在 root logger 无 handler 时生效,pytest 下基本没用
  • 给 logger 显式 setLevel() 是确保日志能输出的第一道关卡
  • propagate = False 让日志只走自己的 handler,绕开 pytest 的日志拦截
  • pytest -s 只管 stdout/stderr,不管 logging 插件

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/hekai7217/article/details/165625447

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--