Merge branch 'main' of https://github.com/Fairy-Oracle-Sanctuary/NeoBot into dev
This commit is contained in:
@@ -6,6 +6,7 @@ Bot 状态查询插件
|
|||||||
import os
|
import os
|
||||||
import psutil
|
import psutil
|
||||||
import time
|
import time
|
||||||
|
import asyncio
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from core.bot import Bot
|
from core.bot import Bot
|
||||||
@@ -32,15 +33,23 @@ def _get_system_info():
|
|||||||
"""
|
"""
|
||||||
同步函数:使用 psutil 获取系统信息,避免阻塞事件循环。
|
同步函数:使用 psutil 获取系统信息,避免阻塞事件循环。
|
||||||
"""
|
"""
|
||||||
# interval=1 会阻塞1秒,必须在线程池中运行
|
try:
|
||||||
cpu_percent = psutil.cpu_percent(interval=1)
|
# interval=1 会阻塞1秒,必须在线程池中运行
|
||||||
mem_info = psutil.virtual_memory()
|
cpu_percent = psutil.cpu_percent(interval=1)
|
||||||
bot_mem_mb = PROCESS.memory_info().rss / (1024 * 1024)
|
mem_info = psutil.virtual_memory()
|
||||||
return {
|
bot_mem_mb = PROCESS.memory_info().rss / (1024 * 1024)
|
||||||
"cpu_percent": f"{cpu_percent:.1f}",
|
return {
|
||||||
"mem_percent": f"{mem_info.percent:.1f}",
|
"cpu_percent": f"{cpu_percent:.1f}",
|
||||||
"bot_mem_mb": f"{bot_mem_mb:.2f}",
|
"mem_percent": f"{mem_info.percent:.1f}",
|
||||||
}
|
"bot_mem_mb": f"{bot_mem_mb:.2f}",
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"获取系统信息失败: {e}")
|
||||||
|
return {
|
||||||
|
"cpu_percent": "N/A",
|
||||||
|
"mem_percent": "N/A",
|
||||||
|
"bot_mem_mb": "N/A",
|
||||||
|
}
|
||||||
|
|
||||||
@matcher.command("status", "状态")
|
@matcher.command("status", "状态")
|
||||||
async def handle_status(bot: Bot, event: MessageEvent, args: list[str]):
|
async def handle_status(bot: Bot, event: MessageEvent, args: list[str]):
|
||||||
@@ -93,26 +102,51 @@ async def handle_status(bot: Bot, event: MessageEvent, args: list[str]):
|
|||||||
}
|
}
|
||||||
|
|
||||||
# 3. 获取统计数据
|
# 3. 获取统计数据
|
||||||
msgs_recv = await redis_manager.get("neobot:stats:messages_received") or 0
|
try:
|
||||||
msgs_sent = await redis_manager.get("neobot:stats:messages_sent") or 0
|
msgs_recv = await redis_manager.get("neobot:stats:messages_received") or 0
|
||||||
command_stats_raw = await redis_manager.redis.hgetall("neobot:command_stats")
|
msgs_sent = await redis_manager.get("neobot:stats:messages_sent") or 0
|
||||||
|
command_stats_raw = await redis_manager.redis.hgetall("neobot:command_stats")
|
||||||
|
|
||||||
total_commands = sum(int(v) for v in command_stats_raw.values())
|
total_commands = sum(int(v) for v in command_stats_raw.values())
|
||||||
|
|
||||||
stats_data = {
|
stats_data = {
|
||||||
"messages_received": int(msgs_recv),
|
"messages_received": int(msgs_recv),
|
||||||
"messages_sent": int(msgs_sent),
|
"messages_sent": int(msgs_sent),
|
||||||
"total_commands": total_commands,
|
"total_commands": total_commands,
|
||||||
}
|
}
|
||||||
|
|
||||||
command_stats_data = sorted(
|
command_stats_data = sorted(
|
||||||
[{"name": k, "count": int(v)} for k, v in command_stats_raw.items()],
|
[{"name": k, "count": int(v)} for k, v in command_stats_raw.items()],
|
||||||
key=lambda x: x["count"],
|
key=lambda x: x["count"],
|
||||||
reverse=True
|
reverse=True
|
||||||
)
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"获取Redis统计数据失败: {e}")
|
||||||
|
stats_data = {
|
||||||
|
"messages_received": 0,
|
||||||
|
"messages_sent": 0,
|
||||||
|
"total_commands": 0,
|
||||||
|
}
|
||||||
|
command_stats_data = []
|
||||||
|
|
||||||
# 4. 异步获取系统信息
|
# 4. 异步获取系统信息
|
||||||
system_data = await run_in_thread_pool(_get_system_info)
|
# 设置超时,防止 psutil 阻塞过久
|
||||||
|
try:
|
||||||
|
system_data = await asyncio.wait_for(run_in_thread_pool(_get_system_info), timeout=5.0)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
logger.error("获取系统信息超时")
|
||||||
|
system_data = {
|
||||||
|
"cpu_percent": "Timeout",
|
||||||
|
"mem_percent": "Timeout",
|
||||||
|
"bot_mem_mb": "Timeout",
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"获取系统信息异常: {e}")
|
||||||
|
system_data = {
|
||||||
|
"cpu_percent": "Error",
|
||||||
|
"mem_percent": "Error",
|
||||||
|
"bot_mem_mb": "Error",
|
||||||
|
}
|
||||||
|
|
||||||
# 5. 准备模板所需的所有数据
|
# 5. 准备模板所需的所有数据
|
||||||
template_data = {
|
template_data = {
|
||||||
@@ -125,18 +159,22 @@ async def handle_status(bot: Bot, event: MessageEvent, args: list[str]):
|
|||||||
}
|
}
|
||||||
|
|
||||||
# 6. 渲染图片
|
# 6. 渲染图片
|
||||||
base64_str = await image_manager.render_template_to_base64(
|
try:
|
||||||
template_name="status.html",
|
base64_str = await image_manager.render_template_to_base64(
|
||||||
data=template_data,
|
template_name="status.html",
|
||||||
output_name="status.png",
|
data=template_data,
|
||||||
image_type="png"
|
output_name="status.png",
|
||||||
)
|
image_type="png"
|
||||||
|
)
|
||||||
|
|
||||||
if base64_str:
|
if base64_str:
|
||||||
await event.reply(MessageSegment.image(base64_str))
|
await event.reply(MessageSegment.image(base64_str))
|
||||||
else:
|
else:
|
||||||
# 如果渲染失败,image_manager 内部会记录错误,这里给用户一个通用提示
|
# 如果渲染失败,image_manager 内部会记录错误,这里给用户一个通用提示
|
||||||
await event.reply("状态图片生成失败,可能是渲染服务出现问题,请联系管理员。")
|
await event.reply("状态图片生成失败,可能是渲染服务出现问题,请联系管理员。")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"渲染图片失败: {e}")
|
||||||
|
await event.reply("状态图片渲染过程中发生错误。")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(f"生成状态图时发生意外错误, 用户: {event.user_id}")
|
logger.exception(f"生成状态图时发生意外错误, 用户: {event.user_id}")
|
||||||
|
|||||||
Reference in New Issue
Block a user