logger.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import logging
  2. import json
  3. from datetime import datetime
  4. import os
  5. import sys
  6. from typing import Dict, Any
  7. from pathlib import Path
  8. # 确保日志目录存在
  9. LOG_DIR = Path("chat_logs")
  10. LOG_DIR.mkdir(exist_ok=True)
  11. # 详细日志目录结构
  12. DETAILED_LOG_DIR = LOG_DIR / "detailed"
  13. DETAILED_LOG_DIR.mkdir(exist_ok=True)
  14. # 全局变量
  15. current_log_date = datetime.now().strftime("%Y%m%d")
  16. chat_logger = None # 初始化为None,在setup_logging中初始化
  17. def setup_logging(force_reconfigure=False):
  18. """配置日志系统"""
  19. global chat_logger
  20. # 创建或重新获取logger
  21. logger = logging.getLogger("chat_logger")
  22. logger.setLevel(logging.INFO)
  23. # 文件处理器 - 按天分割
  24. today_str = datetime.now().strftime("%Y%m%d")
  25. log_file = LOG_DIR / f"chat_{today_str}.log"
  26. # 检查是否需要重新配置(强制重新配置或没有handlers)
  27. needs_reconfigure = force_reconfigure or not logger.handlers
  28. if needs_reconfigure:
  29. # 清理旧的handler
  30. for handler in logger.handlers[:]:
  31. handler.close()
  32. logger.removeHandler(handler)
  33. # 创建新的文件处理器
  34. file_handler = logging.FileHandler(log_file, encoding="utf-8")
  35. file_handler.setLevel(logging.INFO)
  36. # 控制台处理器
  37. console_handler = logging.StreamHandler()
  38. console_handler.setLevel(logging.INFO)
  39. # 确保控制台编码
  40. try:
  41. if hasattr(sys.stdout, "reconfigure") and sys.stdout.encoding != "utf-8":
  42. sys.stdout.reconfigure(encoding="utf-8")
  43. except:
  44. pass
  45. # 格式化
  46. formatter = logging.Formatter(
  47. "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
  48. datefmt="%Y-%m-%d %H:%M:%S",
  49. )
  50. file_handler.setFormatter(formatter)
  51. console_handler.setFormatter(formatter)
  52. logger.addHandler(file_handler)
  53. logger.addHandler(console_handler)
  54. chat_logger = logger
  55. return logger
  56. # 初始化日志
  57. chat_logger = setup_logging()
  58. def get_detailed_log_path(user_id: str, timestamp: datetime = None) -> Path:
  59. """获取详细日志文件的路径"""
  60. if timestamp is None:
  61. timestamp = datetime.now()
  62. # 按日期创建目录
  63. date_str = timestamp.strftime("%Y%m%d")
  64. date_dir = DETAILED_LOG_DIR / date_str
  65. date_dir.mkdir(exist_ok=True)
  66. # 生成文件名
  67. filename = f"{user_id}_{timestamp.strftime('%Y%m%d_%H%M%S')}.json"
  68. return date_dir / filename
  69. def _reconfigure_logging():
  70. """重新配置日志处理器,用于处理跨日情况"""
  71. global chat_logger, current_log_date
  72. today = datetime.now().strftime("%Y%m%d")
  73. if today != current_log_date:
  74. # 记录日期变化信息到当前日志文件
  75. if chat_logger:
  76. chat_logger.info(
  77. f"检测到日期变化: {current_log_date} -> {today}, 重新配置日志处理器"
  78. )
  79. current_log_date = today
  80. # 强制重新配置日志处理器
  81. setup_logging(force_reconfigure=True)
  82. def log_chat_entry(user_id: str, user_message: str, agent_response: Dict[str, Any]):
  83. """记录完整的对话日志"""
  84. try:
  85. # 每次调用都检查日期是否变化
  86. _reconfigure_logging()
  87. timestamp = datetime.now()
  88. # 构建日志条目
  89. log_entry = {
  90. "timestamp": timestamp.isoformat(),
  91. "user_id": user_id,
  92. "user_message": user_message,
  93. "thread_id": agent_response.get("thread_id", ""),
  94. "agent_response": {
  95. "final_answer": agent_response.get("final_answer", ""),
  96. "all_ai_messages_count": len(agent_response.get("all_ai_messages", [])),
  97. "all_messages_count": len(agent_response.get("all_messages", [])),
  98. "tool_calls_count": len(agent_response.get("tool_calls", [])),
  99. },
  100. "all_messages": [
  101. {
  102. "type": msg.get("type"),
  103. "content": msg.get("content", "")[:500], # 限制长度
  104. "tool_calls": msg.get("tool_calls"),
  105. "index": msg.get("index"),
  106. }
  107. for msg in agent_response.get("all_messages", [])
  108. ],
  109. "tool_calls": agent_response.get("tool_calls", []),
  110. }
  111. # 记录到日志文件
  112. chat_logger.info(f"对话记录 - Thread: {user_id}")
  113. chat_logger.info(f"用户消息: {user_message}")
  114. chat_logger.info(
  115. f"Agent响应: {agent_response.get('final_answer', '')[:200]}..."
  116. )
  117. # 保存详细日志到单独文件
  118. detailed_log_file = get_detailed_log_path(user_id, timestamp)
  119. with open(detailed_log_file, "w", encoding="utf-8") as f:
  120. json.dump(log_entry, f, ensure_ascii=False, indent=2)
  121. chat_logger.info(f"详细日志已保存到: {detailed_log_file}")
  122. except Exception as e:
  123. chat_logger.error(f"记录日志时出错: {str(e)}")