refactor(logger): 将控制台渲染器迁移至 Rich 库,支持十六进制颜色
用 Rich 的原生十六进制颜色支持替代了手动 ANSI 颜色处理 将所有模块颜色定义从 ANSI 转义码转换为 #RRGGBB 格式 移除了 _normalize_color() 函数及相关 ANSI 转换逻辑 更新 ModuleColoredConsoleRenderer,使用 Rich Text 对象进行渲染 通过引入 structlog.typing 增强类型提示 保持日志元数据注册的向后兼容性 破坏性变更:日志元数据现在存储原始十六进制颜色,而非 ANSI 代码
This commit is contained in:
@@ -7,11 +7,13 @@ import time
|
|||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
import orjson
|
import orjson
|
||||||
import structlog
|
import structlog
|
||||||
import tomlkit
|
import tomlkit
|
||||||
|
from rich.console import Console
|
||||||
|
from rich.text import Text
|
||||||
|
from structlog.typing import EventDict, WrappedLogger
|
||||||
|
|
||||||
# 创建logs目录
|
# 创建logs目录
|
||||||
LOG_DIR = Path("logs")
|
LOG_DIR = Path("logs")
|
||||||
@@ -26,37 +28,11 @@ _LOGGER_META_LOCK = threading.Lock()
|
|||||||
_LOGGER_META: dict[str, dict[str, str | None]] = {}
|
_LOGGER_META: dict[str, dict[str, str | None]] = {}
|
||||||
|
|
||||||
|
|
||||||
def _normalize_color(color: str | None) -> str | None:
|
|
||||||
"""接受 ANSI 码 / #RRGGBB / rgb(r,g,b) / 颜色名(直接返回) -> ANSI 码.
|
|
||||||
不做复杂解析,只支持 #RRGGBB 转 24bit ANSI。
|
|
||||||
"""
|
|
||||||
if not color:
|
|
||||||
return None
|
|
||||||
color = color.strip()
|
|
||||||
if color.startswith("\033["):
|
|
||||||
return color # 已经是ANSI
|
|
||||||
if color.startswith("#") and len(color) == 7:
|
|
||||||
try:
|
|
||||||
r = int(color[1:3], 16)
|
|
||||||
g = int(color[3:5], 16)
|
|
||||||
b = int(color[5:7], 16)
|
|
||||||
return f"\033[38;2;{r};{g};{b}m"
|
|
||||||
except ValueError:
|
|
||||||
return None
|
|
||||||
# 简单 rgb(r,g,b)
|
|
||||||
if color.lower().startswith("rgb(") and color.endswith(")"):
|
|
||||||
try:
|
|
||||||
nums = color[color.find("(") + 1 : -1].split(",")
|
|
||||||
r, g, b = (int(x) for x in nums[:3])
|
|
||||||
return f"\033[38;2;{r};{g};{b}m"
|
|
||||||
except Exception:
|
|
||||||
return None
|
|
||||||
# 其他情况直接返回,假设是短ANSI或名称(控制台渲染器不做翻译,仅输出)
|
|
||||||
return color
|
|
||||||
|
|
||||||
|
|
||||||
def _register_logger_meta(name: str, *, alias: str | None = None, color: str | None = None):
|
def _register_logger_meta(name: str, *, alias: str | None = None, color: str | None = None):
|
||||||
"""注册/更新 logger 元数据。"""
|
"""注册/更新 logger 元数据。
|
||||||
|
|
||||||
|
color 参数直接存储 #RRGGBB 格式的颜色值。
|
||||||
|
"""
|
||||||
if not name:
|
if not name:
|
||||||
return
|
return
|
||||||
with _LOGGER_META_LOCK:
|
with _LOGGER_META_LOCK:
|
||||||
@@ -64,7 +40,8 @@ def _register_logger_meta(name: str, *, alias: str | None = None, color: str | N
|
|||||||
if alias is not None:
|
if alias is not None:
|
||||||
meta["alias"] = alias
|
meta["alias"] = alias
|
||||||
if color is not None:
|
if color is not None:
|
||||||
meta["color"] = _normalize_color(color)
|
# 直接存储颜色值(假设已经是 #RRGGBB 格式)
|
||||||
|
meta["color"] = color.upper() if color.startswith("#") else color
|
||||||
|
|
||||||
|
|
||||||
def get_logger_meta(name: str) -> dict[str, str | None]:
|
def get_logger_meta(name: str) -> dict[str, str | None]:
|
||||||
@@ -426,200 +403,200 @@ def reconfigure_existing_loggers():
|
|||||||
|
|
||||||
DEFAULT_MODULE_COLORS = {
|
DEFAULT_MODULE_COLORS = {
|
||||||
# 核心模块
|
# 核心模块
|
||||||
"main": "\033[1;97m", # 亮白色+粗体 (主程序)
|
"main": "#FFFFFF", # 亮白色+粗体 (主程序)
|
||||||
"api": "\033[92m", # 亮绿色
|
"api": "#00FF00", # 亮绿色
|
||||||
"emoji": "\033[38;5;214m", # 橙黄色,偏向橙色但与replyer和action_manager不同
|
"emoji": "#FFAF00", # 橙黄色,偏向橙色但与replyer和action_manager不同
|
||||||
"chat": "\033[92m", # 亮蓝色
|
"chat": "#00FF00", # 亮蓝色
|
||||||
"config": "\033[93m", # 亮黄色
|
"config": "#FFFF00", # 亮黄色
|
||||||
"common": "\033[95m", # 亮紫色
|
"common": "#FF00FF", # 亮紫色
|
||||||
"tools": "\033[96m", # 亮青色
|
"tools": "#00FFFF", # 亮青色
|
||||||
"lpmm": "\033[96m",
|
"lpmm": "#00FFFF",
|
||||||
"plugin_system": "\033[91m", # 亮红色
|
"plugin_system": "#FF0000", # 亮红色
|
||||||
"person_info": "\033[32m", # 绿色
|
"person_info": "#008000", # 绿色
|
||||||
"individuality": "\033[94m", # 显眼的亮蓝色
|
"individuality": "#0000FF", # 显眼的亮蓝色
|
||||||
"manager": "\033[35m", # 紫色
|
"manager": "#800080", # 紫色
|
||||||
"llm_models": "\033[36m", # 青色
|
"llm_models": "#008080", # 青色
|
||||||
"remote": "\033[38;5;242m", # 深灰色,更不显眼
|
"remote": "#6C6C6C", # 深灰色,更不显眼
|
||||||
"planner": "\033[36m",
|
"planner": "#008080",
|
||||||
"memory": "\033[38;5;117m", # 天蓝色
|
"memory": "#87D7FF", # 天蓝色
|
||||||
"hfc": "\033[38;5;81m", # 稍微暗一些的青色,保持可读
|
"hfc": "#5FD7FF", # 稍微暗一些的青色,保持可读
|
||||||
"action_manager": "\033[38;5;208m", # 橙色,不与replyer重复
|
"action_manager": "#FF8700", # 橙色,不与replyer重复
|
||||||
"message_manager": "\033[38;5;27m", # 深蓝色,消息管理器
|
"message_manager": "#005FFF", # 深蓝色,消息管理器
|
||||||
"chatter_manager": "\033[38;5;129m", # 紫色,聊天管理器
|
"chatter_manager": "#AF00FF", # 紫色,聊天管理器
|
||||||
"chatter_interest_scoring": "\033[38;5;214m", # 橙黄色,兴趣评分
|
"chatter_interest_scoring": "#FFAF00", # 橙黄色,兴趣评分
|
||||||
"plan_executor": "\033[38;5;172m", # 橙褐色,计划执行器
|
"plan_executor": "#D78700", # 橙褐色,计划执行器
|
||||||
# 关系系统
|
# 关系系统
|
||||||
"relation": "\033[38;5;139m", # 柔和的紫色,不刺眼
|
"relation": "#AF87AF", # 柔和的紫色,不刺眼
|
||||||
# 聊天相关模块
|
# 聊天相关模块
|
||||||
"normal_chat": "\033[38;5;81m", # 亮蓝绿色
|
"normal_chat": "#5FD7FF", # 亮蓝绿色
|
||||||
"heartflow": "\033[38;5;175m", # 柔和的粉色,不显眼但保持粉色系
|
"heartflow": "#D787AF", # 柔和的粉色,不显眼但保持粉色系
|
||||||
"sub_heartflow": "\033[38;5;207m", # 粉紫色
|
"sub_heartflow": "#FF5FFF", # 粉紫色
|
||||||
"subheartflow_manager": "\033[38;5;201m", # 深粉色
|
"subheartflow_manager": "#FF00FF", # 深粉色
|
||||||
"background_tasks": "\033[38;5;240m", # 灰色
|
"background_tasks": "#585858", # 灰色
|
||||||
"chat_message": "\033[38;5;45m", # 青色
|
"chat_message": "#00D7FF", # 青色
|
||||||
"chat_stream": "\033[38;5;51m", # 亮青色
|
"chat_stream": "#00FFFF", # 亮青色
|
||||||
"sender": "\033[38;5;67m", # 稍微暗一些的蓝色,不显眼
|
"sender": "#5F87AF", # 稍微暗一些的蓝色,不显眼
|
||||||
"message_storage": "\033[38;5;33m", # 深蓝色
|
"message_storage": "#0087FF", # 深蓝色
|
||||||
"expressor": "\033[38;5;166m", # 橙色
|
"expressor": "#D75F00", # 橙色
|
||||||
# 专注聊天模块
|
# 专注聊天模块
|
||||||
"replyer": "\033[38;5;166m", # 橙色
|
"replyer": "#D75F00", # 橙色
|
||||||
"memory_activator": "\033[38;5;117m", # 天蓝色
|
"memory_activator": "#87D7FF", # 天蓝色
|
||||||
# 插件系统
|
# 插件系统
|
||||||
"plugins": "\033[31m", # 红色
|
"plugins": "#800000", # 红色
|
||||||
"plugin_api": "\033[33m", # 黄色
|
"plugin_api": "#808000", # 黄色
|
||||||
"plugin_manager": "\033[38;5;208m", # 红色
|
"plugin_manager": "#FF8700", # 红色
|
||||||
"base_plugin": "\033[38;5;202m", # 橙红色
|
"base_plugin": "#FF5F00", # 橙红色
|
||||||
"send_api": "\033[38;5;208m", # 橙色
|
"send_api": "#FF8700", # 橙色
|
||||||
"base_command": "\033[38;5;208m", # 橙色
|
"base_command": "#FF8700", # 橙色
|
||||||
"component_registry": "\033[38;5;214m", # 橙黄色
|
"component_registry": "#FFAF00", # 橙黄色
|
||||||
"stream_api": "\033[38;5;220m", # 黄色
|
"stream_api": "#FFD700", # 黄色
|
||||||
"plugin_hot_reload": "\033[38;5;226m", # 品红色
|
"plugin_hot_reload": "#FFFF00", # 品红色
|
||||||
"config_api": "\033[38;5;226m", # 亮黄色
|
"config_api": "#FFFF00", # 亮黄色
|
||||||
"heartflow_api": "\033[38;5;154m", # 黄绿色
|
"heartflow_api": "#AFFF00", # 黄绿色
|
||||||
"action_apis": "\033[38;5;118m", # 绿色
|
"action_apis": "#87FF00", # 绿色
|
||||||
"independent_apis": "\033[38;5;82m", # 绿色
|
"independent_apis": "#5FFF00", # 绿色
|
||||||
"llm_api": "\033[38;5;46m", # 亮绿色
|
"llm_api": "#00FF00", # 亮绿色
|
||||||
"database_api": "\033[38;5;10m", # 绿色
|
"database_api": "#00FF00", # 绿色
|
||||||
"utils_api": "\033[38;5;14m", # 青色
|
"utils_api": "#00FFFF", # 青色
|
||||||
"message_api": "\033[38;5;6m", # 青色
|
"message_api": "#008080", # 青色
|
||||||
# 管理器模块
|
# 管理器模块
|
||||||
"async_task_manager": "\033[38;5;129m", # 紫色
|
"async_task_manager": "#AF00FF", # 紫色
|
||||||
"mood": "\033[38;5;135m", # 紫红色
|
"mood": "#AF5FFF", # 紫红色
|
||||||
"local_storage": "\033[38;5;141m", # 紫色
|
"local_storage": "#AF87FF", # 紫色
|
||||||
"willing": "\033[38;5;147m", # 浅紫色
|
"willing": "#AFAFFF", # 浅紫色
|
||||||
# 工具模块
|
# 工具模块
|
||||||
"tool_use": "\033[38;5;172m", # 橙褐色
|
"tool_use": "#D78700", # 橙褐色
|
||||||
"tool_executor": "\033[38;5;172m", # 橙褐色
|
"tool_executor": "#D78700", # 橙褐色
|
||||||
"base_tool": "\033[38;5;178m", # 金黄色
|
"base_tool": "#D7AF00", # 金黄色
|
||||||
# 工具和实用模块
|
# 工具和实用模块
|
||||||
"prompt_build": "\033[38;5;105m", # 紫色
|
"prompt_build": "#8787FF", # 紫色
|
||||||
"chat_utils": "\033[38;5;111m", # 蓝色
|
"chat_utils": "#87AFFF", # 蓝色
|
||||||
"chat_image": "\033[38;5;117m", # 浅蓝色
|
"chat_image": "#87D7FF", # 浅蓝色
|
||||||
"maibot_statistic": "\033[38;5;129m", # 紫色
|
"maibot_statistic": "#AF00FF", # 紫色
|
||||||
# 特殊功能插件
|
# 特殊功能插件
|
||||||
"mute_plugin": "\033[38;5;240m", # 灰色
|
"mute_plugin": "#585858", # 灰色
|
||||||
"core_actions": "\033[38;5;117m", # 深红色
|
"core_actions": "#87D7FF", # 深红色
|
||||||
"tts_action": "\033[38;5;58m", # 深黄色
|
"tts_action": "#5F5F00", # 深黄色
|
||||||
"doubao_pic_plugin": "\033[38;5;64m", # 深绿色
|
"doubao_pic_plugin": "#5F8700", # 深绿色
|
||||||
# Action组件
|
# Action组件
|
||||||
"no_reply_action": "\033[38;5;214m", # 亮橙色,显眼但不像警告
|
"no_reply_action": "#FFAF00", # 亮橙色,显眼但不像警告
|
||||||
"reply_action": "\033[38;5;46m", # 亮绿色
|
"reply_action": "#00FF00", # 亮绿色
|
||||||
"base_action": "\033[38;5;250m", # 浅灰色
|
"base_action": "#BCBCBC", # 浅灰色
|
||||||
# 数据库和消息
|
# 数据库和消息
|
||||||
"database_model": "\033[38;5;94m", # 橙褐色
|
"database_model": "#875F00", # 橙褐色
|
||||||
"database": "\033[38;5;46m", # 橙褐色
|
"database": "#00FF00", # 橙褐色
|
||||||
"maim_message": "\033[38;5;140m", # 紫褐色
|
"maim_message": "#AF87D7", # 紫褐色
|
||||||
# 日志系统
|
# 日志系统
|
||||||
"logger": "\033[38;5;8m", # 深灰色
|
"logger": "#808080", # 深灰色
|
||||||
"confirm": "\033[1;93m", # 黄色+粗体
|
"confirm": "#FFFF00", # 黄色+粗体
|
||||||
# 模型相关
|
# 模型相关
|
||||||
"model_utils": "\033[38;5;164m", # 紫红色
|
"model_utils": "#D700D7", # 紫红色
|
||||||
"relationship_fetcher": "\033[38;5;170m", # 浅紫色
|
"relationship_fetcher": "#D75FD7", # 浅紫色
|
||||||
"relationship_builder": "\033[38;5;93m", # 浅蓝色
|
"relationship_builder": "#8700FF", # 浅蓝色
|
||||||
"sqlalchemy_init": "\033[38;5;105m", #
|
"sqlalchemy_init": "#8787FF", #
|
||||||
"sqlalchemy_models": "\033[38;5;105m",
|
"sqlalchemy_models": "#8787FF",
|
||||||
"sqlalchemy_database_api": "\033[38;5;105m",
|
"sqlalchemy_database_api": "#8787FF",
|
||||||
# s4u
|
# s4u
|
||||||
"context_web_api": "\033[38;5;240m", # 深灰色
|
"context_web_api": "#585858", # 深灰色
|
||||||
"S4U_chat": "\033[92m", # 亮绿色
|
"S4U_chat": "#00FF00", # 亮绿色
|
||||||
# API相关扩展
|
# API相关扩展
|
||||||
"chat_api": "\033[38;5;34m", # 深绿色
|
"chat_api": "#00AF00", # 深绿色
|
||||||
"emoji_api": "\033[38;5;40m", # 亮绿色
|
"emoji_api": "#00D700", # 亮绿色
|
||||||
"generator_api": "\033[38;5;28m", # 森林绿
|
"generator_api": "#008700", # 森林绿
|
||||||
"person_api": "\033[38;5;22m", # 深绿色
|
"person_api": "#005F00", # 深绿色
|
||||||
"tool_api": "\033[38;5;76m", # 绿色
|
"tool_api": "#5FD700", # 绿色
|
||||||
"OpenAI客户端": "\033[38;5;81m",
|
"OpenAI客户端": "#5FD7FF",
|
||||||
"Gemini客户端": "\033[38;5;81m",
|
"Gemini客户端": "#5FD7FF",
|
||||||
# 插件系统扩展
|
# 插件系统扩展
|
||||||
"plugin_base": "\033[38;5;196m", # 红色
|
"plugin_base": "#FF0000", # 红色
|
||||||
"base_event_handler": "\033[38;5;203m", # 粉红色
|
"base_event_handler": "#FF5F5F", # 粉红色
|
||||||
"events_manager": "\033[38;5;209m", # 橙红色
|
"events_manager": "#FF875F", # 橙红色
|
||||||
"global_announcement_manager": "\033[38;5;215m", # 浅橙色
|
"global_announcement_manager": "#FFAF5F", # 浅橙色
|
||||||
# 工具和依赖管理
|
# 工具和依赖管理
|
||||||
"dependency_config": "\033[38;5;24m", # 深蓝色
|
"dependency_config": "#005F87", # 深蓝色
|
||||||
"dependency_manager": "\033[38;5;30m", # 深青色
|
"dependency_manager": "#008787", # 深青色
|
||||||
"manifest_utils": "\033[38;5;39m", # 蓝色
|
"manifest_utils": "#00AFFF", # 蓝色
|
||||||
"schedule_manager": "\033[38;5;27m", # 深蓝色
|
"schedule_manager": "#005FFF", # 深蓝色
|
||||||
"monthly_plan_manager": "\033[38;5;171m",
|
"monthly_plan_manager": "#D75FFF",
|
||||||
"plan_manager": "\033[38;5;171m",
|
"plan_manager": "#D75FFF",
|
||||||
"llm_generator": "\033[38;5;171m",
|
"llm_generator": "#D75FFF",
|
||||||
"schedule_bridge": "\033[38;5;171m",
|
"schedule_bridge": "#D75FFF",
|
||||||
"sleep_manager": "\033[38;5;171m",
|
"sleep_manager": "#D75FFF",
|
||||||
"official_configs": "\033[38;5;171m",
|
"official_configs": "#D75FFF",
|
||||||
"mmc_com_layer": "\033[38;5;67m",
|
"mmc_com_layer": "#5F87AF",
|
||||||
# 聊天和多媒体扩展
|
# 聊天和多媒体扩展
|
||||||
"chat_voice": "\033[38;5;87m", # 浅青色
|
"chat_voice": "#5FFFFF", # 浅青色
|
||||||
"typo_gen": "\033[38;5;123m", # 天蓝色
|
"typo_gen": "#87FFFF", # 天蓝色
|
||||||
"utils_video": "\033[38;5;75m", # 亮蓝色
|
"utils_video": "#5FAFFF", # 亮蓝色
|
||||||
"ReplyerManager": "\033[38;5;173m", # 浅橙色
|
"ReplyerManager": "#D7875F", # 浅橙色
|
||||||
"relationship_builder_manager": "\033[38;5;176m", # 浅紫色
|
"relationship_builder_manager": "#D787D7", # 浅紫色
|
||||||
"expression_selector": "\033[38;5;176m",
|
"expression_selector": "#D787D7",
|
||||||
"chat_message_builder": "\033[38;5;176m",
|
"chat_message_builder": "#D787D7",
|
||||||
# MaiZone QQ空间相关
|
# MaiZone QQ空间相关
|
||||||
"MaiZone": "\033[38;5;98m", # 紫色
|
"MaiZone": "#875FD7", # 紫色
|
||||||
"MaiZone-Monitor": "\033[38;5;104m", # 深紫色
|
"MaiZone-Monitor": "#8787D7", # 深紫色
|
||||||
"MaiZone.ConfigLoader": "\033[38;5;110m", # 蓝紫色
|
"MaiZone.ConfigLoader": "#87AFD7", # 蓝紫色
|
||||||
"MaiZone-Scheduler": "\033[38;5;134m", # 紫红色
|
"MaiZone-Scheduler": "#AF5FD7", # 紫红色
|
||||||
"MaiZone-Utils": "\033[38;5;140m", # 浅紫色
|
"MaiZone-Utils": "#AF87D7", # 浅紫色
|
||||||
# MaiZone Refactored
|
# MaiZone Refactored
|
||||||
"MaiZone.HistoryUtils": "\033[38;5;140m",
|
"MaiZone.HistoryUtils": "#AF87D7",
|
||||||
"MaiZone.SchedulerService": "\033[38;5;134m",
|
"MaiZone.SchedulerService": "#AF5FD7",
|
||||||
"MaiZone.QZoneService": "\033[38;5;98m",
|
"MaiZone.QZoneService": "#875FD7",
|
||||||
"MaiZone.MonitorService": "\033[38;5;104m",
|
"MaiZone.MonitorService": "#8787D7",
|
||||||
"MaiZone.ImageService": "\033[38;5;110m",
|
"MaiZone.ImageService": "#87AFD7",
|
||||||
"MaiZone.CookieService": "\033[38;5;140m",
|
"MaiZone.CookieService": "#AF87D7",
|
||||||
"MaiZone.ContentService": "\033[38;5;110m",
|
"MaiZone.ContentService": "#87AFD7",
|
||||||
"MaiZone.Plugin": "\033[38;5;98m",
|
"MaiZone.Plugin": "#875FD7",
|
||||||
"MaiZone.SendFeedCommand": "\033[38;5;134m",
|
"MaiZone.SendFeedCommand": "#AF5FD7",
|
||||||
"MaiZone.SendFeedAction": "\033[38;5;134m",
|
"MaiZone.SendFeedAction": "#AF5FD7",
|
||||||
"MaiZone.ReadFeedAction": "\033[38;5;134m",
|
"MaiZone.ReadFeedAction": "#AF5FD7",
|
||||||
# 网络工具
|
# 网络工具
|
||||||
"web_surfing_tool": "\033[38;5;130m", # 棕色
|
"web_surfing_tool": "#AF5F00", # 棕色
|
||||||
"tts": "\033[38;5;136m", # 浅棕色
|
"tts": "#AF8700", # 浅棕色
|
||||||
"poke_plugin": "\033[38;5;136m",
|
"poke_plugin": "#AF8700",
|
||||||
"set_emoji_like_plugin": "\033[38;5;136m",
|
"set_emoji_like_plugin": "#AF8700",
|
||||||
# mais4u系统扩展
|
# mais4u系统扩展
|
||||||
"s4u_config": "\033[38;5;18m", # 深蓝色
|
"s4u_config": "#000087", # 深蓝色
|
||||||
"action": "\033[38;5;52m", # 深红色(mais4u的action)
|
"action": "#5F0000", # 深红色(mais4u的action)
|
||||||
"context_web": "\033[38;5;58m", # 深黄色
|
"context_web": "#5F5F00", # 深黄色
|
||||||
"gift_manager": "\033[38;5;161m", # 粉红色
|
"gift_manager": "#D7005F", # 粉红色
|
||||||
"prompt": "\033[38;5;99m", # 紫色(mais4u的prompt)
|
"prompt": "#875FFF", # 紫色(mais4u的prompt)
|
||||||
"super_chat_manager": "\033[38;5;125m", # 紫红色
|
"super_chat_manager": "#AF005F", # 紫红色
|
||||||
"watching": "\033[38;5;131m", # 深橙色
|
"watching": "#AF5F5F", # 深橙色
|
||||||
"offline_llm": "\033[38;5;236m", # 深灰色
|
"offline_llm": "#303030", # 深灰色
|
||||||
"s4u_stream_generator": "\033[38;5;60m", # 深紫色
|
"s4u_stream_generator": "#5F5F87", # 深紫色
|
||||||
# 其他工具
|
# 其他工具
|
||||||
"消息压缩工具": "\033[38;5;244m", # 灰色
|
"消息压缩工具": "#808080", # 灰色
|
||||||
"lpmm_get_knowledge_tool": "\033[38;5;102m", # 绿色
|
"lpmm_get_knowledge_tool": "#878787", # 绿色
|
||||||
"message_chunker": "\033[38;5;244m",
|
"message_chunker": "#808080",
|
||||||
"plan_generator": "\033[38;5;171m",
|
"plan_generator": "#D75FFF",
|
||||||
"Permission": "\033[38;5;196m",
|
"Permission": "#FF0000",
|
||||||
"web_search_plugin": "\033[38;5;130m",
|
"web_search_plugin": "#AF5F00",
|
||||||
"url_parser_tool": "\033[38;5;130m",
|
"url_parser_tool": "#AF5F00",
|
||||||
"api_key_manager": "\033[38;5;130m",
|
"api_key_manager": "#AF5F00",
|
||||||
"tavily_engine": "\033[38;5;130m",
|
"tavily_engine": "#AF5F00",
|
||||||
"exa_engine": "\033[38;5;130m",
|
"exa_engine": "#AF5F00",
|
||||||
"ddg_engine": "\033[38;5;130m",
|
"ddg_engine": "#AF5F00",
|
||||||
"bing_engine": "\033[38;5;130m",
|
"bing_engine": "#AF5F00",
|
||||||
"vector_instant_memory_v2": "\033[38;5;117m",
|
"vector_instant_memory_v2": "#87D7FF",
|
||||||
"async_memory_optimizer": "\033[38;5;117m",
|
"async_memory_optimizer": "#87D7FF",
|
||||||
"async_instant_memory_wrapper": "\033[38;5;117m",
|
"async_instant_memory_wrapper": "#87D7FF",
|
||||||
"action_diagnostics": "\033[38;5;214m",
|
"action_diagnostics": "#FFAF00",
|
||||||
"anti_injector.message_processor": "\033[38;5;196m",
|
"anti_injector.message_processor": "#FF0000",
|
||||||
"anti_injector.user_ban": "\033[38;5;196m",
|
"anti_injector.user_ban": "#FF0000",
|
||||||
"anti_injector.statistics": "\033[38;5;196m",
|
"anti_injector.statistics": "#FF0000",
|
||||||
"anti_injector.decision_maker": "\033[38;5;196m",
|
"anti_injector.decision_maker": "#FF0000",
|
||||||
"anti_injector.counter_attack": "\033[38;5;196m",
|
"anti_injector.counter_attack": "#FF0000",
|
||||||
"hfc.processor": "\033[38;5;81m",
|
"hfc.processor": "#5FD7FF",
|
||||||
"hfc.normal_mode": "\033[38;5;81m",
|
"hfc.normal_mode": "#5FD7FF",
|
||||||
"wakeup": "\033[38;5;81m",
|
"wakeup": "#5FD7FF",
|
||||||
"cache_manager": "\033[38;5;244m",
|
"cache_manager": "#808080",
|
||||||
"monthly_plan_db": "\033[38;5;94m",
|
"monthly_plan_db": "#875F00",
|
||||||
"db_migration": "\033[38;5;94m",
|
"db_migration": "#875F00",
|
||||||
"小彩蛋": "\033[38;5;214m",
|
"小彩蛋": "#FFAF00",
|
||||||
"AioHTTP-Gemini客户端": "\033[38;5;81m",
|
"AioHTTP-Gemini客户端": "#5FD7FF",
|
||||||
"napcat_adapter": "\033[38;5;67m", # 柔和的灰蓝色,不刺眼且低调
|
"napcat_adapter": "#5F87AF", # 柔和的灰蓝色,不刺眼且低调
|
||||||
"event_manager": "\033[38;5;79m", # 柔和的蓝绿色,稍微醒目但不刺眼
|
"event_manager": "#5FD7AF", # 柔和的蓝绿色,稍微醒目但不刺眼
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_MODULE_ALIASES = {
|
DEFAULT_MODULE_ALIASES = {
|
||||||
@@ -750,7 +727,9 @@ DEFAULT_MODULE_ALIASES = {
|
|||||||
"AioHTTP-Gemini客户端": "AioHTTP-Gemini客户端",
|
"AioHTTP-Gemini客户端": "AioHTTP-Gemini客户端",
|
||||||
}
|
}
|
||||||
|
|
||||||
RESET_COLOR = "\033[0m"
|
|
||||||
|
# 创建全局 Rich Console 实例用于颜色渲染
|
||||||
|
_rich_console = Console(force_terminal=True, color_system="truecolor")
|
||||||
|
|
||||||
|
|
||||||
def convert_pathname_to_module(logger, method_name, event_dict):
|
def convert_pathname_to_module(logger, method_name, event_dict):
|
||||||
@@ -785,21 +764,21 @@ def convert_pathname_to_module(logger, method_name, event_dict):
|
|||||||
|
|
||||||
|
|
||||||
class ModuleColoredConsoleRenderer:
|
class ModuleColoredConsoleRenderer:
|
||||||
"""自定义控制台渲染器,为不同模块提供不同颜色"""
|
"""自定义控制台渲染器,使用 Rich 库原生支持 hex 颜色"""
|
||||||
|
|
||||||
def __init__(self, colors=True):
|
def __init__(self, colors=True):
|
||||||
# sourcery skip: merge-duplicate-blocks, remove-redundant-if
|
# sourcery skip: merge-duplicate-blocks, remove-redundant-if
|
||||||
self._colors = colors
|
self._colors = colors
|
||||||
self._config = LOG_CONFIG
|
self._config = LOG_CONFIG
|
||||||
|
|
||||||
# 日志级别颜色
|
# 日志级别颜色 (#RRGGBB 格式)
|
||||||
self._level_colors = {
|
self._level_colors_hex = {
|
||||||
"debug": "\033[38;5;208m", # 橙色
|
"debug": "#D78700", # 橙色 (ANSI 208)
|
||||||
"info": "\033[38;5;117m", # 天蓝色
|
"info": "#87D7FF", # 天蓝色 (ANSI 117)
|
||||||
"success": "\033[32m", # 绿色
|
"success": "#00FF00", # 绿色
|
||||||
"warning": "\033[33m", # 黄色
|
"warning": "#FFFF00", # 黄色
|
||||||
"error": "\033[31m", # 红色
|
"error": "#FF0000", # 红色
|
||||||
"critical": "\033[35m", # 紫色
|
"critical": "#FF00FF", # 紫色
|
||||||
}
|
}
|
||||||
|
|
||||||
# 根据配置决定是否启用颜色
|
# 根据配置决定是否启用颜色
|
||||||
@@ -822,71 +801,65 @@ class ModuleColoredConsoleRenderer:
|
|||||||
def __call__(self, logger, method_name, event_dict):
|
def __call__(self, logger, method_name, event_dict):
|
||||||
# sourcery skip: merge-duplicate-blocks
|
# sourcery skip: merge-duplicate-blocks
|
||||||
"""渲染日志消息"""
|
"""渲染日志消息"""
|
||||||
|
|
||||||
# 获取基本信息
|
# 获取基本信息
|
||||||
timestamp = event_dict.get("timestamp", "")
|
timestamp = event_dict.get("timestamp", "")
|
||||||
level = event_dict.get("level", "info")
|
level = event_dict.get("level", "info")
|
||||||
logger_name = event_dict.get("logger_name", "")
|
logger_name = event_dict.get("logger_name", "")
|
||||||
event = event_dict.get("event", "")
|
event = event_dict.get("event", "")
|
||||||
|
|
||||||
# 构建输出
|
# 构建 Rich Text 对象列表
|
||||||
parts = []
|
parts = []
|
||||||
|
|
||||||
# 日志级别样式配置
|
# 日志级别样式配置
|
||||||
log_level_style = self._config.get("log_level_style", "lite")
|
log_level_style = self._config.get("log_level_style", "lite")
|
||||||
level_color = self._level_colors.get(level.lower(), "") if self._colors else ""
|
level_hex_color = self._level_colors_hex.get(level.lower(), "")
|
||||||
|
|
||||||
# 时间戳(lite模式下按级别着色)
|
# 时间戳(lite模式下按级别着色)
|
||||||
if timestamp:
|
if timestamp:
|
||||||
if log_level_style == "lite" and level_color:
|
if log_level_style == "lite" and self._colors and level_hex_color:
|
||||||
timestamp_part = f"{level_color}{timestamp}{RESET_COLOR}"
|
parts.append(Text(timestamp, style=level_hex_color))
|
||||||
else:
|
else:
|
||||||
timestamp_part = timestamp
|
parts.append(Text(timestamp))
|
||||||
parts.append(timestamp_part)
|
|
||||||
|
|
||||||
# 日志级别显示(根据配置样式)
|
# 日志级别显示(根据配置样式)
|
||||||
if log_level_style == "full":
|
if log_level_style == "full":
|
||||||
# 显示完整级别名并着色
|
# 显示完整级别名并着色
|
||||||
level_text = level.upper()
|
level_text = f"[{level.upper():>8}]"
|
||||||
if level_color:
|
if self._colors and level_hex_color:
|
||||||
level_part = f"{level_color}[{level_text:>8}]{RESET_COLOR}"
|
parts.append(Text(level_text, style=level_hex_color))
|
||||||
else:
|
else:
|
||||||
level_part = f"[{level_text:>8}]"
|
parts.append(Text(level_text))
|
||||||
parts.append(level_part)
|
|
||||||
|
|
||||||
elif log_level_style == "compact":
|
elif log_level_style == "compact":
|
||||||
# 只显示首字母并着色
|
# 只显示首字母并着色
|
||||||
level_text = level.upper()[0]
|
level_text = f"[{level.upper()[0]:>8}]"
|
||||||
if level_color:
|
if self._colors and level_hex_color:
|
||||||
level_part = f"{level_color}[{level_text:>8}]{RESET_COLOR}"
|
parts.append(Text(level_text, style=level_hex_color))
|
||||||
else:
|
else:
|
||||||
level_part = f"[{level_text:>8}]"
|
parts.append(Text(level_text))
|
||||||
parts.append(level_part)
|
|
||||||
|
|
||||||
# lite模式不显示级别,只给时间戳着色
|
# lite模式不显示级别,只给时间戳着色
|
||||||
|
|
||||||
# 获取模块颜色,用于full模式下的整体着色
|
# 获取模块颜色
|
||||||
module_color = ""
|
module_hex_color = ""
|
||||||
|
meta: dict[str, str | None] = {"alias": None, "color": None}
|
||||||
|
if logger_name:
|
||||||
|
meta = get_logger_meta(logger_name)
|
||||||
if self._colors and self._enable_module_colors and logger_name:
|
if self._colors and self._enable_module_colors and logger_name:
|
||||||
# 动态优先,其次默认表
|
# 动态优先,其次默认表
|
||||||
meta = get_logger_meta(logger_name)
|
module_hex_color = meta.get("color") or DEFAULT_MODULE_COLORS.get(logger_name, "")
|
||||||
module_color = meta.get("color") or DEFAULT_MODULE_COLORS.get(logger_name, "")
|
|
||||||
|
|
||||||
# 模块名称(带颜色和别名支持)
|
# 模块名称(带颜色和别名支持)
|
||||||
if logger_name:
|
if logger_name:
|
||||||
# 获取别名,如果没有别名则使用原名称
|
# 获取别名,如果没有别名则使用原名称
|
||||||
# 若上面条件不成立需要再次获取 meta
|
|
||||||
if "meta" not in locals():
|
|
||||||
meta = get_logger_meta(logger_name)
|
|
||||||
display_name = meta.get("alias") or DEFAULT_MODULE_ALIASES.get(logger_name, logger_name)
|
display_name = meta.get("alias") or DEFAULT_MODULE_ALIASES.get(logger_name, logger_name)
|
||||||
|
|
||||||
if self._colors and self._enable_module_colors:
|
module_text = f"[{display_name}]"
|
||||||
if module_color:
|
if self._colors and self._enable_module_colors and module_hex_color:
|
||||||
module_part = f"{module_color}[{display_name}]{RESET_COLOR}"
|
parts.append(Text(module_text, style=module_hex_color))
|
||||||
else:
|
|
||||||
module_part = f"[{display_name}]"
|
|
||||||
else:
|
else:
|
||||||
module_part = f"[{display_name}]"
|
parts.append(Text(module_text))
|
||||||
parts.append(module_part)
|
|
||||||
|
|
||||||
# 消息内容(确保转换为字符串)
|
# 消息内容(确保转换为字符串)
|
||||||
event_content = ""
|
event_content = ""
|
||||||
@@ -902,38 +875,41 @@ class ModuleColoredConsoleRenderer:
|
|||||||
# 其他类型直接转换为字符串
|
# 其他类型直接转换为字符串
|
||||||
event_content = str(event)
|
event_content = str(event)
|
||||||
|
|
||||||
# 在full模式下为消息内容着色
|
# 在 full 模式下为消息内容着色
|
||||||
if self._colors and self._enable_full_content_colors:
|
if self._colors and self._enable_full_content_colors:
|
||||||
# 检查是否包含“内心思考:”
|
|
||||||
if "内心思考:" in event_content:
|
if "内心思考:" in event_content:
|
||||||
# 使用明亮的粉色
|
# 使用明亮的粉色用于“内心思考”段落
|
||||||
thought_color = "\033[38;5;218m"
|
thought_hex_color = "#FFAFD7"
|
||||||
# 分割消息内容
|
|
||||||
prefix, thought = event_content.split("内心思考:", 1)
|
prefix, thought = event_content.split("内心思考:", 1)
|
||||||
|
|
||||||
# 前缀部分(“决定进行回复,”)使用模块颜色
|
prefix = prefix.strip()
|
||||||
if module_color:
|
thought = thought.strip()
|
||||||
prefix_colored = f"{module_color}{prefix.strip()}{RESET_COLOR}"
|
|
||||||
else:
|
|
||||||
prefix_colored = prefix.strip()
|
|
||||||
|
|
||||||
# “内心思考”部分换行并使用专属颜色
|
# 组合为一个 Text,避免 join 时插入多余空格
|
||||||
thought_colored = f"\n\n{thought_color}内心思考:{thought.strip()}{RESET_COLOR}\n"
|
content_text = Text()
|
||||||
|
if prefix:
|
||||||
|
if module_hex_color:
|
||||||
|
content_text.append(prefix, style=module_hex_color)
|
||||||
|
else:
|
||||||
|
content_text.append(prefix)
|
||||||
|
|
||||||
# 重新组合
|
# 与“内心思考”段落之间插入空行
|
||||||
# parts.append(prefix_colored + thought_colored)
|
if prefix:
|
||||||
# 将前缀和思考内容作为独立的part添加,避免它们之间出现多余的空格
|
content_text.append("\n\n")
|
||||||
if prefix_colored:
|
|
||||||
parts.append(prefix_colored)
|
|
||||||
parts.append(thought_colored)
|
|
||||||
|
|
||||||
elif module_color:
|
# “内心思考”标题+内容
|
||||||
event_content = f"{module_color}{event_content}{RESET_COLOR}"
|
content_text.append("内心思考:", style=thought_hex_color)
|
||||||
parts.append(event_content)
|
if thought:
|
||||||
|
content_text.append(thought, style=thought_hex_color)
|
||||||
|
|
||||||
|
parts.append(content_text)
|
||||||
else:
|
else:
|
||||||
parts.append(event_content)
|
if module_hex_color:
|
||||||
|
parts.append(Text(event_content, style=module_hex_color))
|
||||||
|
else:
|
||||||
|
parts.append(Text(event_content))
|
||||||
else:
|
else:
|
||||||
parts.append(event_content)
|
parts.append(Text(event_content))
|
||||||
|
|
||||||
# 处理其他字段
|
# 处理其他字段
|
||||||
extras = []
|
extras = []
|
||||||
@@ -950,15 +926,24 @@ class ModuleColoredConsoleRenderer:
|
|||||||
|
|
||||||
# 在full模式下为额外字段着色
|
# 在full模式下为额外字段着色
|
||||||
extra_field = f"{key}={value_str}"
|
extra_field = f"{key}={value_str}"
|
||||||
if self._colors and self._enable_full_content_colors and module_color:
|
# 在full模式下为额外字段着色
|
||||||
extra_field = f"{module_color}{extra_field}{RESET_COLOR}"
|
if self._colors and self._enable_full_content_colors and module_hex_color:
|
||||||
|
extras.append(Text(extra_field, style=module_hex_color))
|
||||||
extras.append(extra_field)
|
else:
|
||||||
|
extras.append(Text(extra_field))
|
||||||
|
|
||||||
if extras:
|
if extras:
|
||||||
parts.append(" ".join(extras))
|
parts.append(Text(" "))
|
||||||
|
parts.extend(extras)
|
||||||
|
|
||||||
return " ".join(parts)
|
# 使用 Rich 拼接并返回字符串
|
||||||
|
result = Text(" ").join(parts)
|
||||||
|
# 将 Rich Text 对象转换为带 ANSI 颜色码的字符串
|
||||||
|
from io import StringIO
|
||||||
|
string_io = StringIO()
|
||||||
|
temp_console = Console(file=string_io, force_terminal=True, color_system="truecolor", width=999)
|
||||||
|
temp_console.print(result, end="")
|
||||||
|
return string_io.getvalue()
|
||||||
|
|
||||||
|
|
||||||
# 配置标准logging以支持文件输出和压缩
|
# 配置标准logging以支持文件输出和压缩
|
||||||
@@ -974,8 +959,11 @@ logging.basicConfig(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def add_logger_metadata(logger: Any, method_name: str, event_dict: dict): # type: ignore[override]
|
def add_logger_metadata(logger: WrappedLogger, method_name: str, event_dict: EventDict) -> EventDict: # type: ignore[override]
|
||||||
"""structlog 自定义处理器: 注入 color / alias 字段 (用于 JSON 输出)。"""
|
"""structlog 自定义处理器: 注入 color / alias 字段 (用于 JSON 输出)。
|
||||||
|
|
||||||
|
color 使用 #RRGGBB 格式(已通过 _normalize_color 统一)。
|
||||||
|
"""
|
||||||
name = event_dict.get("logger_name")
|
name = event_dict.get("logger_name")
|
||||||
if name:
|
if name:
|
||||||
meta = get_logger_meta(name)
|
meta = get_logger_meta(name)
|
||||||
@@ -984,7 +972,7 @@ def add_logger_metadata(logger: Any, method_name: str, event_dict: dict): # typ
|
|||||||
meta["color"] = DEFAULT_MODULE_COLORS[name]
|
meta["color"] = DEFAULT_MODULE_COLORS[name]
|
||||||
if meta.get("alias") is None and name in DEFAULT_MODULE_ALIASES:
|
if meta.get("alias") is None and name in DEFAULT_MODULE_ALIASES:
|
||||||
meta["alias"] = DEFAULT_MODULE_ALIASES[name]
|
meta["alias"] = DEFAULT_MODULE_ALIASES[name]
|
||||||
# 注入
|
# 注入 - color 已经是 #RRGGBB 格式
|
||||||
if meta.get("color"):
|
if meta.get("color"):
|
||||||
event_dict["color"] = meta["color"]
|
event_dict["color"] = meta["color"]
|
||||||
if meta.get("alias"):
|
if meta.get("alias"):
|
||||||
|
|||||||
Reference in New Issue
Block a user