You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Structlog与logging模块在pytest中无法生成日志的问题排查

structlog日志在pytest中无输出问题排查

问题场景

测试目录结构:

├── tests
│   ├── __init__.py
│   ├── conftest.py
│   ├── test_main.py

tests/__init__.py中的日志配置:

import structlog, logging, sys
from structlog.testing import LogCapture

logging.basicConfig(filename="test.log", filemode="w")

structlog.configure(
    processors=[LogCapture()],
    context_class=structlog.threadlocal.wrap_dict(dict),
    logger_factory=structlog.stdlib.LoggerFactory(),
    cache_logger_on_first_use=True
)

test_main.py内容:

import logging, structlog, pytest

from src.factories.factories import MyFactory
import src.main
from pathlib import Path
from datetime import datetime

@pytest.mark.parametrize(
    "factory",
    [
        MyFactory(),
    ],
)
def test_main(path_to_results_folder_fixture_in_conftest, factory):
    structlog.get_logger().info("test")
    no_of_files_function = lambda: sum(1 for _ in Path(path_to_results_folder_fixture_in_conftest).iterdir())
    len_before = no_of_files_function()
    src.main.main("sony", factory, path_to_results_folder)
    assert no_of_files_function() == len_before + 1

运行pytest test_main.py后,test.log为空,控制台也无日志输出,但预期structlog.get_logger().info("test")应生成日志内容。

问题原因及修复方法

核心问题

  1. LogCapture处理器的作用限制:你将structlog.testing.LogCapture作为唯一处理器,它的功能是在内存中捕获日志供测试断言使用,不会将日志传递给标准logging系统,自然无法写入文件或输出到控制台。
  2. 日志级别未显式配置:logging.basicConfig默认日志级别为WARNING,你输出的INFO级别日志会被默认过滤掉。
  3. structlog未连接到标准输出流程:现有配置没有搭建从structlog到标准logging的输出链路,导致logging.basicConfig的文件输出配置无效。

修复步骤

方案1:保留日志捕获+输出日志

如果你既需要在测试中捕获日志做断言,又要输出日志到文件,可以修改tests/__init__.py的配置:

import structlog, logging, sys
from structlog.testing import LogCapture

# 配置标准logging,显式设置INFO级别
logging.basicConfig(
    filename="test.log",
    filemode="w",
    format="%(message)s",
    level=logging.INFO
)

structlog.configure(
    processors=[
        LogCapture(),  # 保留日志捕获功能
        structlog.stdlib.add_log_level,  # 添加日志级别字段
        structlog.processors.TimeStamper(fmt="iso"),  # 可选:添加时间戳
        structlog.stdlib.ProcessorFormatter.wrap_for_formatter,  # 连接到标准logging格式器
    ],
    context_class=structlog.threadlocal.wrap_dict(dict),
    logger_factory=structlog.stdlib.LoggerFactory(),
    cache_logger_on_first_use=True
)

方案2:仅输出日志(无需捕获)

如果不需要在测试中断言日志内容,直接移除LogCapture处理器,改用常规输出配置:

import structlog, logging, sys

logging.basicConfig(
    filename="test.log",
    filemode="w",
    format="%(message)s",
    level=logging.INFO
)

structlog.configure(
    processors=[
        structlog.stdlib.add_log_level,
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.stdlib.render_to_log_kwargs,  # 将structlog日志转换为标准logging参数
    ],
    context_class=dict,
    logger_factory=structlog.stdlib.LoggerFactory(),
    cache_logger_on_first_use=True
)

额外代码修复

测试函数中存在未定义变量:path_to_results_folder应该替换为path_to_results_folder_fixture_in_conftest,否则运行时会抛出NameError。


内容的提问来源于stack exchange,提问作者aldo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 00:35:27