Merge pull request #2698 from InfinityPacer/feature/log-refactor

This commit is contained in:
jxxghp
2024-09-11 06:48:13 +08:00
committed by GitHub
3 changed files with 93 additions and 35 deletions
+79 -35
View File
@@ -5,29 +5,69 @@ from pathlib import Path
from typing import Dict, Any from typing import Dict, Any
import click import click
from pydantic import BaseSettings
from app.core.config import settings from app.utils.system import SystemUtils
# 日志级别颜色
class LogSettings(BaseSettings):
"""
日志设置
"""
# 是否为调试模式
DEBUG: bool = False
# 日志级别(DEBUG、INFO、WARNING、ERROR等)
LOG_LEVEL: str = "INFO"
# 日志文件最大大小(单位:MB
LOG_MAX_FILE_SIZE: int = 5
# 备份的日志文件数量
LOG_BACKUP_COUNT: int = 3
# 控制台日志格式
LOG_CONSOLE_FORMAT: str = "%(leveltext)s%(message)s"
# 文件日志格式
LOG_FILE_FORMAT: str = "%(levelname)s%(asctime)s - %(message)s"
@property
def LOG_PATH(self):
"""
获取日志存储路径
"""
return SystemUtils.get_config_path() / "logs"
@property
def LOG_MAX_FILE_SIZE_BYTES(self):
"""
将日志文件大小转换为字节(MB -> Bytes
"""
return self.LOG_MAX_FILE_SIZE * 1024 * 1024
class Config:
case_sensitive = True
env_file = SystemUtils.get_config_path() / "app.env"
env_file_encoding = "utf-8"
# 日志级别颜色映射
level_name_colors = { level_name_colors = {
logging.DEBUG: lambda level_name: click.style(str(level_name), fg="cyan"), logging.DEBUG: lambda level_name: click.style(str(level_name), fg="cyan"),
logging.INFO: lambda level_name: click.style(str(level_name), fg="green"), logging.INFO: lambda level_name: click.style(str(level_name), fg="green"),
logging.WARNING: lambda level_name: click.style(str(level_name), fg="yellow"), logging.WARNING: lambda level_name: click.style(str(level_name), fg="yellow"),
logging.ERROR: lambda level_name: click.style(str(level_name), fg="red"), logging.ERROR: lambda level_name: click.style(str(level_name), fg="red"),
logging.CRITICAL: lambda level_name: click.style( logging.CRITICAL: lambda level_name: click.style(str(level_name), fg="bright_red"),
str(level_name), fg="bright_red"
),
} }
class CustomFormatter(logging.Formatter): class CustomFormatter(logging.Formatter):
""" """
定义日志输出格式 定义日志输出格式
""" """
def __init__(self, fmt=None):
super().__init__(fmt)
def format(self, record): def format(self, record):
seperator = " " * (8 - len(record.levelname)) separator = " " * (8 - len(record.levelname))
record.leveltext = level_name_colors[record.levelno](record.levelname + ":") + seperator record.leveltext = level_name_colors[record.levelno](record.levelname + ":") + separator
return super().format(record) return super().format(record)
@@ -35,15 +75,16 @@ class LoggerManager:
""" """
日志管理 日志管理
""" """
# 管理所有的Logger # 管理所有的 Logger
_loggers: Dict[str, Any] = {} _loggers: Dict[str, Any] = {}
# 默认日志文件 # 默认日志文件名称
_default_log_file = "moviepilot.log" _default_log_file = "moviepilot.log"
@staticmethod @staticmethod
def __get_caller(): def __get_caller():
""" """
获取调用者的文件名称与插件名称(如果是插件调用内置的模块, 也能写入到插件日志文件中) 获取调用者的文件名称与插件名称
如果是插件调用内置的模块, 也能写入到插件日志文件中
""" """
# 调用者文件名称 # 调用者文件名称
caller_name = None caller_name = None
@@ -79,18 +120,17 @@ class LoggerManager:
设置日志 设置日志
log_file:日志文件相对路径 log_file:日志文件相对路径
""" """
log_file_path = settings.LOG_PATH / log_file log_file_path = log_settings.LOG_PATH / log_file
if not log_file_path.parent.exists(): log_file_path.parent.mkdir(parents=True, exist_ok=True)
log_file_path.parent.mkdir(parents=True, exist_ok=True)
# 创建新实例 # 创建新实例
_logger = logging.getLogger(log_file_path.stem) _logger = logging.getLogger(log_file_path.stem)
# DEBUG if log_settings.DEBUG:
if settings.DEBUG:
_logger.setLevel(logging.DEBUG) _logger.setLevel(logging.DEBUG)
else: else:
_logger.setLevel(logging.INFO) loglevel = getattr(logging, log_settings.LOG_LEVEL.upper(), logging.INFO)
_logger.setLevel(loglevel)
# 移除已有的 handler,避免重复添加 # 移除已有的 handler,避免重复添加
for handler in _logger.handlers: for handler in _logger.handlers:
@@ -98,18 +138,20 @@ class LoggerManager:
# 终端日志 # 终端日志
console_handler = logging.StreamHandler() console_handler = logging.StreamHandler()
console_formatter = CustomFormatter(f"%(leveltext)s%(message)s") console_formatter = CustomFormatter(log_settings.LOG_CONSOLE_FORMAT)
console_handler.setFormatter(console_formatter) console_handler.setFormatter(console_formatter)
_logger.addHandler(console_handler) _logger.addHandler(console_handler)
# 文件日志 # 文件日志
file_handler = RotatingFileHandler(filename=log_file_path, file_handler = RotatingFileHandler(
mode='w', filename=log_file_path,
maxBytes=5 * 1024 * 1024, mode="a",
backupCount=3, maxBytes=log_settings.LOG_MAX_FILE_SIZE_BYTES,
encoding='utf-8') backupCount=log_settings.LOG_BACKUP_COUNT,
file_formater = CustomFormatter(f"【%(levelname)s】%(asctime)s - %(message)s") encoding="utf-8"
file_handler.setFormatter(file_formater) )
file_formatter = CustomFormatter(log_settings.LOG_FILE_FORMAT)
file_handler.setFormatter(file_formatter)
_logger.addHandler(file_handler) _logger.addHandler(file_handler)
return _logger return _logger
@@ -120,7 +162,6 @@ class LoggerManager:
:param method: 日志方法 :param method: 日志方法
:param msg: 日志信息 :param msg: 日志信息
""" """
# 获取调用者文件名和插件名 # 获取调用者文件名和插件名
caller_name, plugin_name = self.__get_caller() caller_name, plugin_name = self.__get_caller()
# 区分插件日志 # 区分插件日志
@@ -138,45 +179,48 @@ class LoggerManager:
self._loggers[logfile] = _logger self._loggers[logfile] = _logger
# 调用logger的方法打印日志 # 调用logger的方法打印日志
if hasattr(_logger, method): if hasattr(_logger, method):
method = getattr(_logger, method) log_method = getattr(_logger, method)
method(f"{caller_name} - {msg}", *args, **kwargs) log_method(f"{caller_name} - {msg}", *args, **kwargs)
def info(self, msg: str, *args, **kwargs): def info(self, msg: str, *args, **kwargs):
""" """
重载info方法 输出信息级别日志
""" """
self.logger("info", msg, *args, **kwargs) self.logger("info", msg, *args, **kwargs)
def debug(self, msg: str, *args, **kwargs): def debug(self, msg: str, *args, **kwargs):
""" """
重载debug方法 输出调试级别日志
""" """
self.logger("debug", msg, *args, **kwargs) self.logger("debug", msg, *args, **kwargs)
def warning(self, msg: str, *args, **kwargs): def warning(self, msg: str, *args, **kwargs):
""" """
重载warning方法 输出警告级别日志
""" """
self.logger("warning", msg, *args, **kwargs) self.logger("warning", msg, *args, **kwargs)
def warn(self, msg: str, *args, **kwargs): def warn(self, msg: str, *args, **kwargs):
""" """
重载warn方法 输出警告级别日志(兼容)
""" """
self.logger("warning", msg, *args, **kwargs) self.logger("warning", msg, *args, **kwargs)
def error(self, msg: str, *args, **kwargs): def error(self, msg: str, *args, **kwargs):
""" """
重载error方法 输出错误级别日志
""" """
self.logger("error", msg, *args, **kwargs) self.logger("error", msg, *args, **kwargs)
def critical(self, msg: str, *args, **kwargs): def critical(self, msg: str, *args, **kwargs):
""" """
重载critical方法 输出严重错误级别日志
""" """
self.logger("critical", msg, *args, **kwargs) self.logger("critical", msg, *args, **kwargs)
# 初始化公共日志 # 实例化日志设置
log_settings = LogSettings()
# 初始化日志管理
logger = LoggerManager() logger = LoggerManager()
+12
View File
@@ -471,3 +471,15 @@ class SystemUtils:
if os.name == "nt": if os.name == "nt":
return src.drive == dest.drive return src.drive == dest.drive
return os.stat(src).st_dev == os.stat(dest).st_dev return os.stat(src).st_dev == os.stat(dest).st_dev
@staticmethod
def get_config_path() -> Path:
"""
获取配置路径
"""
if SystemUtils.is_docker():
return Path("/config")
elif SystemUtils.is_frozen():
return Path(sys.executable).parent / "config"
else:
return Path(__file__).parents[2] / "config"
+2
View File
@@ -7,6 +7,8 @@ HOST=0.0.0.0
DEBUG=false DEBUG=false
# 是否开发模式,打开后后台服务将不会启动 # 是否开发模式,打开后后台服务将不会启动
DEV=false DEV=false
# 日志级别(DEBUG、INFO、WARNING、ERROR等),当DEBUG=true时,此配置项将被忽略,日志级别始终为DEBUG
LOG_LEVEL=INFO
# 数据库连接池的大小,可适当降低如10-50以减少I/O压力 # 数据库连接池的大小,可适当降低如10-50以减少I/O压力
DB_POOL_SIZE=100 DB_POOL_SIZE=100
# 数据库连接池最大溢出连接数,可适当降低如0以减少I/O压力 # 数据库连接池最大溢出连接数,可适当降低如0以减少I/O压力