278 lines
7.3 KiB
Python
278 lines
7.3 KiB
Python
"""
|
||
统一日志管理系统
|
||
提供结构化日志记录功能,支持不同日志级别、文件输出、轮转等
|
||
"""
|
||
|
||
import json
|
||
import logging
|
||
import os
|
||
import sys
|
||
from datetime import datetime
|
||
from logging.handlers import RotatingFileHandler
|
||
from pathlib import Path
|
||
|
||
|
||
class LoggerSetup:
|
||
"""日志系统配置类"""
|
||
|
||
def __init__(
|
||
self,
|
||
name: str = "ai-chat-server",
|
||
log_level: str = "INFO",
|
||
log_dir: str = "logs",
|
||
max_bytes: int = 10 * 1024 * 1024,
|
||
backup_count: int = 5,
|
||
):
|
||
"""
|
||
初始化日志系统
|
||
|
||
Args:
|
||
name: 日志记录器名称
|
||
log_level: 日志级别 ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL')
|
||
log_dir: 日志文件存储目录
|
||
max_bytes: 单个日志文件最大大小(字节)
|
||
backup_count: 保留的备份文件数量
|
||
"""
|
||
self.name = name
|
||
self.log_level = getattr(logging, log_level.upper(), logging.INFO)
|
||
self.log_dir = Path(log_dir)
|
||
self.max_bytes = max_bytes
|
||
self.backup_count = backup_count
|
||
|
||
# 创建日志目录
|
||
self.log_dir.mkdir(exist_ok=True)
|
||
|
||
# 设置日志格式(去掉 funcName:lineno,保持人类可读性)
|
||
self.formatter = logging.Formatter(
|
||
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||
)
|
||
|
||
# 创建logger实例
|
||
self.logger = self._setup_logger()
|
||
|
||
def _setup_logger(self):
|
||
"""设置logger实例"""
|
||
logger = logging.getLogger(self.name)
|
||
logger.setLevel(self.log_level)
|
||
|
||
# 避免重复添加处理器
|
||
if logger.handlers:
|
||
logger.handlers.clear()
|
||
|
||
# 控制台处理器
|
||
console_handler = logging.StreamHandler(sys.stdout)
|
||
console_handler.setLevel(self.log_level)
|
||
console_handler.setFormatter(self.formatter)
|
||
logger.addHandler(console_handler)
|
||
|
||
# 文件处理器 - 按日期分割
|
||
date_str = datetime.now().strftime("%Y-%m-%d")
|
||
log_file = self.log_dir / f"{self.name}_{date_str}.log"
|
||
|
||
file_handler = RotatingFileHandler(
|
||
str(log_file),
|
||
maxBytes=self.max_bytes,
|
||
backupCount=self.backup_count,
|
||
encoding="utf-8",
|
||
)
|
||
file_handler.setLevel(self.log_level)
|
||
file_handler.setFormatter(self.formatter)
|
||
logger.addHandler(file_handler)
|
||
|
||
return logger
|
||
|
||
def get_logger(self):
|
||
"""获取配置好的logger实例"""
|
||
return self.logger
|
||
|
||
|
||
# 全局日志实例
|
||
_logger_instance = None
|
||
|
||
|
||
def setup_global_logger(
|
||
name: str = "ai-chat-server",
|
||
log_level: str = "INFO",
|
||
log_dir: str = "logs",
|
||
max_bytes: int = 10 * 1024 * 1024,
|
||
backup_count: int = 5,
|
||
):
|
||
"""
|
||
设置全局日志系统
|
||
|
||
Args:
|
||
name: 日志记录器名称
|
||
log_level: 日志级别
|
||
log_dir: 日志文件目录
|
||
max_bytes: 最大文件大小
|
||
backup_count: 备份文件数
|
||
"""
|
||
global _logger_instance
|
||
logger_setup = LoggerSetup(name, log_level, log_dir, max_bytes, backup_count)
|
||
_logger_instance = logger_setup.get_logger()
|
||
return _logger_instance
|
||
|
||
|
||
def get_logger(name: str = None):
|
||
"""
|
||
获取日志记录器实例
|
||
|
||
Args:
|
||
name: 如果提供,返回子记录器;否则返回全局记录器
|
||
"""
|
||
global _logger_instance
|
||
if _logger_instance is None:
|
||
# 如果没有初始化,默认创建一个
|
||
_logger_instance = setup_global_logger()
|
||
|
||
if name and name != _logger_instance.name:
|
||
return _logger_instance.getChild(name)
|
||
return _logger_instance
|
||
|
||
|
||
# 便捷的日志记录函数
|
||
def log_debug(message: str, *args, **kwargs):
|
||
"""记录DEBUG级别日志"""
|
||
logger = get_logger()
|
||
logger.debug(message, *args, **kwargs)
|
||
|
||
|
||
def log_info(message: str, *args, **kwargs):
|
||
"""记录INFO级别日志"""
|
||
logger = get_logger()
|
||
logger.info(message, *args, **kwargs)
|
||
|
||
|
||
def log_warning(message: str, *args, **kwargs):
|
||
"""记录WARNING级别日志"""
|
||
logger = get_logger()
|
||
logger.warning(message, *args, **kwargs)
|
||
|
||
|
||
def log_error(message: str, *args, **kwargs):
|
||
"""记录ERROR级别日志"""
|
||
logger = get_logger()
|
||
logger.error(message, *args, **kwargs)
|
||
|
||
|
||
def log_critical(message: str, *args, **kwargs):
|
||
"""记录CRITICAL级别日志"""
|
||
logger = get_logger()
|
||
logger.critical(message, *args, **kwargs)
|
||
|
||
|
||
def log_exception(message: str = ""):
|
||
"""记录异常信息"""
|
||
logger = get_logger()
|
||
logger.exception(message)
|
||
|
||
|
||
def log_structured(level: str, message: str, **details):
|
||
"""
|
||
记录结构化日志
|
||
|
||
Args:
|
||
level: 日志级别
|
||
message: 日志消息
|
||
**details: 额外的结构化数据
|
||
"""
|
||
logger = get_logger()
|
||
# 为了开发时的可读性,不再使用单行 JSON 打印全结构
|
||
# 转换为更易读的格式
|
||
detail_str = ", ".join(f"{k}={v}" for k, v in details.items() if v)
|
||
formatted_msg = f"[{message}] {detail_str}"
|
||
|
||
getattr(logger, level.lower())(formatted_msg)
|
||
|
||
|
||
def log_request_info(
|
||
method: str,
|
||
path: str,
|
||
client_ip: str = "unknown",
|
||
user_agent: str = "",
|
||
referer: str = "",
|
||
):
|
||
"""记录请求信息日志"""
|
||
log_structured(
|
||
"info",
|
||
"API Request",
|
||
method=method,
|
||
path=path,
|
||
client_ip=client_ip,
|
||
user_agent=user_agent,
|
||
referer=referer,
|
||
)
|
||
|
||
|
||
def log_response_info(
|
||
status_code: int,
|
||
process_time: float,
|
||
path: str = "",
|
||
method: str = "",
|
||
client_ip: str = "",
|
||
):
|
||
"""记录响应信息日志"""
|
||
log_structured(
|
||
"info",
|
||
"API Response",
|
||
status_code=status_code,
|
||
process_time_ms=process_time,
|
||
path=path,
|
||
method=method,
|
||
client_ip=client_ip,
|
||
)
|
||
|
||
|
||
def log_error_detail(
|
||
error_type: str, error_message: str, traceback_info: str = "", context: dict = None
|
||
):
|
||
"""记录详细的错误信息"""
|
||
log_structured(
|
||
"error",
|
||
f"{error_type}: {error_message}",
|
||
traceback=traceback_info,
|
||
context=context or {},
|
||
)
|
||
|
||
|
||
def log_chat_interaction(
|
||
user_input: str,
|
||
ai_response: str,
|
||
model: str = "",
|
||
conversation_id: str = "",
|
||
tokens_used: dict = None,
|
||
):
|
||
"""记录聊天交互日志"""
|
||
log_structured(
|
||
"info",
|
||
"Chat Interaction",
|
||
user_input=(
|
||
user_input[:100] + "..." if len(user_input) > 100 else user_input
|
||
), # 截断长输入
|
||
ai_response=(
|
||
ai_response[:100] + "..." if len(ai_response) > 100 else ai_response
|
||
),
|
||
model=model,
|
||
conversation_id=conversation_id,
|
||
tokens_used=tokens_used,
|
||
)
|
||
|
||
|
||
def log_system_status(
|
||
status: str,
|
||
uptime: float = 0,
|
||
cpu_usage: float = 0,
|
||
memory_usage: float = 0,
|
||
disk_usage: float = 0,
|
||
):
|
||
"""记录系统状态日志"""
|
||
log_structured(
|
||
"info",
|
||
"System Status",
|
||
status=status,
|
||
uptime_seconds=uptime,
|
||
cpu_percent=cpu_usage,
|
||
memory_percent=memory_usage,
|
||
disk_percent=disk_usage,
|
||
)
|