celery 升级优化V2 | 日志调整 | 前端BUG修复

This commit is contained in:
2026-07-23 12:07:23 +08:00
parent 06bf5c4db7
commit 2931e67226
37 changed files with 3122 additions and 1613 deletions
@@ -21,7 +21,6 @@ MODULE_GENERATION_LOG_ROOT = os.path.join(LOG_BASE_DIR, "ModuleGeneration")
AI_MODEL_LOG_ROOT = LOG_DIR
SENSITIVE_KEY_PATTERNS = (
"secret",
"token",
"authorization",
"cookie",
"credential",
@@ -30,9 +29,28 @@ SENSITIVE_KEY_PATTERNS = (
"access_key",
"api_key",
"apikey",
"security-token",
"x-tos-security-token",
"security_token",
)
SENSITIVE_TOKEN_KEYS = {
"token",
"access_token",
"refresh_token",
"bearer_token",
"security_token",
"x_tos_security_token",
}
FILE_BASE64_KEYS = {
"b64_json",
"file_data",
"file_base64",
"content_base64",
"image_base64",
"video_base64",
"audio_base64",
}
FILE_DATA_URI_MIME_PREFIXES = ("image/", "video/", "audio/")
FILE_DATA_URI_MIME_TYPES = {"application/pdf", "application/octet-stream"}
FILE_BASE64_PREVIEW_CHARS = 30
def _safe_name(value: str | None, default: str = "unknown") -> str:
@@ -49,7 +67,41 @@ def _mask_string(value: str) -> str:
def _is_sensitive_key(key: str) -> bool:
lower = str(key).replace("-", "_").lower()
return lower == "sign" or any(pattern in lower for pattern in SENSITIVE_KEY_PATTERNS)
if lower == "sign" or lower in SENSITIVE_TOKEN_KEYS:
return True
return any(pattern in lower for pattern in SENSITIVE_KEY_PATTERNS)
def _decoded_base64_size(value: str) -> int:
compact = "".join(value.split())
if not compact:
return 0
padding = 2 if compact.endswith("==") else (1 if compact.endswith("=") else 0)
return max(0, (len(compact) * 3) // 4 - padding)
def _file_base64_preview(value: str, key_path: tuple[str, ...]) -> str | None:
data_uri = re.match(r"^data:([^;,]+);base64,(.*)$", value, flags=re.IGNORECASE | re.DOTALL)
prefix = ""
payload = value
is_file = False
if data_uri:
mime = str(data_uri.group(1) or "").lower()
is_file = mime.startswith(FILE_DATA_URI_MIME_PREFIXES) or mime in FILE_DATA_URI_MIME_TYPES
prefix = value[: value.find(",") + 1]
payload = data_uri.group(2)
elif key_path and key_path[-1].replace("-", "_").lower() in FILE_BASE64_KEYS:
# Raw base64 is treated as file content only for an explicit file field.
is_file = len(value) >= 64 and bool(re.fullmatch(r"[A-Za-z0-9+/=\s]+", value))
if not is_file:
return None
compact = "".join(payload.split())
preview = compact[:FILE_BASE64_PREVIEW_CHARS]
total_bytes = _decoded_base64_size(compact)
preview_bytes = min(total_bytes, (len(preview) * 3) // 4)
remaining_bytes = max(0, total_bytes - preview_bytes)
return f"{prefix}{preview}...<remaining_file_bytes:{remaining_bytes}>"
def _sanitize_url(value: str) -> str:
@@ -65,10 +117,13 @@ def _sanitize_url(value: str) -> str:
return value
def sanitize_log_value(value: Any) -> Any:
def sanitize_log_value(value: Any, *, key_path: tuple[str, ...] = ()) -> Any:
if value is None:
return None
if isinstance(value, str):
file_preview = _file_base64_preview(value, key_path)
if file_preview is not None:
return file_preview
text = _sanitize_url(value) if value.startswith(("http://", "https://")) else value
if len(text) > MAX_LOG_FIELD_LENGTH:
return text[:MAX_LOG_FIELD_LENGTH] + f"...<truncated:{len(text) - MAX_LOG_FIELD_LENGTH}>"
@@ -77,10 +132,14 @@ def sanitize_log_value(value: Any) -> Any:
output: dict[str, Any] = {}
for k, v in value.items():
key = str(k)
output[key] = "***" if _is_sensitive_key(key) else sanitize_log_value(v)
output[key] = (
"***"
if _is_sensitive_key(key)
else sanitize_log_value(v, key_path=(*key_path, key))
)
return output
if isinstance(value, list):
return [sanitize_log_value(v) for v in value]
if isinstance(value, (list, tuple)):
return [sanitize_log_value(v, key_path=(*key_path, str(index))) for index, v in enumerate(value)]
return value
@@ -262,6 +321,13 @@ def log_ai_model_event(
*,
event_type: str,
module: str | None = None,
step_code: str | None = None,
call_id: str | None = None,
event_phase: str | None = None,
owner_type: str | None = None,
owner_id: str | None = None,
generation_attempt_no: int | None = None,
latency_ms: int | None = None,
event_status: str = "success",
source: str | None = None,
trace_id: str | None = None,
@@ -314,8 +380,19 @@ def log_ai_model_event(
)
entry.update(
{
"call_id": call_id,
"event_phase": event_phase or event_type,
"step_code": step_code,
"owner_type": owner_type,
"owner_id": owner_id,
"generation_attempt_no": generation_attempt_no,
"latency_ms": latency_ms,
# Preserve the legacy fields for existing log readers while also
# exposing unambiguous configuration/provider model names.
"model_name": model_config_name,
"model_id": model_name,
"model_config_name": model_config_name,
"provider_model_name": model_name,
"model_config_id": model_config_id,
"provider": provider,
"api_base": api_base,