feat: 添加超详细的HTTP请求日志系统

详细日志增强:
- HTTP请求URL和超时配置
- 完整的请求头信息 (Authorization脱敏显示)
- 请求体大小和内容预览
- HTTP响应状态码和原因短语
- 完整的响应头信息
- 响应体大小和内容预览

 重试机制日志:
- 每次尝试的详细时间统计
- 失败原因的具体记录
- 重试等待过程的状态显示
- 成功/失败的明确标识

 错误分析支持:
- JSON解析错误的详细信息
- 错误响应的完整内容
- 候选结果数量统计
- 内容预览和截断显示

 调试友好:
- 分步骤的详细日志
- 时间戳和耗时统计
- 敏感信息的安全处理
- 结构化的日志输出

现在可以完整分析API调用的每个环节!
This commit is contained in:
imeepos 2025-07-14 13:27:04 +08:00
parent ea2c72ea05
commit e626521ac2
1 changed files with 95 additions and 10 deletions

View File

@ -337,21 +337,31 @@ impl GeminiService {
// 重试机制
let mut last_error = None;
println!("🔄 开始重试机制,最大重试次数: {}", self.config.max_retries);
for attempt in 0..self.config.max_retries {
println!("🔄 尝试 {}/{}", attempt + 1, self.config.max_retries);
println!("🎯 === 第 {}/{} 次尝试 ===", attempt + 1, self.config.max_retries);
let attempt_start = std::time::Instant::now();
match self.send_generate_request(&generate_url, &client_config, &request_data).await {
Ok(result) => {
println!("✅ 成功获取Gemini分析结果");
let attempt_duration = attempt_start.elapsed();
println!("✅ 第 {} 次尝试成功!耗时: {:?}", attempt + 1, attempt_duration);
println!("🎉 成功获取Gemini分析结果");
return self.parse_gemini_response_content(&result);
}
Err(e) => {
let attempt_duration = attempt_start.elapsed();
last_error = Some(e);
println!("⚠️ 尝试 {}/{} 失败: {}", attempt + 1, self.config.max_retries, last_error.as_ref().unwrap());
println!("❌ 第 {} 次尝试失败,耗时: {:?}", attempt + 1, attempt_duration);
println!("📝 失败原因: {}", last_error.as_ref().unwrap());
if attempt < self.config.max_retries - 1 {
println!("⏳ 等待 {} 秒后重试...", self.config.retry_delay);
println!("⏳ 等待 {} 秒后进行第 {}重试...", self.config.retry_delay, attempt + 2);
tokio::time::sleep(tokio::time::Duration::from_secs(self.config.retry_delay)).await;
println!("🔄 重试等待结束,准备下一次尝试");
} else {
println!("💔 已达到最大重试次数,放弃重试");
}
}
}
@ -367,39 +377,114 @@ impl GeminiService {
client_config: &ClientConfig,
request_data: &GenerateContentRequest,
) -> Result<GeminiResponse> {
println!("🌐 准备发送HTTP请求...");
println!("📍 请求URL: {}", url);
println!("⏱️ 超时时间: {}", self.config.timeout);
let mut request_builder = self.client
.post(url)
.timeout(tokio::time::Duration::from_secs(self.config.timeout))
.json(request_data);
// 添加请求头
// 添加请求头并记录日志
println!("📋 添加请求头:");
for (key, value) in &client_config.headers {
println!(" {}: {}", key, if key == "Authorization" {
format!("Bearer {}...", &value[7..std::cmp::min(27, value.len())])
} else {
value.clone()
});
request_builder = request_builder.header(key, value);
}
// 记录请求体信息
println!("📦 请求体信息:");
println!(" Content-Type: application/json");
println!(" Body size: {} bytes", serde_json::to_string(request_data).unwrap_or_default().len());
// 记录请求体内容(截断显示)
let request_json = serde_json::to_string_pretty(request_data).unwrap_or_default();
let preview_len = std::cmp::min(1000, request_json.len());
println!("📄 请求体预览 (前{}字符):", preview_len);
println!("{}", &request_json[..preview_len]);
if request_json.len() > 1000 {
println!(" ... (请求体已截断,总长度: {} 字符)", request_json.len());
}
println!("🚀 发送HTTP请求...");
let response = request_builder.send().await?;
let status = response.status();
let headers = response.headers().clone();
println!("📥 生成响应状态: {}", status);
println!("📋 生成响应头: {:?}", headers);
println!("📥 HTTP响应接收完成");
println!("📊 响应状态: {} {}", status.as_u16(), status.canonical_reason().unwrap_or("Unknown"));
println!("📋 响应头详情:");
for (name, value) in headers.iter() {
println!(" {}: {}", name, value.to_str().unwrap_or("<binary>"));
}
// 记录响应大小
if let Some(content_length) = headers.get("content-length") {
println!("📏 响应大小: {} bytes", content_length.to_str().unwrap_or("unknown"));
}
if !status.is_success() {
println!("❌ HTTP请求失败状态码: {}", status);
let error_text = response.text().await.unwrap_or_default();
println!("❌ 生成失败响应体: {}", error_text);
println!("📄 错误响应体长度: {} 字符", error_text.len());
println!("📄 错误响应体内容:");
println!("{}", error_text);
// 尝试解析错误响应为JSON
if let Ok(error_json) = serde_json::from_str::<serde_json::Value>(&error_text) {
println!("🔍 解析后的错误JSON:");
println!("{}", serde_json::to_string_pretty(&error_json).unwrap_or_default());
}
return Err(anyhow!("API请求失败: {} - {}", status, error_text));
}
let response_text = response.text().await?;
println!("📄 生成成功响应: {}", response_text);
println!("✅ HTTP请求成功");
println!("📄 响应体长度: {} 字符", response_text.len());
// 显示响应体预览
let preview_len = std::cmp::min(2000, response_text.len());
println!("📄 响应体预览 (前{}字符):", preview_len);
println!("{}", &response_text[..preview_len]);
if response_text.len() > 2000 {
println!(" ... (响应体已截断,总长度: {} 字符)", response_text.len());
}
println!("🔍 开始解析JSON响应...");
let gemini_response: GeminiResponse = serde_json::from_str(&response_text)
.map_err(|e| anyhow!("解析生成响应失败: {} - 响应内容: {}", e, response_text))?;
.map_err(|e| {
println!("❌ JSON解析失败: {}", e);
println!("📄 完整响应内容: {}", response_text);
anyhow!("解析生成响应失败: {} - 响应内容: {}", e, response_text)
})?;
println!("✅ JSON解析成功");
println!("📊 候选结果数量: {}", gemini_response.candidates.len());
if gemini_response.candidates.is_empty() {
println!("❌ API返回的候选结果为空");
return Err(anyhow!("API返回结果为空"));
}
// 记录第一个候选结果的信息
if let Some(first_candidate) = gemini_response.candidates.first() {
println!("📝 第一个候选结果的部分数量: {}", first_candidate.content.parts.len());
if let Some(first_part) = first_candidate.content.parts.first() {
let text_preview = if first_part.text.len() > 200 {
format!("{}...", &first_part.text[..200])
} else {
first_part.text.clone()
};
println!("📝 第一个部分内容预览: {}", text_preview);
}
}
Ok(gemini_response)
}