diff --git a/astrbot/core/log.py b/astrbot/core/log.py index e578c2f1f..b819fcc2b 100644 --- a/astrbot/core/log.py +++ b/astrbot/core/log.py @@ -1,6 +1,7 @@ import logging import colorlog import asyncio +import os from collections import deque from asyncio import Queue from typing import List @@ -17,6 +18,31 @@ log_color_config = { } +def is_plugin_path(pathname): + """ + 检查文件路径是否来自插件目录 + """ + if not pathname: + return False + + norm_path = os.path.normpath(pathname) + return ("data/plugins" in norm_path) or ("packages/" in norm_path) + + +def get_short_level_name(level_name): + """ + 将日志级别名称转换为四个字母的缩写 + """ + level_map = { + "DEBUG": "DBUG", + "INFO": "INFO", + "WARNING": "WARN", + "ERROR": "ERRO", + "CRITICAL": "CRIT", + } + return level_map.get(level_name, level_name[:4].upper()) + + class LogBroker: def __init__(self): self.log_cache = deque(maxlen=CACHED_SIZE) @@ -62,12 +88,41 @@ class LogManager: return logger console_handler = logging.StreamHandler() console_handler.setLevel(logging.DEBUG) + console_formatter = colorlog.ColoredFormatter( - fmt="%(log_color)s [%(asctime)s] [%(levelname)-5s] [%(filename)s:%(lineno)d]: %(message)s %(reset)s", + fmt="%(log_color)s [%(asctime)s] %(plugin_tag)s [%(short_levelname)-4s] [%(filename)s:%(lineno)d]: %(message)s %(reset)s", datefmt="%H:%M:%S", log_colors=log_color_config, ) + + class PluginFilter(logging.Filter): + def filter(self, record): + record.plugin_tag = ( + "[Plug]" if is_plugin_path(record.pathname) else "[Core]" + ) + return True + + class FileNameFilter(logging.Filter): + # 获取这个文件和父文件夹的名字:. 并且去除 .py + def filter(self, record): + dirname = os.path.dirname(record.pathname) + record.filename = ( + os.path.basename(dirname) + + "." + + os.path.basename(record.pathname).replace(".py", "") + ) + return True + + class LevelNameFilter(logging.Filter): + # 添加短日志级别名称 + def filter(self, record): + record.short_levelname = get_short_level_name(record.levelname) + return True + console_handler.setFormatter(console_formatter) + logger.addFilter(PluginFilter()) + logger.addFilter(FileNameFilter()) + logger.addFilter(LevelNameFilter()) # 添加级别名称过滤器 logger.setLevel(logging.DEBUG) logger.addHandler(console_handler) @@ -80,9 +135,10 @@ class LogManager: if logger.handlers: handler.setFormatter(logger.handlers[0].formatter) else: + # 为队列处理器设置相同格式的formatter handler.setFormatter( logging.Formatter( - "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + "[%(asctime)s] [%(short_levelname)s] %(plugin_tag)s[%(filename)s:%(lineno)d]: %(message)s" ) ) logger.addHandler(handler) diff --git a/astrbot/core/pipeline/process_stage/method/llm_request.py b/astrbot/core/pipeline/process_stage/method/llm_request.py index ede3bb9d8..5acff1b55 100644 --- a/astrbot/core/pipeline/process_stage/method/llm_request.py +++ b/astrbot/core/pipeline/process_stage/method/llm_request.py @@ -3,6 +3,7 @@ """ import traceback +import asyncio import json from typing import Union, AsyncGenerator from ...context import PipelineContext @@ -137,11 +138,11 @@ class LLMRequestSubStage(Stage): # 保存到历史记录 await self._save_to_history(event, req, llm_response) - await Metric.upload( + asyncio.create_task(Metric.upload( llm_tick=1, model_name=provider.get_model(), provider_type=provider.meta().type, - ) + )) if llm_response.role == "assistant": # text completion diff --git a/astrbot/core/provider/entites.py b/astrbot/core/provider/entites.py index a98bbfa7c..3180b4955 100644 --- a/astrbot/core/provider/entites.py +++ b/astrbot/core/provider/entites.py @@ -46,7 +46,7 @@ class ProviderRequest: conversation: Conversation = None def __repr__(self): - return f"ProviderRequest(prompt={self.prompt}, session_id={self.session_id}, image_urls={self.image_urls}, func_tool={self.func_tool}, contexts={self.contexts}, system_prompt={self.system_prompt})" + return f"ProviderRequest(prompt={self.prompt}, session_id={self.session_id}, image_urls={self.image_urls}, func_tool={self.func_tool}, contexts={self.contexts}, system_prompt={self.system_prompt.strip()})" def __str__(self): return self.__repr__() diff --git a/astrbot/core/provider/func_tool_manager.py b/astrbot/core/provider/func_tool_manager.py index 1b2bd6410..0022d2773 100644 --- a/astrbot/core/provider/func_tool_manager.py +++ b/astrbot/core/provider/func_tool_manager.py @@ -19,6 +19,9 @@ class FuncTool: active: bool = True """是否激活""" + def __repr__(self): + return f"FuncTool(name={self.name}, parameters={self.parameters}, description={self.description}), active={self.active})" + SUPPORTED_TYPES = [ "string", diff --git a/astrbot/core/provider/manager.py b/astrbot/core/provider/manager.py index 3da2ea00c..28146333f 100644 --- a/astrbot/core/provider/manager.py +++ b/astrbot/core/provider/manager.py @@ -132,9 +132,8 @@ class ProviderManager: return logger.info( - f"载入 {provider_config['type']}({provider_config['id']}) 服务提供商适配器 ..." + f"载入 {provider_config['type']}({provider_config['id']}) 服务提供商 ..." ) - logger.debug(f"Provider Config: {provider_config}") # 动态导入 try: diff --git a/astrbot/core/star/star_manager.py b/astrbot/core/star/star_manager.py index be476f33f..04e523f92 100644 --- a/astrbot/core/star/star_manager.py +++ b/astrbot/core/star/star_manager.py @@ -79,7 +79,7 @@ class PluginManager: elif os.path.exists(os.path.join(path, d, d + ".py")): module_str = d else: - print(f"插件 {d} 未找到 main.py 或者 {d}.py,跳过。") + logger.info(f"插件 {d} 未找到 main.py 或者 {d}.py,跳过。") continue if os.path.exists(os.path.join(path, d, "main.py")) or os.path.exists( os.path.join(path, d, d + ".py")