Fix opera log non-json data overload (#998)

* fix: skip non-json body logging for multipart uploads

* Update truncation implementation
This commit is contained in:
shj366
2026-01-10 18:23:02 +08:00
committed by GitHub
parent cbe4e5ebe0
commit 326bdf9a17

View File

@@ -1,3 +1,4 @@
import json
import time
from asyncio import Queue
@@ -150,7 +151,7 @@ class OperaLogMiddleware(BaseHTTPMiddleware):
return response
async def get_request_args(self, request: Request) -> dict[str, Any] | None:
async def get_request_args(self, request: Request) -> dict[str, Any] | None: # noqa: C901
"""
获取请求参数
@@ -178,26 +179,65 @@ class OperaLogMiddleware(BaseHTTPMiddleware):
if body_data:
# 注意:非 json 数据默认使用 data 作为键
if 'application/json' not in content_type:
args['data'] = str(body_data)
args['data'] = body_data.decode('utf-8', 'ignore') if isinstance(body_data, bytes) else str(body_data)
else:
json_data = await request.json()
if isinstance(json_data, dict):
args['json'] = await self.desensitization(json_data)
else:
args['data'] = str(body_data)
args['data'] = str(json_data)
# 表单参数
form_data = await request.form()
if len(form_data) > 0:
serialized_form = {}
for k, v in form_data.items():
form_data = {k: v.filename} if isinstance(v, UploadFile) else {k: v}
if isinstance(v, UploadFile):
serialized_form[k] = {
'filename': v.filename,
'content_type': v.content_type,
'size': v.size,
}
else:
serialized_form[k] = v
if 'multipart/form-data' not in content_type:
args['x-www-form-urlencoded'] = await self.desensitization(form_data)
args['x-www-form-urlencoded'] = await self.desensitization(serialized_form)
else:
args['form-data'] = await self.desensitization(form_data)
args['form-data'] = await self.desensitization(serialized_form)
if args:
args = self.truncate(args)
return args or None
@staticmethod
def truncate(args: dict[str, Any]) -> dict[str, Any]:
"""
截断处理
:param args: 需要截断的请求参数字典
:return:
"""
max_size = 10240 # 数据最大大小(字节)
try:
args_str = json.dumps(args, ensure_ascii=False)
args_size = len(args_str.encode('utf-8'))
if args_size > max_size:
truncated_str = args_str[:max_size]
return {
'_truncated': True,
'_original_size': args_size,
'_max_size': max_size,
'_message': f'数据过大已截断:原始大小 {args_size} 字节,限制 {max_size} 字节',
'data_preview': truncated_str,
}
except Exception as e:
log.error(f'请求参数截断处理失败:{e}')
return args
@staticmethod
@sync_to_async
def desensitization(args: dict[str, Any]) -> dict[str, Any]: