diff --git a/.gitignore b/.gitignore index a8b468a..ee46f8e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ .vscode test .ruff_cache -config.toml \ No newline at end of file +config.toml +logs/ \ No newline at end of file diff --git a/main.py b/main.py index c3d96a9..9beca8a 100644 --- a/main.py +++ b/main.py @@ -2,7 +2,7 @@ import asyncio import sys import json import websockets as Server -from src.logger import logger +from src.logger import get_module_logger from src.recv_handler import recv_handler from src.send_handler import send_handler from src.config import global_config @@ -10,6 +10,9 @@ from src.mmc_com_layer import mmc_start_com, mmc_stop_com, router from src.message_queue import message_queue, put_response, check_timeout_response +logger = get_module_logger("适配器主程序") + + async def message_recv(server_connection: Server.ServerConnection): recv_handler.server_connection = server_connection send_handler.server_connection = server_connection diff --git a/src/config.py b/src/config.py index 920b6d6..f2abe29 100644 --- a/src/config.py +++ b/src/config.py @@ -2,10 +2,11 @@ import os import sys import tomli import shutil -from .logger import logger +from loguru import logger from typing import Optional + class Config: platform: str = "qq" nickname: Optional[str] = None diff --git a/src/logger.py b/src/logger.py index c097f14..4fa2560 100644 --- a/src/logger.py +++ b/src/logger.py @@ -1,25 +1,138 @@ from loguru import logger -from .config import global_config +from typing import Optional, Union, List, Tuple import sys -# import builtins +import os +from types import ModuleType +from pathlib import Path +from .config import global_config -logger.remove() -logger.add( - sys.stderr, - level=global_config.debug_level, - format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}", -) +# 保存原生处理器ID +default_handler_id = None +for handler_id in logger._core.handlers: + default_handler_id = handler_id + break + +# 移除默认处理器 +if default_handler_id is not None: + logger.remove(default_handler_id) + +# 类型别名 +LoguruLogger = logger.__class__ + +# 全局注册表:记录模块与处理器ID的映射 +_handler_registry: dict[str, List[int]] = {} +_custom_style_handlers: dict[Tuple[str, str], List[int]] = {} # 记录自定义样式处理器ID + +# 获取日志存储根地址 +current_file_path = Path(__file__).resolve() +LOG_ROOT = "logs" + +# LOG_LEVEL = global_config.get("Debug", {}).get("level", "INFO").upper() +# print(global_config.debug_level) + +DEFAULT_CONFIG = { + # 日志级别配置 + "console_level": global_config.debug_level, + "file_level": "DEBUG", + # 格式配置 + "console_format": ( + "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | {message}" + ), + "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | {message}", + "log_dir": LOG_ROOT, + "rotation": "00:00", + "retention": "3 days", + "compression": "zip", + } + +def is_registered_module(record: dict) -> bool: + """检查是否为已注册的模块""" + return record["extra"].get("module") in _handler_registry -# def handle_output(message: str): -# if "连接失败" in message: -# logger.error(message) -# elif "收到无效的" in message: -# logger.warning(message) -# elif "检测到平台" in message: -# logger.warning(message) -# else: -# logger.info(message) +def is_unregistered_module(record: dict) -> bool: + """检查是否为未注册的模块""" + return not is_registered_module(record) -# builtins.print = handle_output +def log_patcher(record: dict) -> None: + """自动填充未设置模块名的日志记录,保留原生模块名称""" + if "module" not in record["extra"]: + # 尝试从name中提取模块名 + module_name = record.get("name", "") + if module_name == "": + module_name = "root" + record["extra"]["module"] = module_name +class LogConfig: + """日志配置类""" + + def __init__(self, **kwargs): + self.config = DEFAULT_CONFIG.copy() + self.config.update(kwargs) + + def to_dict(self) -> dict: + return self.config.copy() + + def update(self, **kwargs): + self.config.update(kwargs) + + +def get_module_logger( + module: Union[str, ModuleType], + *, + console_level: Optional[str] = None, + file_level: Optional[str] = None, + extra_handlers: Optional[List[dict]] = None, + config: Optional[LogConfig] = None, +) -> LoguruLogger: + module_name = module if isinstance(module, str) else module.__name__ + current_config = config.config if config else DEFAULT_CONFIG + + # 清理旧处理器 + if module_name in _handler_registry: + for handler_id in _handler_registry[module_name]: + logger.remove(handler_id) + del _handler_registry[module_name] + + handler_ids = [] + + # 控制台处理器 + console_id = logger.add( + sink=sys.stderr, + level=os.getenv("CONSOLE_LOG_LEVEL", console_level or current_config["console_level"]), + format=current_config["console_format"], + filter=lambda record: record["extra"].get("module") == module_name and "custom_style" not in record["extra"], + enqueue=True, + ) + handler_ids.append(console_id) + + # 文件处理器 + log_dir = Path("logs") + log_dir.mkdir(parents=True, exist_ok=True) + log_file = log_dir / "{time:YYYY-MM-DD}.log" + log_file.parent.mkdir(parents=True, exist_ok=True) + + file_id = logger.add( + sink=str(log_file), + level=os.getenv("FILE_LOG_LEVEL", file_level or current_config["file_level"]), + format=current_config["file_format"], + rotation=current_config["rotation"], + retention=current_config["retention"], + compression=current_config["compression"], + encoding="utf-8", + filter=lambda record: record["extra"].get("module") == module_name and "custom_style" not in record["extra"], + enqueue=True, + ) + handler_ids.append(file_id) + + # 额外处理器 + if extra_handlers: + for handler in extra_handlers: + handler_id = logger.add(**handler) + handler_ids.append(handler_id) + + # 更新注册表 + _handler_registry[module_name] = handler_ids + + return logger.bind(module=module_name) + diff --git a/src/message_queue.py b/src/message_queue.py index 95d646c..ba01518 100644 --- a/src/message_queue.py +++ b/src/message_queue.py @@ -2,7 +2,9 @@ import asyncio import time from typing import Dict from .config import global_config -from .logger import logger +from .logger import get_module_logger + +logger = get_module_logger("消息队列") response_dict: Dict = {} response_time_dict: Dict = {} diff --git a/src/mmc_com_layer.py b/src/mmc_com_layer.py index 76a549f..e46514b 100644 --- a/src/mmc_com_layer.py +++ b/src/mmc_com_layer.py @@ -1,8 +1,10 @@ from maim_message import Router, RouteConfig, TargetConfig from .config import global_config -from .logger import logger +from .logger import get_module_logger from .send_handler import send_handler +logger = get_module_logger("麦麦核心链接") + route_config = RouteConfig( route_config={ global_config.platform: TargetConfig( diff --git a/src/recv_handler.py b/src/recv_handler.py index 33f98b9..e638fbb 100644 --- a/src/recv_handler.py +++ b/src/recv_handler.py @@ -1,4 +1,4 @@ -from .logger import logger +from .logger import get_module_logger from .config import global_config from .qq_emoji_list import qq_face import time @@ -31,6 +31,8 @@ from .utils import ( from .message_queue import get_response +logger = get_module_logger("收到消息处理") + class RecvHandler: maibot_router: Router = None diff --git a/src/send_handler.py b/src/send_handler.py index 247b512..ab7b4c1 100644 --- a/src/send_handler.py +++ b/src/send_handler.py @@ -5,7 +5,7 @@ import uuid # from .config import global_config # 白名单机制不启用 from .message_queue import get_response -from .logger import logger +from .logger import get_module_logger from maim_message import ( UserInfo, @@ -17,6 +17,7 @@ from maim_message import ( from .utils import get_image_format, convert_image_to_gif +logger = get_module_logger("发送处理器") class SendHandler: def __init__(self): diff --git a/src/utils.py b/src/utils.py index c699d8d..c7e3adc 100644 --- a/src/utils.py +++ b/src/utils.py @@ -2,7 +2,7 @@ import websockets as Server import json import base64 import uuid -from .logger import logger +from .logger import get_module_logger from .message_queue import get_response import urllib3 @@ -11,6 +11,7 @@ import ssl from PIL import Image import io +logger = get_module_logger("utils") class SSLAdapter(urllib3.PoolManager): def __init__(self, *args, **kwargs):