Python3.7下使用requests写日志到文件时缺失send、reply及响应头内容的问题
问题根因
你当前日志文件中缺失的send:/reply:/header:类内容,根本没有接入Python标准logging的日志投递流程。
当你设置http_client.HTTPConnection.debuglevel = 1后,http.client模块输出的这类详细调试信息,是直接往标准输出流(sys.stdout)写入的原生打印内容,和logging体系完全独立。
这也直接解释了两个观测到的现象:
- 控制台默认承接stdout的全部输出,所以能完整看到这部分调试信息
- 你给urllib3 logger挂载的文件日志处理器,只能接收通过logging接口投递的日志(也就是目前日志里已有的“新建HTTPS连接”“请求返回状态码”这两条记录),完全捕获不到这些绕过logging流程的原生打印内容
全量日志写入的实现方案
有两种可落地的解决路径,其中第二种是生产环境推荐的规范方案:
方案1:拦截重定向标准输出
既然这部分调试内容是往stdout写入的,就可以通过自定义双写流,让stdout的输出同时保留在控制台、追加写入到日志文件。注意不要直接把系统stdout完全替换为文件句柄,否则控制台会丢失全部输出内容。
可直接运行的示例代码:
import sys import requests import logging import http.client as http_client # 开启http.client的详细调试输出 http_client.HTTPConnection.debuglevel = 1 # 原有urllib3 logging配置保持不变 logging.basicConfig() logging.getLogger().setLevel(logging.DEBUG) requests_log = logging.getLogger("urllib3") requests_log.setLevel(logging.DEBUG) requests_log.propagate = True # 配置文件日志格式 handler = logging.FileHandler('test2.log', mode='a', encoding='utf-8') formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler.setFormatter(formatter) handler.setLevel(logging.DEBUG) requests_log.addHandler(handler) # 自定义双写流:同时把stdout内容写到控制台和日志文件 class DualWriter: def __init__(self, *target_writers): self.target_writers = target_writers def write(self, content): for writer in self.target_writers: writer.write(content) def flush(self): for writer in self.target_writers: writer.flush() # 替换系统stdout为双写对象 log_writer = open('test2.log', 'a', encoding='utf-8') sys.stdout = DualWriter(sys.__stdout__, log_writer) # 发起请求 requests.get('https://httpbin.org/headers')
该方案的缺陷:抓取到的stdout调试内容没有统一的日志格式,会和原有logging输出的内容混杂,缺少时间戳、日志级别标记,日志可读性较差。
方案2:使用urllib3原生日志能力替代http.client的debug打印(推荐)
urllib3本身已经内置了完整的请求/响应细节日志能力,完全不需要依赖http.client.debuglevel的stdout打印。只要打开对应层级logger的DEBUG级别,所有请求发送、响应返回的详细内容都会通过logging体系正常投递,自然就能被你的文件日志处理器捕获,和原有日志保持统一格式。
需要调整的配置逻辑:
- 删除
http_client.HTTPConnection.debuglevel = 1代码行,避免冗余的stdout打印 - 除了顶层的
urllib3logger,还要把负责连接细节日志的urllib3.connectionlogger设置为DEBUG级别,确保请求/响应头的内容能正常投递
调整后的核心配置片段:
import requests import logging # 不需要手动开启http.client的debuglevel # http_client.HTTPConnection.debuglevel = 1 logging.basicConfig() logging.getLogger().setLevel(logging.DEBUG) # 配置统一的文件日志处理器 handler = logging.FileHandler('test2.log', mode='a', encoding='utf-8') formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler.setFormatter(formatter) handler.setLevel(logging.DEBUG) # 遍历挂载需要开启debug的logger for logger_name in ["urllib3", "urllib3.connection"]: logger = logging.getLogger(logger_name) logger.setLevel(logging.DEBUG) logger.addHandler(handler) logger.propagate = True requests.get('https://httpbin.org/headers')
该方案的优势:所有日志都走统一的logging管道,格式整齐、可追溯,没有冗余的stdout输出,是生产环境推荐的配置方式。
内容的提问来源于stack exchange,提问作者Santhosh
相关产品推荐
相关产品推荐

