| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- import logging
- import json
- from datetime import datetime
- import os
- import sys
- from typing import Dict, Any
- from pathlib import Path
- # 确保日志目录存在
- LOG_DIR = Path("chat_logs")
- LOG_DIR.mkdir(exist_ok=True)
- # 详细日志目录结构
- DETAILED_LOG_DIR = LOG_DIR / "detailed"
- DETAILED_LOG_DIR.mkdir(exist_ok=True)
- # 全局变量
- current_log_date = datetime.now().strftime("%Y%m%d")
- chat_logger = None # 初始化为None,在setup_logging中初始化
- def setup_logging(force_reconfigure=False):
- """配置日志系统"""
- global chat_logger
- # 创建或重新获取logger
- logger = logging.getLogger("chat_logger")
- logger.setLevel(logging.INFO)
- # 文件处理器 - 按天分割
- today_str = datetime.now().strftime("%Y%m%d")
- log_file = LOG_DIR / f"chat_{today_str}.log"
- # 检查是否需要重新配置(强制重新配置或没有handlers)
- needs_reconfigure = force_reconfigure or not logger.handlers
- if needs_reconfigure:
- # 清理旧的handler
- for handler in logger.handlers[:]:
- handler.close()
- logger.removeHandler(handler)
- # 创建新的文件处理器
- file_handler = logging.FileHandler(log_file, encoding="utf-8")
- file_handler.setLevel(logging.INFO)
- # 控制台处理器
- console_handler = logging.StreamHandler()
- console_handler.setLevel(logging.INFO)
- # 确保控制台编码
- try:
- if hasattr(sys.stdout, "reconfigure") and sys.stdout.encoding != "utf-8":
- sys.stdout.reconfigure(encoding="utf-8")
- except:
- pass
- # 格式化
- formatter = logging.Formatter(
- "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
- datefmt="%Y-%m-%d %H:%M:%S",
- )
- file_handler.setFormatter(formatter)
- console_handler.setFormatter(formatter)
- logger.addHandler(file_handler)
- logger.addHandler(console_handler)
- chat_logger = logger
- return logger
- # 初始化日志
- chat_logger = setup_logging()
- def get_detailed_log_path(user_id: str, timestamp: datetime = None) -> Path:
- """获取详细日志文件的路径"""
- if timestamp is None:
- timestamp = datetime.now()
- # 按日期创建目录
- date_str = timestamp.strftime("%Y%m%d")
- date_dir = DETAILED_LOG_DIR / date_str
- date_dir.mkdir(exist_ok=True)
- # 生成文件名
- filename = f"{user_id}_{timestamp.strftime('%Y%m%d_%H%M%S')}.json"
- return date_dir / filename
- def _reconfigure_logging():
- """重新配置日志处理器,用于处理跨日情况"""
- global chat_logger, current_log_date
- today = datetime.now().strftime("%Y%m%d")
- if today != current_log_date:
- # 记录日期变化信息到当前日志文件
- if chat_logger:
- chat_logger.info(
- f"检测到日期变化: {current_log_date} -> {today}, 重新配置日志处理器"
- )
- current_log_date = today
- # 强制重新配置日志处理器
- setup_logging(force_reconfigure=True)
- def log_chat_entry(user_id: str, user_message: str, agent_response: Dict[str, Any]):
- """记录完整的对话日志"""
- try:
- # 每次调用都检查日期是否变化
- _reconfigure_logging()
- timestamp = datetime.now()
- # 构建日志条目
- log_entry = {
- "timestamp": timestamp.isoformat(),
- "user_id": user_id,
- "user_message": user_message,
- "thread_id": agent_response.get("thread_id", ""),
- "agent_response": {
- "final_answer": agent_response.get("final_answer", ""),
- "all_ai_messages_count": len(agent_response.get("all_ai_messages", [])),
- "all_messages_count": len(agent_response.get("all_messages", [])),
- "tool_calls_count": len(agent_response.get("tool_calls", [])),
- },
- "all_messages": [
- {
- "type": msg.get("type"),
- "content": msg.get("content", "")[:500], # 限制长度
- "tool_calls": msg.get("tool_calls"),
- "index": msg.get("index"),
- }
- for msg in agent_response.get("all_messages", [])
- ],
- "tool_calls": agent_response.get("tool_calls", []),
- }
- # 记录到日志文件
- chat_logger.info(f"对话记录 - Thread: {user_id}")
- chat_logger.info(f"用户消息: {user_message}")
- chat_logger.info(
- f"Agent响应: {agent_response.get('final_answer', '')[:200]}..."
- )
- # 保存详细日志到单独文件
- detailed_log_file = get_detailed_log_path(user_id, timestamp)
- with open(detailed_log_file, "w", encoding="utf-8") as f:
- json.dump(log_entry, f, ensure_ascii=False, indent=2)
- chat_logger.info(f"详细日志已保存到: {detailed_log_file}")
- except Exception as e:
- chat_logger.error(f"记录日志时出错: {str(e)}")
|