- 新增 SystemNotification 模型,实现系统通知的数据存储 - 管理后台新增通知相关接口,支持通知的增删改查 - 用户端新增接口,获取最新激活通知并支持标记已读 - 在前端首页添加全局通知弹窗,实现通知自动轮询及已读同步 - 生成历史记录中兼容支持图片缩略图及新旧图片格式 - 优化后台图片同步逻辑,新增缩略图生成与存储 - 支持上传参考图的拖拽、粘贴、多文件上传及排序功能 - 增加购买积分页面入口及菜单项,调整菜单结构 - 日志系统由 Redis 列表迁移为有序集合,保留 30 天日志 - 优化日志页面样式,提升可读性及滚动体验 - 调整部分模板布局为自定义滚动条容器,增强视觉一致性
79 lines
2.6 KiB
Python
79 lines
2.6 KiB
Python
import logging
|
||
import os
|
||
from datetime import datetime
|
||
from logging.handlers import RotatingFileHandler
|
||
from extensions import redis_client
|
||
import json
|
||
|
||
# 创建日志目录
|
||
LOG_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'logs')
|
||
os.makedirs(LOG_DIR, exist_ok=True)
|
||
|
||
class SystemLogger:
|
||
def __init__(self):
|
||
self.logger = logging.getLogger('vision_ai')
|
||
self.logger.setLevel(logging.INFO)
|
||
|
||
# 文件处理器 (自动轮转,最大10MB,保留5个备份)
|
||
file_handler = RotatingFileHandler(
|
||
os.path.join(LOG_DIR, 'system.log'),
|
||
maxBytes=10*1024*1024,
|
||
backupCount=5,
|
||
encoding='utf-8'
|
||
)
|
||
file_handler.setLevel(logging.INFO)
|
||
|
||
# 控制台处理器
|
||
console_handler = logging.StreamHandler()
|
||
console_handler.setLevel(logging.INFO)
|
||
|
||
# 格式化
|
||
formatter = logging.Formatter(
|
||
'[%(asctime)s] %(levelname)s - %(message)s',
|
||
datefmt='%Y-%m-%d %H:%M:%S'
|
||
)
|
||
file_handler.setFormatter(formatter)
|
||
console_handler.setFormatter(formatter)
|
||
|
||
self.logger.addHandler(file_handler)
|
||
self.logger.addHandler(console_handler)
|
||
|
||
def _push_to_redis(self, level, message, extra=None):
|
||
"""推送到 Redis 并保留 30 天数据"""
|
||
try:
|
||
now = datetime.now()
|
||
log_entry = {
|
||
"time": now.strftime('%Y-%m-%d %H:%M:%S'),
|
||
"level": level,
|
||
"message": message,
|
||
"extra": extra or {}
|
||
}
|
||
# 使用有序集合 (ZSET),分数为时间戳,方便按时间清理
|
||
timestamp = now.timestamp()
|
||
redis_client.zadd('system_logs_zset', {json.dumps(log_entry, ensure_ascii=False): timestamp})
|
||
|
||
# 清理 30 天之前的日志 (30 * 24 * 3600 秒)
|
||
thirty_days_ago = timestamp - (30 * 24 * 3600)
|
||
redis_client.zremrangebyscore('system_logs_zset', 0, thirty_days_ago)
|
||
except:
|
||
pass
|
||
|
||
def info(self, message, **kwargs):
|
||
self.logger.info(message)
|
||
self._push_to_redis('INFO', message, kwargs)
|
||
|
||
def warning(self, message, **kwargs):
|
||
self.logger.warning(message)
|
||
self._push_to_redis('WARNING', message, kwargs)
|
||
|
||
def error(self, message, **kwargs):
|
||
self.logger.error(message)
|
||
self._push_to_redis('ERROR', message, kwargs)
|
||
|
||
def debug(self, message, **kwargs):
|
||
self.logger.debug(message)
|
||
self._push_to_redis('DEBUG', message, kwargs)
|
||
|
||
# 全局日志实例
|
||
system_logger = SystemLogger()
|