日志改为摘要 + 有界预览:单次请求日志 6940KB → 2.8KB
/convert/start 原先 logger.info 直接 dump 整份结果(json.dumps(indent=2)):实测
1MB 输入 → 20188 条 → 6.9MB 日志,是原文的 15%,indent 还要再乘 1.4。转几份族谱
日志文件就会被撑爆。
改为:
- 一行摘要:输入字数、结果条数、类型分布、耗时(格式与 batch 接口的日志保持一致)
- 前 LOG_PREVIEW_ITEMS(=10) 条结果预览,体积有硬上界
- 新增 _result_summary() helper
类型分布一行能看出解析形态(如 {'干支纪年': 15624, '古代纪年': 147, ...}),
排查"整批变成未匹配"这类回归比翻全量结果还快。明细请用接口返回值。
验证:单次 1MB 请求日志 2.8KB(降 2428x);/convert/start、/convert/batch、
403 鉴权、空文本四条路径均正常;pytest 260 passed。
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
+23
-1
@@ -1,4 +1,5 @@
|
|||||||
import json
|
import json
|
||||||
|
from collections import Counter
|
||||||
from time import perf_counter
|
from time import perf_counter
|
||||||
from fastapi import FastAPI, HTTPException, Header, Request
|
from fastapi import FastAPI, HTTPException, Header, Request
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
@@ -20,12 +21,26 @@ app.add_middleware(
|
|||||||
# batch 接口单次请求的条目上限(防滥用)
|
# batch 接口单次请求的条目上限(防滥用)
|
||||||
BATCH_MAX_ITEMS = 1000
|
BATCH_MAX_ITEMS = 1000
|
||||||
|
|
||||||
|
# 日志里最多预览多少条结果。完整结果序列化后体积可达数 MB
|
||||||
|
# (实测 1MB 输入 → 20188 条 → 6.9MB JSON,是原文的 15%,含缩进还要再乘 1.4),
|
||||||
|
# 全量落盘会迅速撑爆日志文件。
|
||||||
|
LOG_PREVIEW_ITEMS = 10
|
||||||
|
|
||||||
|
|
||||||
def _check_auth(Authorization: str):
|
def _check_auth(Authorization: str):
|
||||||
if Authorization != "3FFA6A4B073CF065969630692331A873":
|
if Authorization != "3FFA6A4B073CF065969630692331A873":
|
||||||
raise HTTPException(status_code=403, detail="未授权的操作")
|
raise HTTPException(status_code=403, detail="未授权的操作")
|
||||||
|
|
||||||
|
|
||||||
|
def _result_summary(res: list) -> str:
|
||||||
|
"""一行摘要:结果条数 + 类型分布(如 {'古代纪年': 12, '干支纪年': 3})。
|
||||||
|
|
||||||
|
/convert/start 的日志只记摘要与有界预览,不记全量结果——看明细请用接口返回值。
|
||||||
|
"""
|
||||||
|
kinds = Counter(r["类型"] for r in res)
|
||||||
|
return f"{len(res)} 条, 类型分布 {dict(kinds)}"
|
||||||
|
|
||||||
|
|
||||||
def _parse_urlencoded_content(body: bytes) -> str:
|
def _parse_urlencoded_content(body: bytes) -> str:
|
||||||
"""手动解析 x-www-form-urlencoded 的 content 字段:绕过 starlette 1MB 表单限制"""
|
"""手动解析 x-www-form-urlencoded 的 content 字段:绕过 starlette 1MB 表单限制"""
|
||||||
from urllib.parse import parse_qs
|
from urllib.parse import parse_qs
|
||||||
@@ -47,8 +62,15 @@ async def convert_str(
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
content = _parse_urlencoded_content(await request.body())
|
content = _parse_urlencoded_content(await request.body())
|
||||||
|
t0 = perf_counter()
|
||||||
res = convert_text(content)
|
res = convert_text(content)
|
||||||
logger.info(f"转换结果: {json.dumps(res, ensure_ascii=False, indent=2)}")
|
dt = perf_counter() - t0
|
||||||
|
# 只记摘要 + 前 N 条预览(格式与 batch 接口的日志保持一致)
|
||||||
|
logger.info(f"转换完成: 输入 {len(content)} 字, {_result_summary(res)}, "
|
||||||
|
f"耗时 {dt * 1000:.0f}ms")
|
||||||
|
if res:
|
||||||
|
head = res[:LOG_PREVIEW_ITEMS]
|
||||||
|
logger.info(f"结果前 {len(head)} 条: {json.dumps(head, ensure_ascii=False)}")
|
||||||
return JSONResponse(content={"code": 0, "result": res})
|
return JSONResponse(content={"code": 0, "result": res})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"转换异常: {str(e)}")
|
logger.error(f"转换异常: {str(e)}")
|
||||||
|
|||||||
Reference in New Issue
Block a user