加入指令数据统计,指令看板内容
This commit is contained in:
7
plugins/stats_collector/__init__.py
Normal file
7
plugins/stats_collector/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from plugins.stats_collector.main import StatsCollectorPlugin
|
||||
|
||||
def get_plugin():
|
||||
"""获取插件实例"""
|
||||
return StatsCollectorPlugin()
|
||||
|
||||
__all__ = ['StatsCollectorPlugin', 'get_plugin']
|
||||
21
plugins/stats_collector/config.yaml
Normal file
21
plugins/stats_collector/config.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
# 统计收集器插件配置
|
||||
name: stats_collector
|
||||
description: 插件使用统计收集器
|
||||
version: 1.0.0
|
||||
author: Trae AI
|
||||
enabled: true
|
||||
|
||||
# 统计设置
|
||||
settings:
|
||||
# 是否记录详细日志
|
||||
debug_logging: false
|
||||
|
||||
# 统计保留天数
|
||||
retention_days: 90
|
||||
|
||||
# 是否统计系统插件
|
||||
include_system_plugins: true
|
||||
|
||||
# 排除的插件列表
|
||||
excluded_plugins:
|
||||
- stats_collector
|
||||
75
plugins/stats_collector/decorators.py
Normal file
75
plugins/stats_collector/decorators.py
Normal file
@@ -0,0 +1,75 @@
|
||||
import functools
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
from typing import Callable, Dict, Any, Tuple
|
||||
|
||||
from event_system.event_manager import EventManager
|
||||
from event_system.events.stats_events import PluginCallStartEvent, PluginCallEndEvent, PluginCallErrorEvent
|
||||
|
||||
|
||||
def plugin_stats_decorator(plugin_name: str) -> Callable:
|
||||
"""插件统计装饰器
|
||||
|
||||
Args:
|
||||
plugin_name: 插件名称
|
||||
|
||||
Returns:
|
||||
装饰器函数
|
||||
"""
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@functools.wraps(func)
|
||||
def wrapper(self, message: Dict[str, Any]) -> Tuple[bool, str]:
|
||||
# 获取事件管理器
|
||||
event_manager = EventManager.get_instance()
|
||||
|
||||
# 提取消息信息
|
||||
content = message.get("content", "")
|
||||
sender = message.get("sender", "")
|
||||
roomid = message.get("roomid", "")
|
||||
|
||||
# 发布插件调用开始事件
|
||||
start_time = datetime.now()
|
||||
event_manager.publish(PluginCallStartEvent, {
|
||||
"plugin_name": plugin_name,
|
||||
"command": content,
|
||||
"user_id": sender,
|
||||
"group_id": roomid,
|
||||
"start_time": start_time
|
||||
})
|
||||
|
||||
try:
|
||||
# 调用原始方法
|
||||
success, response = func(self, message)
|
||||
|
||||
# 发布插件调用结束事件
|
||||
end_time = datetime.now()
|
||||
event_manager.publish(PluginCallEndEvent, {
|
||||
"plugin_name": plugin_name,
|
||||
"command": content,
|
||||
"user_id": sender,
|
||||
"group_id": roomid,
|
||||
"start_time": start_time,
|
||||
"end_time": end_time,
|
||||
"success": success,
|
||||
"response": response
|
||||
})
|
||||
|
||||
return success, response
|
||||
except Exception as e:
|
||||
# 发布插件调用错误事件
|
||||
event_manager.publish(PluginCallErrorEvent, {
|
||||
"plugin_name": plugin_name,
|
||||
"command": content,
|
||||
"user_id": sender,
|
||||
"group_id": roomid,
|
||||
"start_time": start_time,
|
||||
"error_message": str(e),
|
||||
"stack_trace": traceback.format_exc()
|
||||
})
|
||||
|
||||
# 重新抛出异常,让上层处理
|
||||
raise
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
136
plugins/stats_collector/main.py
Normal file
136
plugins/stats_collector/main.py
Normal file
@@ -0,0 +1,136 @@
|
||||
import logging
|
||||
import time
|
||||
from typing import Dict, Any, Tuple, Optional
|
||||
from datetime import datetime
|
||||
|
||||
from plugin_common.plugin_interface import PluginInterface
|
||||
from event_system.event_manager import EventManager
|
||||
# 修正导入,使用与装饰器相同的事件类型
|
||||
from event_system.events.plugin_events import PluginCallStartEvent, PluginCallEndEvent, PluginCallErrorEvent
|
||||
from db.stats_db import StatsDBOperator
|
||||
from db.db_manager import DBConnectionManager
|
||||
from job_decorators import register_job_decorator
|
||||
|
||||
from .decorators import plugin_stats_decorator
|
||||
|
||||
|
||||
class StatsCollectorPlugin(PluginInterface):
|
||||
"""统计收集插件"""
|
||||
|
||||
def __init__(self):
|
||||
self.name = "统计收集器"
|
||||
self.version = "1.0.0"
|
||||
self.description = "收集插件调用统计数据"
|
||||
self.author = "Trae AI"
|
||||
self.logger = logging.getLogger("StatsCollector")
|
||||
|
||||
# 默认配置
|
||||
self.config = {
|
||||
"enable": True,
|
||||
"record_all_plugins": True, # 是否记录所有插件的调用
|
||||
"excluded_plugins": [], # 排除的插件列表
|
||||
}
|
||||
|
||||
self.event_manager = EventManager.get_instance()
|
||||
# 修正获取数据库连接管理器的方式
|
||||
self.db_manager = DBConnectionManager.get_instance()
|
||||
self.stats_db = StatsDBOperator(self.db_manager)
|
||||
|
||||
# 用于临时存储插件调用开始时间的字典
|
||||
self.plugin_call_start_times = {}
|
||||
|
||||
def initialize(self, config: Dict[str, Any]) -> bool:
|
||||
"""初始化插件"""
|
||||
if config:
|
||||
self.config.update(config)
|
||||
|
||||
if not self.config["enable"]:
|
||||
self.logger.info("统计收集插件已禁用")
|
||||
return False
|
||||
|
||||
# 注册事件处理器
|
||||
self.event_manager.register(PluginCallStartEvent, self.handle_plugin_call_start)
|
||||
self.event_manager.register(PluginCallEndEvent, self.handle_plugin_call_end)
|
||||
self.event_manager.register(PluginCallErrorEvent, self.handle_plugin_error)
|
||||
|
||||
self.logger.info("统计收集插件已初始化")
|
||||
return True
|
||||
|
||||
def handle_plugin_call_start(self, event: PluginCallStartEvent) -> None:
|
||||
"""处理插件调用开始事件"""
|
||||
# 检查是否需要记录该插件
|
||||
if not self._should_record_plugin(event.plugin_name):
|
||||
return
|
||||
|
||||
# 记录开始时间和相关信息
|
||||
# 注意:plugin_events.py 中的事件结构与 stats_events.py 不同
|
||||
self.logger.debug(f"记录插件调用开始: {event.plugin_name} - {event.command}")
|
||||
|
||||
def handle_plugin_call_end(self, event: PluginCallEndEvent) -> None:
|
||||
"""处理插件调用结束事件"""
|
||||
# 检查是否需要记录该插件
|
||||
if not self._should_record_plugin(event.plugin_name):
|
||||
return
|
||||
|
||||
# 记录统计数据
|
||||
try:
|
||||
self.stats_db.record_plugin_call(
|
||||
plugin_name=event.plugin_name,
|
||||
command=event.command,
|
||||
user_id=event.user_id,
|
||||
group_id=event.group_id,
|
||||
success=event.process_result, # 注意字段名不同
|
||||
process_time_ms=event.process_time # 注意字段名不同
|
||||
)
|
||||
self.logger.debug(f"记录插件调用结束: {event.plugin_name} - {event.command} - 成功: {event.process_result} - 处理时间: {event.process_time}ms")
|
||||
except Exception as e:
|
||||
self.logger.error(f"记录插件调用统计数据出错: {e}")
|
||||
|
||||
def handle_plugin_error(self, event: PluginCallErrorEvent) -> None:
|
||||
"""处理插件调用错误事件"""
|
||||
# 检查是否需要记录该插件
|
||||
if not self._should_record_plugin(event.plugin_name):
|
||||
return
|
||||
|
||||
# 记录错误信息
|
||||
try:
|
||||
self.stats_db.record_error(
|
||||
plugin_name=event.plugin_name,
|
||||
command=event.command,
|
||||
user_id=event.user_id,
|
||||
group_id=event.group_id,
|
||||
error_message=event.error_message,
|
||||
stack_trace=event.stack_trace
|
||||
)
|
||||
self.logger.debug(f"记录插件调用错误: {event.plugin_name} - {event.command} - {event.error_message}")
|
||||
except Exception as e:
|
||||
self.logger.error(f"记录插件错误信息出错: {e}")
|
||||
|
||||
def _should_record_plugin(self, plugin_name: str) -> bool:
|
||||
"""检查是否应该记录该插件的调用"""
|
||||
if not self.config["record_all_plugins"]:
|
||||
return False
|
||||
|
||||
if plugin_name in self.config["excluded_plugins"]:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def match_command(self, content: str) -> bool:
|
||||
"""匹配命令"""
|
||||
# 该插件不处理用户消息
|
||||
return False
|
||||
|
||||
def process_message(self, message: Dict[str, Any]) -> Tuple[bool, str]:
|
||||
"""处理消息"""
|
||||
# 该插件不处理用户消息
|
||||
return False, ""
|
||||
|
||||
def shutdown(self) -> None:
|
||||
"""关闭插件"""
|
||||
# 取消注册事件处理器
|
||||
self.event_manager.unregister(PluginCallStartEvent, self.handle_plugin_call_start)
|
||||
self.event_manager.unregister(PluginCallEndEvent, self.handle_plugin_call_end)
|
||||
self.event_manager.unregister(PluginCallErrorEvent, self.handle_plugin_error)
|
||||
|
||||
self.logger.info("统计收集插件已关闭")
|
||||
Reference in New Issue
Block a user