pytest日志问题排查记录

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

一、问题现象

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


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

python 复制代码
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

python 复制代码
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 插件也可能把它拦截,不会直接打到控制台。


四、做了哪些修改

修改后的代码

python 复制代码
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 插件
相关推荐
code_whiter17 分钟前
7.自动化测试常用函数
python·功能测试
小园子的小菜27 分钟前
Python协程深度解析:从原理演进到实战避坑
后端·python
砚底藏山河35 分钟前
量化实战:截面因子有效性检验(IC 分析与分层回测)
java·python·金融·maven
GitFun1 小时前
给策略加了条-8%止损线,11年只触发1次
python·股票·量化交易
马六六i2 小时前
市面上正规的IP驱动产业新场景新工具有哪些
大数据·网络·python·tcp/ip
I Am a robert girl3 小时前
稀有事件估计的迭代去对齐:从源码视角拆解重要性采样新范式
开发语言·python·机器学习·重要性采样·蒙特卡洛方法·稀有事件估计
天若有情6733 小时前
开源|Comfort Lang v1.0.1,一款主打清爽交互的新型命令式编程语言
python·开源·交互·编程语言·项目分享·repl·comfort lang
打工仔折腾 AI3 小时前
System Prompt 替代 Few-shot:用规则约束大模型输出的省钱实践
java·人工智能·python·spring·langchain·prompt·ai agent 实战
打工仔折腾 AI3 小时前
从零写一个CAD 05:以鼠标为中心的滚轮缩放,招法能复用但顺序不能反
开发语言·后端·python·性能优化·计算机外设·swift·ai agent 实战
for_ever_love__4 小时前
控制流——if、for、while 与可迭代对象
python·大模型开发·循环·控制流