feat(log): log supports hot update.

This commit is contained in:
Aqr-K
2025-01-03 06:08:29 +08:00
parent 8ac0d169d2
commit cea77bddee
2 changed files with 65 additions and 8 deletions

View File

@@ -1,19 +1,24 @@
import inspect
import logging
import os
from logging.handlers import RotatingFileHandler
from pathlib import Path
from typing import Dict, Any, Optional
import click
from pydantic import BaseSettings
from pydantic import BaseSettings, BaseModel
from app.utils.system import SystemUtils
class LogSettings(BaseSettings):
class LogConfigModel(BaseModel):
"""
日志设置
Pydantic 配置模型,描述所有配置项及其类型和默认值
"""
class Config:
extra = "ignore" # 忽略未定义的配置项
# 配置文件目录
CONFIG_DIR: Optional[str] = None
# 是否为调试模式
@@ -29,6 +34,12 @@ class LogSettings(BaseSettings):
# 文件日志格式
LOG_FILE_FORMAT: str = "%(levelname)s%(asctime)s - %(message)s"
class LogSettings(BaseSettings, LogConfigModel):
"""
日志设置类
"""
@property
def CONFIG_PATH(self):
return SystemUtils.get_config_path(self.CONFIG_DIR)
@@ -121,10 +132,12 @@ class LoggerManager:
return caller_name or "log.py", plugin_name
@staticmethod
def __setup_logger(log_file: str):
def __setup_logger(log_file: str, plugin_name: str = None):
"""
设置日志
log_file日志文件相对路径
:param log_file日志文件相对路径
:param plugin_name: 插件名称
"""
log_file_path = log_settings.LOG_PATH / log_file
log_file_path.parent.mkdir(parents=True, exist_ok=True)
@@ -134,6 +147,22 @@ class LoggerManager:
if log_settings.DEBUG:
_logger.setLevel(logging.DEBUG)
# Todo: 允许每个插件设置独立的日志级别,用于单个插件的调试,不必使用全局影响全局日志级别,产生大量无用日志
# elif plugin_name:
# # 从数据库中获取插件的日志等级不存在则用None
# plugin_log_level =
#
# # 插件日志等级存在且合法,则使用插件日志等级
# if plugin_log_level and plugin_log_level.upper() in ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']:
# loglevel = getattr(logging, plugin_log_level.upper(), logging.INFO)
# _logger.setLevel(loglevel)
# # 插件日志等级不存在,则使用全局日志等级
# else:
# loglevel = getattr(logging, log_settings.LOG_LEVEL.upper(), logging.INFO)
# _logger.setLevel(loglevel)
# 全局日志等级
else:
loglevel = getattr(logging, log_settings.LOG_LEVEL.upper(), logging.INFO)
_logger.setLevel(loglevel)
@@ -162,6 +191,26 @@ class LoggerManager:
return _logger
def update_loggers(self):
"""
更新日志实例
"""
_new_loggers: Dict[str, Any] = {}
for log_file, _logger in self._loggers.items():
# 移除已有的 handler避免重复添加
for handler in _logger.handlers:
_logger.removeHandler(handler)
plugin_name = None
# 如果不是默认日志文件,则拆分出插件名称
if log_file != self._default_log_file:
log_file_name = os.path.basename(log_file)
plugin_name = os.path.splitext(log_file_name)[0]
# 重新设置日志实例
_new_logger = self.__setup_logger(log_file=log_file, plugin_name=plugin_name)
_new_loggers[log_file] = _new_logger
self._loggers = _new_loggers
def logger(self, method: str, msg: str, *args, **kwargs):
"""
获取模块的logger
@@ -181,7 +230,7 @@ class LoggerManager:
# 获取调用者的模块的logger
_logger = self._loggers.get(logfile)
if not _logger:
_logger = self.__setup_logger(logfile)
_logger = self.__setup_logger(log_file=logfile, plugin_name=plugin_name)
self._loggers[logfile] = _logger
# 调用logger的方法打印日志
if hasattr(_logger, method):