refactor(logging): introduce centralized logging and FastAPI lifespan
Some checks failed
Build and Push Docker / build-and-push (push) Failing after 2m38s

This commit is contained in:
gameloader
2025-10-13 10:17:19 +08:00
parent 0e5199d3c0
commit f1a48874d0
5 changed files with 175 additions and 24 deletions

View File

@ -4,6 +4,7 @@ import threading
from datetime import datetime from datetime import datetime
import sys import sys
import os import os
import logging
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from config import ( from config import (
@ -13,6 +14,8 @@ from config import (
from api.doubao_tts import text_to_speech from api.doubao_tts import text_to_speech
from memory_module.memory_integration import Mem0Integration from memory_module.memory_integration import Mem0Integration
logger = logging.getLogger(__name__)
class ChatService: class ChatService:
def __init__(self, user_id: str = None): def __init__(self, user_id: str = None):
@ -25,7 +28,7 @@ class ChatService:
if self._initialized: if self._initialized:
return return
print(f"[INFO] Initializing Mem0 integration for user: {self.user_id}") logger.info(f"Initializing Mem0 integration for user: {self.user_id}")
self._initialized = True self._initialized = True
def chat(self, user_input: str, include_audio: bool = True) -> Dict[str, Any]: def chat(self, user_input: str, include_audio: bool = True) -> Dict[str, Any]:

View File

@ -1,9 +1,25 @@
from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException from fastapi import FastAPI, HTTPException
from pydantic import BaseModel from pydantic import BaseModel
from typing import Optional from typing import Optional
import uvicorn import uvicorn
import os
import sys
# 添加项目根目录到Python路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from chat_service import ChatService from chat_service import ChatService
from logging_config import setup_logging, get_logger
# 设置日志
setup_logging(
level=os.getenv('LOG_LEVEL', 'INFO'),
enable_file_logging=os.getenv('ENABLE_FILE_LOGGING', 'false').lower() == 'true'
)
# 获取logger
logger = get_logger(__name__)
# 请求和响应模型 # 请求和响应模型
@ -23,21 +39,30 @@ class ChatResponse(BaseModel):
audio_error: Optional[str] = None audio_error: Optional[str] = None
# 创建 FastAPI 应用
app = FastAPI(
title="Mem0 Memory API",
description="基于 Mem0 的记忆增强聊天服务 API",
version="1.0.0"
)
# 全局聊天服务实例 # 全局聊天服务实例
chat_service = ChatService() chat_service = ChatService()
@app.on_event("startup") @asynccontextmanager
async def startup_event(): async def lifespan(app: FastAPI):
"""应用启动时初始化聊天服务""" """应用生命周期管理器"""
logger.info("Starting Mem0 Memory API...")
# 应用启动时初始化聊天服务
chat_service.initialize() chat_service.initialize()
logger.info("Mem0 Memory API started successfully")
yield
# 应用关闭时可以在这里执行清理操作
# 例如关闭数据库连接、释放资源等
logger.info("Shutting down Mem0 Memory API...")
# 创建 FastAPI 应用
app = FastAPI(
title="Mem0 Memory API",
description="基于 Mem0 的记忆增强聊天服务 API",
version="1.0.0",
lifespan=lifespan
)
@app.get("/") @app.get("/")

View File

@ -1,11 +1,15 @@
# main.py # main.py
import sys import sys
import logging
from haystack import Document from haystack import Document
# 需要 OpenAIDocumentEmbedder 来嵌入要写入的文档 # 需要 OpenAIDocumentEmbedder 来嵌入要写入的文档
from haystack.components.embedders import OpenAIDocumentEmbedder from haystack.components.embedders import OpenAIDocumentEmbedder
from haystack.utils import Secret from haystack.utils import Secret
# 设置logger
logger = logging.getLogger(__name__)
# 导入所需的配置和构建函数 # 导入所需的配置和构建函数
from config import ( from config import (
DEFAULT_USER_ID, DEFAULT_USER_ID,
@ -130,7 +134,7 @@ def run_chat_session(user_id: str):
print(f"Chatbot: {answer} (Tokens: {total_tokens})") print(f"Chatbot: {answer} (Tokens: {total_tokens})")
else: else:
print("Chatbot: Sorry, I couldn't generate an answer for that.") print("Chatbot: Sorry, I couldn't generate an answer for that.")
print("Debug Info (Pipeline Results):", results) # 打印完整结果以供调试 logger.debug(f"Pipeline Results: {results}") # 记录调试信息
except KeyboardInterrupt: except KeyboardInterrupt:
print("\nExiting chat session. Goodbye!") print("\nExiting chat session. Goodbye!")

117
logging_config.py Normal file
View File

@ -0,0 +1,117 @@
import logging
import logging.config
import os
from datetime import datetime
def setup_logging(
level: str = None,
log_file: str = None,
enable_file_logging: bool = False
):
"""
设置日志配置
Args:
level: 日志级别 (DEBUG, INFO, WARNING, ERROR, CRITICAL)
log_file: 日志文件名
enable_file_logging: 是否启用文件日志
"""
# 如果没有指定级别从环境变量获取默认INFO
if level is None:
level = os.getenv('LOG_LEVEL', 'INFO').upper()
# 默认日志格式
log_format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
date_format = '%Y-%m-%d %H:%M:%S'
# 基本配置
config = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': log_format,
'datefmt': date_format
},
'detailed': {
'format': '%(asctime)s - %(name)s - %(levelname)s - %(module)s - %(funcName)s - %(lineno)d - %(message)s',
'datefmt': date_format
}
},
'handlers': {
'console': {
'level': level,
'class': 'logging.StreamHandler',
'formatter': 'standard',
'stream': 'ext://sys.stdout'
}
},
'root': {
'level': level,
'handlers': ['console']
},
'loggers': {
# 针对特定模块的日志配置
'memory_integration': {
'level': level,
'handlers': ['console'],
'propagate': False
},
'chat_service': {
'level': level,
'handlers': ['console'],
'propagate': False
},
'rag_pipeline': {
'level': level,
'handlers': ['console'],
'propagate': False
},
'uvicorn': {
'level': 'INFO',
'handlers': ['console'],
'propagate': False
},
'fastapi': {
'level': 'INFO',
'handlers': ['console'],
'propagate': False
}
}
}
# 如果启用文件日志
if enable_file_logging:
if log_file is None:
# 默认日志文件名
log_dir = 'logs'
os.makedirs(log_dir, exist_ok=True)
log_file = os.path.join(
log_dir,
f"app_{datetime.now().strftime('%Y%m%d')}.log"
)
# 添加文件处理器
config['handlers']['file'] = {
'level': 'DEBUG', # 文件日志记录所有级别
'class': 'logging.handlers.RotatingFileHandler',
'filename': log_file,
'maxBytes': 10485760, # 10MB
'backupCount': 5,
'formatter': 'detailed',
'encoding': 'utf-8'
}
# 为所有logger添加文件处理器
for logger_name in config['loggers']:
config['loggers'][logger_name]['handlers'].append('file')
config['root']['handlers'].append('file')
# 应用配置
logging.config.dictConfig(config)
def get_logger(name: str) -> logging.Logger:
"""获取指定名称的logger"""
return logging.getLogger(name)

View File

@ -4,6 +4,9 @@ from datetime import datetime
import openai import openai
import threading import threading
from mem0 import Memory from mem0 import Memory
import logging
logger = logging.getLogger(__name__)
class Mem0Integration: class Mem0Integration:
@ -42,19 +45,19 @@ In your response, consider the memories above to provide a personalized answer."
memories = results.get("memories", results.get("results", [])) memories = results.get("memories", results.get("results", []))
return memories return memories
else: else:
print(f"[ERROR] Unexpected search results format: {type(results)}") logger.error(f"Unexpected search results format: {type(results)}")
return [] return []
except Exception as e: except Exception as e:
print(f"[ERROR] Failed to search memories: {e}") logger.error(f"Failed to search memories: {e}")
return [] return []
def add_memory(self, messages: List[Dict[str, str]], user_id: str, metadata: Optional[Dict] = None) -> Dict[str, Any]: def add_memory(self, messages: List[Dict[str, str]], user_id: str, metadata: Optional[Dict] = None) -> Dict[str, Any]:
"""Add a memory for the user.""" """Add a memory for the user."""
try: try:
# Debug: Print what we're trying to add # Debug: Log what we're trying to add
print(f"[DEBUG] Adding memory for user {user_id}") logger.debug(f"Adding memory for user {user_id}")
print(f"[DEBUG] Messages: {messages}") logger.debug(f"Messages: {messages}")
print(f"[DEBUG] Metadata: {metadata}") logger.debug(f"Metadata: {metadata}")
result = self.memory.add( result = self.memory.add(
messages=messages, messages=messages,
@ -63,13 +66,12 @@ In your response, consider the memories above to provide a personalized answer."
infer= False infer= False
) )
# Debug: Print the result # Debug: Log the result
print(f"[DEBUG] Add memory result: {result}") logger.debug(f"Add memory result: {result}")
return result return result
except Exception as e: except Exception as e:
print(f"[ERROR] Failed to add memory: {e}") logger.error(f"Failed to add memory: {e}")
import traceback logger.exception("Exception details:")
traceback.print_exc()
return {} return {}
def format_memories_for_prompt(self, memories: List[Any]) -> str: def format_memories_for_prompt(self, memories: List[Any]) -> str: