chore(debug): 新增对话保存写入追踪日志,捕获空覆盖调用栈
临时调试代码:每次保存对话时记录 old/new 消息数与项目内调用栈到 logs/conversation_save_debug.log(JSONL),wipe_suspect 时额外打印告警。 用于排查对话消息被清空问题,确认修复后应移除。
This commit is contained in:
parent
766080c05c
commit
0dd51c7b48
@ -24,6 +24,69 @@ try:
|
||||
except Exception:
|
||||
perf_log = None
|
||||
|
||||
try:
|
||||
from config import LOGS_DIR as _CONV_SAVE_LOG_DIR
|
||||
except Exception:
|
||||
_CONV_SAVE_LOG_DIR = None
|
||||
|
||||
|
||||
def _debug_conversation_save_trace(conversation_id: str, file_path, data: Dict):
|
||||
"""[临时调试] 记录每次对话文件写入,重点捕获「非空被空覆盖」的调用栈。
|
||||
|
||||
输出: logs/conversation_save_debug.log (JSONL)
|
||||
排查完「对话消息被清空」问题后应移除。
|
||||
"""
|
||||
try:
|
||||
import traceback
|
||||
new_msgs = data.get("messages") if isinstance(data, dict) else None
|
||||
new_len = len(new_msgs) if isinstance(new_msgs, list) else -1
|
||||
old_len = None
|
||||
try:
|
||||
p = Path(file_path)
|
||||
if p.exists():
|
||||
old_data = json.loads(p.read_text(encoding="utf-8"))
|
||||
old_msgs = old_data.get("messages")
|
||||
old_len = len(old_msgs) if isinstance(old_msgs, list) else None
|
||||
except Exception:
|
||||
old_len = None
|
||||
wipe_suspect = bool(old_len and new_len == 0)
|
||||
# 只保留项目内调用帧,排除标准库/第三方
|
||||
try:
|
||||
repo_root = Path(__file__).resolve().parents[2]
|
||||
except Exception:
|
||||
repo_root = None
|
||||
frames = []
|
||||
for fr in traceback.extract_stack()[:-2]:
|
||||
fn = str(fr.filename)
|
||||
if repo_root and not fn.startswith(str(repo_root)):
|
||||
continue
|
||||
if "/.astrion/" in fn or "site-packages" in fn:
|
||||
continue
|
||||
rel = fn[len(str(repo_root)) + 1:] if repo_root and fn.startswith(str(repo_root)) else fn
|
||||
frames.append(f"{rel}:{fr.lineno}:{fr.name}")
|
||||
record = {
|
||||
"ts": datetime.now().isoformat(),
|
||||
"event": "conversation_save",
|
||||
"conversation_id": conversation_id,
|
||||
"old_msg_len": old_len,
|
||||
"new_msg_len": new_len,
|
||||
"wipe_suspect": wipe_suspect,
|
||||
"title": (data.get("title") if isinstance(data, dict) else None),
|
||||
"thread": threading.current_thread().name,
|
||||
"stack_tail": frames[-14:],
|
||||
}
|
||||
if _CONV_SAVE_LOG_DIR:
|
||||
log_dir = Path(_CONV_SAVE_LOG_DIR)
|
||||
else:
|
||||
log_dir = Path(DATA_DIR).parent / "logs"
|
||||
log_dir.mkdir(parents=True, exist_ok=True)
|
||||
with open(log_dir / "conversation_save_debug.log", "a", encoding="utf-8") as f:
|
||||
f.write(json.dumps(record, ensure_ascii=False) + "\n")
|
||||
if wipe_suspect:
|
||||
print(f"🚨 [ConvSaveDebug] 对话 {conversation_id} 消息将被空列表覆盖!栈: {frames[-14:]}")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@dataclass
|
||||
class ConversationMetadata:
|
||||
"""对话元数据"""
|
||||
@ -194,6 +257,7 @@ class CrudMixin:
|
||||
try:
|
||||
# 确保Token统计数据有效
|
||||
data = self._validate_token_statistics(data)
|
||||
_debug_conversation_save_trace(conversation_id, file_path, data)
|
||||
with self._io_lock:
|
||||
self._atomic_write_json(file_path, data)
|
||||
except Exception as e:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user