diff --git a/plugins/maibot_adapter/config.toml b/plugins/maibot_adapter/config.toml index fad27e8..a301139 100644 --- a/plugins/maibot_adapter/config.toml +++ b/plugins/maibot_adapter/config.toml @@ -1,5 +1,11 @@ [MaiBotAdapter] -enable = false +enable = true + +# 插件日志级别: +# 1. INFO:输出关键生命周期与异常信息,日志量更小; +# 2. DEBUG:输出完整运行细节(入队、路由判定、收发包、ACK 等); +# 3. 你当前要求查看更细日志,默认改为 DEBUG。 +log_level = "DEBUG" # 是否默认采集群消息到 MaiBot: # 1. 这是“把消息送给 MaiBot 做上下文与记忆”的总开关; diff --git a/plugins/maibot_adapter/main.py b/plugins/maibot_adapter/main.py index 6277c03..d496bf3 100644 --- a/plugins/maibot_adapter/main.py +++ b/plugins/maibot_adapter/main.py @@ -80,6 +80,7 @@ class MaiBotAdapterPlugin(MessagePluginInterface): self._reconnect_delay = 5 self._queue_maxsize = 500 self._max_send_retries = 3 + self._log_level = "INFO" # 运行时状态。 self._config_ready = False @@ -117,6 +118,9 @@ class MaiBotAdapterPlugin(MessagePluginInterface): self._reconnect_delay = max(1, int(plugin_config.get("reconnect_delay", 5) or 5)) self._queue_maxsize = max(50, int(plugin_config.get("queue_maxsize", 500) or 500)) self._max_send_retries = max(1, int(plugin_config.get("max_send_retries", 3) or 3)) + self._log_level = str(plugin_config.get("log_level", "INFO") or "INFO").strip().upper() + if self._log_level not in {"DEBUG", "INFO"}: + self._log_level = "INFO" # 官方 API Server 至少需要 ws 地址与 api_key: # 1. 地址用于建立长期 WebSocket; @@ -126,7 +130,7 @@ class MaiBotAdapterPlugin(MessagePluginInterface): if not self._config_ready: self.LOG.warning(f"[{self.name}] api_server_ws_url/api_key 未配置完整,插件会加载成功但不会转发消息") - self.LOG.info( + self._log_runtime( f"[{self.name}] 初始化完成: enabled={self._enabled}, " f"collect_group_messages={self._collect_group_messages}, collect_private_messages={self._collect_private_messages}, " f"enable_reply_output={self._enable_reply_output}, reply_group_messages={self._reply_group_messages}, " @@ -137,7 +141,7 @@ class MaiBotAdapterPlugin(MessagePluginInterface): def start(self) -> bool: self.status = PluginStatus.RUNNING - self.LOG.info(f"[{self.name}] 插件已启动,等待首条消息后再懒启动长连接") + self._log_runtime(f"[{self.name}] 插件已启动,等待首条消息后再懒启动长连接") return True def stop(self) -> bool: @@ -192,7 +196,7 @@ class MaiBotAdapterPlugin(MessagePluginInterface): payload = self._build_outbound_payload(message=message, normalized_content=normalized_content) try: outbound_queue.put_nowait(payload) - self.LOG.info( + self._log_runtime( f"[{self.name}] 消息已入队: route_type={payload['route_type']}, roomid={payload['roomid']}, " f"route_source={payload['route_source']}, sender={payload['sender']}, " f"msg_type={payload['message_type']}, queue_size={outbound_queue.qsize()}, " @@ -231,7 +235,7 @@ class MaiBotAdapterPlugin(MessagePluginInterface): asyncio.create_task(self._sender_loop(), name="maibot_adapter_sender_loop"), ] self._runtime_started = True - self.LOG.info( + self._log_runtime( f"[{self.name}] 后台运行时已启动: connection_uuid={self._connection_uuid}, " f"queue_maxsize={self._queue_maxsize}, heartbeat_interval={self._heartbeat_interval}" ) @@ -270,7 +274,7 @@ class MaiBotAdapterPlugin(MessagePluginInterface): } ssl_option = None if self._verify_ssl else False - self.LOG.info( + self._log_runtime( f"[{self.name}] 正在连接 MaiBot API Server: url={self._api_server_ws_url}, " f"platform={self._platform_name}, connection_uuid={headers['x-uuid']}" ) @@ -287,7 +291,7 @@ class MaiBotAdapterPlugin(MessagePluginInterface): if self._connected_event is not None: self._connected_event.set() - self.LOG.info( + self._log_runtime( f"[{self.name}] MaiBot API Server 连接成功: url={self._api_server_ws_url}, " f"connection_uuid={headers['x-uuid']}" ) @@ -303,7 +307,7 @@ class MaiBotAdapterPlugin(MessagePluginInterface): if message.type == aiohttp.WSMsgType.TEXT: raw_text = str(message.data or "") - self.LOG.info(f"[{self.name}] 收到 MaiBot 原始消息: {raw_text[:500]}") + self._log_runtime(f"[{self.name}] 收到 MaiBot 原始消息: {raw_text[:500]}") payload = self._parse_json_message(raw_text) if payload is None: continue @@ -358,7 +362,7 @@ class MaiBotAdapterPlugin(MessagePluginInterface): } await websocket.send_json(package) - self.LOG.info( + self._log_runtime( f"[{self.name}] 已发送到 MaiBot: roomid={payload['roomid']}, sender={payload['sender']}, " f"msg_type={payload['message_type']}, package_id={package['msg_id']}, " f"content_preview={payload['normalized_content'][:120]}" @@ -395,11 +399,11 @@ class MaiBotAdapterPlugin(MessagePluginInterface): if package_type == "sys_ack": acked_msg_id = str(((package.get("meta") or {}).get("acked_msg_id")) or "") - self.LOG.info(f"[{self.name}] 收到 MaiBot ACK: package_id={package_id}, acked_msg_id={acked_msg_id}") + self._log_runtime(f"[{self.name}] 收到 MaiBot ACK: package_id={package_id}, acked_msg_id={acked_msg_id}") return if package_type != "sys_std": - self.LOG.info(f"[{self.name}] 忽略非 sys_std 消息: package_type={package_type}, package_id={package_id}") + self._log_runtime(f"[{self.name}] 忽略非 sys_std 消息: package_type={package_type}, package_id={package_id}") return api_message = package.get("payload") or {} @@ -409,7 +413,7 @@ class MaiBotAdapterPlugin(MessagePluginInterface): reply_text = self._extract_segment_text(message_segment).strip() if not reply_text: - self.LOG.info( + self._log_runtime( f"[{self.name}] MaiBot 返回了空文本或非文本片段,忽略发送: package_id={package_id}, " f"segment_type={message_segment.get('type')}" ) @@ -423,7 +427,7 @@ class MaiBotAdapterPlugin(MessagePluginInterface): ) return - self.LOG.info( + self._log_runtime( f"[{self.name}] 收到 MaiBot 回复: package_id={package_id}, route_type={route['route_type']}, " f"target={route['target']}, at_target={route.get('at_target', '')}, " f"platform={message_dim.get('platform')}, reply_preview={reply_text[:120]}" @@ -434,7 +438,7 @@ class MaiBotAdapterPlugin(MessagePluginInterface): async def _emit_reply(self, route: Dict[str, str], reply_text: str, api_message: Dict[str, Any]) -> None: """按配置决定是否把 MaiBot 回复真正发回微信。""" if not self._enable_reply_output: - self.LOG.info(f"[{self.name}] enable_reply_output=false,仅采集不发回微信") + self._log_runtime(f"[{self.name}] enable_reply_output=false,仅采集不发回微信") return bot = self._last_bot or getattr(self, "bot", None) @@ -448,16 +452,16 @@ class MaiBotAdapterPlugin(MessagePluginInterface): if route_type == "group": if not self._reply_group_messages: - self.LOG.info(f"[{self.name}] reply_group_messages=false,群回复已跳过: target={target}") + self._log_runtime(f"[{self.name}] reply_group_messages=false,群回复已跳过: target={target}") return if self._respect_group_feature_switch and not self._group_reply_allowed(target): - self.LOG.info(f"[{self.name}] 群功能开关未启用,仅采集不回群: target={target}") + self._log_runtime(f"[{self.name}] 群功能开关未启用,仅采集不回群: target={target}") return if self._mention_user_on_group_reply and at_target: await bot.send_at_message(target, reply_text, [at_target]) else: await bot.send_text_message(target, reply_text, at_target if at_target else "") - self.LOG.info( + self._log_runtime( f"[{self.name}] 已发出 MaiBot 群回复: target={target}, at_target={at_target}, " f"reply_len={len(reply_text)}" ) @@ -465,10 +469,10 @@ class MaiBotAdapterPlugin(MessagePluginInterface): if route_type == "private": if not self._reply_private_messages: - self.LOG.info(f"[{self.name}] reply_private_messages=false,私聊回复已跳过: target={target}") + self._log_runtime(f"[{self.name}] reply_private_messages=false,私聊回复已跳过: target={target}") return await bot.send_text_message(target, reply_text, "") - self.LOG.info(f"[{self.name}] 已发出 MaiBot 私聊回复: target={target}, reply_len={len(reply_text)}") + self._log_runtime(f"[{self.name}] 已发出 MaiBot 私聊回复: target={target}, reply_len={len(reply_text)}") return self.LOG.warning(f"[{self.name}] 未知路由类型,无法发送 MaiBot 回复: route={route}, api_message={api_message}") @@ -506,7 +510,7 @@ class MaiBotAdapterPlugin(MessagePluginInterface): group_name = self._resolve_group_name(message, roomid) # 路由诊断日志:这里把关键字段一次性打全,便于定位“群消息为何被识别成私聊”。 - self.LOG.info( + self._log_runtime( f"[{self.name}] 路由判定: route_type={route_type}, route_source={route_source}, " f"plugin_roomid={str(message.get('roomid', '') or '').strip()}, " f"wx_roomid={str(getattr(full_msg, 'roomid', '') or '').strip() if isinstance(full_msg, WxMessage) else ''}, " @@ -813,6 +817,13 @@ class MaiBotAdapterPlugin(MessagePluginInterface): return None return payload + def _log_runtime(self, message: str) -> None: + """根据插件配置动态输出运行日志级别。""" + if self._log_level == "DEBUG": + self.LOG.debug(message) + return + self.LOG.info(message) + def _is_supported_message(self, message: Dict[str, Any]) -> bool: """仅接收 MaiBot 当前最适合做上下文理解的消息类型。""" full_msg = message.get("full_wx_msg")