- 在插件接口和基本插件实现中新增 Execute 方法,支持插件功能的动态执行。 - 更新各个插件(如日志插件、统计插件、存储插件等)以实现 Execute 方法,允许通过操作名称和参数执行特定功能。 - 在插件管理器中添加 ExecutePlugin、ExecutePluginsByType 和 ExecuteAllPlugins 方法,便于批量执行插件操作。 - 示例程序中更新插件调用方式,展示如何使用 Execute 方法进行操作。 此更新提升了插件系统的灵活性和可扩展性,便于开发者动态管理和执行插件功能。
298 lines
6.9 KiB
Go
298 lines
6.9 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/darkit/goproxy/examples/plugin"
|
|
)
|
|
|
|
// StatsPlugin 统计插件
|
|
// 用于收集和记录系统运行时统计数据
|
|
type StatsPlugin struct {
|
|
*plugin.BasePlugin
|
|
stats map[string]int64
|
|
startTime time.Time
|
|
mu sync.RWMutex
|
|
tickerStop chan bool
|
|
ticker *time.Ticker
|
|
config map[string]interface{}
|
|
}
|
|
|
|
// Plugin 导出的插件变量
|
|
var Plugin = &StatsPlugin{
|
|
// 使用默认构造函数,不指定插件类型,将默认为通用插件
|
|
BasePlugin: plugin.NewBasePluginWithDefaultType(
|
|
"StatsPlugin",
|
|
"1.0.0",
|
|
"系统运行时统计插件",
|
|
"开发者",
|
|
),
|
|
stats: make(map[string]int64),
|
|
tickerStop: make(chan bool),
|
|
}
|
|
|
|
// 为展示如何指定类型,我们也可以显式设置插件类型
|
|
// var Plugin = &StatsPlugin{
|
|
// BasePlugin: plugin.NewBasePlugin(
|
|
// "StatsPlugin",
|
|
// "1.0.0",
|
|
// "系统运行时统计插件",
|
|
// "开发者",
|
|
// plugin.PluginTypeUtils, // 明确指定为工具类插件
|
|
// ),
|
|
// stats: make(map[string]int64),
|
|
// tickerStop: make(chan bool),
|
|
// }
|
|
|
|
// Init 初始化插件
|
|
func (p *StatsPlugin) Init(ctx context.Context, config map[string]interface{}) error {
|
|
p.config = config
|
|
|
|
// 初始化统计指标
|
|
p.mu.Lock()
|
|
p.stats["requests"] = 0
|
|
p.stats["errors"] = 0
|
|
p.stats["bytes_sent"] = 0
|
|
p.stats["bytes_received"] = 0
|
|
p.mu.Unlock()
|
|
|
|
fmt.Println("统计插件初始化完成")
|
|
return nil
|
|
}
|
|
|
|
// Start 启动插件
|
|
func (p *StatsPlugin) Start(ctx context.Context) error {
|
|
p.startTime = time.Now()
|
|
|
|
// 启动定时统计任务
|
|
interval := 60 * time.Second // 默认60秒
|
|
|
|
// 从配置中获取统计间隔
|
|
if intervalSec, ok := p.config["interval_seconds"].(float64); ok {
|
|
interval = time.Duration(intervalSec) * time.Second
|
|
}
|
|
|
|
p.ticker = time.NewTicker(interval)
|
|
|
|
go func() {
|
|
for {
|
|
select {
|
|
case <-p.ticker.C:
|
|
p.logStats()
|
|
case <-p.tickerStop:
|
|
p.ticker.Stop()
|
|
return
|
|
case <-ctx.Done():
|
|
p.ticker.Stop()
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
fmt.Println("统计插件已启动")
|
|
return nil
|
|
}
|
|
|
|
// Stop 停止插件
|
|
func (p *StatsPlugin) Stop(ctx context.Context) error {
|
|
if p.ticker != nil {
|
|
p.tickerStop <- true
|
|
}
|
|
|
|
// 输出最终统计信息
|
|
p.logStats()
|
|
|
|
fmt.Println("统计插件已停止")
|
|
return nil
|
|
}
|
|
|
|
// Execute 执行插件功能
|
|
func (p *StatsPlugin) Execute(ctx context.Context, action string, params map[string]interface{}) (interface{}, error) {
|
|
switch action {
|
|
case "incrementStat":
|
|
// 需要参数: name, value
|
|
name, ok := params["name"].(string)
|
|
if !ok {
|
|
return nil, fmt.Errorf("缺少必需参数: name")
|
|
}
|
|
|
|
// 处理整数值参数
|
|
var value int64
|
|
if floatValue, ok := params["value"].(float64); ok {
|
|
value = int64(floatValue)
|
|
} else if strValue, ok := params["value"].(string); ok {
|
|
var err error
|
|
_, err = fmt.Sscanf(strValue, "%d", &value)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("参数value必须是整数: %v", err)
|
|
}
|
|
} else {
|
|
return nil, fmt.Errorf("缺少必需参数: value")
|
|
}
|
|
|
|
p.IncrementStat(name, value)
|
|
return true, nil
|
|
|
|
case "getStat":
|
|
// 需要参数: name
|
|
name, ok := params["name"].(string)
|
|
if !ok {
|
|
return nil, fmt.Errorf("缺少必需参数: name")
|
|
}
|
|
|
|
value := p.GetStat(name)
|
|
return value, nil
|
|
|
|
case "getAllStats":
|
|
// 不需要参数
|
|
return p.GetAllStats(), nil
|
|
|
|
case "recordRequest":
|
|
// 需要参数: bytesReceived, bytesSent, isError
|
|
var bytesReceived, bytesSent int64
|
|
var isError bool
|
|
|
|
// 处理bytesReceived参数
|
|
if floatValue, ok := params["bytesReceived"].(float64); ok {
|
|
bytesReceived = int64(floatValue)
|
|
} else {
|
|
return nil, fmt.Errorf("缺少必需参数: bytesReceived")
|
|
}
|
|
|
|
// 处理bytesSent参数
|
|
if floatValue, ok := params["bytesSent"].(float64); ok {
|
|
bytesSent = int64(floatValue)
|
|
} else {
|
|
return nil, fmt.Errorf("缺少必需参数: bytesSent")
|
|
}
|
|
|
|
// 处理isError参数
|
|
if value, ok := params["isError"].(bool); ok {
|
|
isError = value
|
|
}
|
|
|
|
p.RecordRequest(bytesReceived, bytesSent, isError)
|
|
return true, nil
|
|
|
|
case "resetStats":
|
|
// 不需要参数
|
|
p.mu.Lock()
|
|
p.stats = make(map[string]int64)
|
|
p.stats["requests"] = 0
|
|
p.stats["errors"] = 0
|
|
p.stats["bytes_sent"] = 0
|
|
p.stats["bytes_received"] = 0
|
|
p.startTime = time.Now()
|
|
p.mu.Unlock()
|
|
return true, nil
|
|
|
|
case "getStatsReport":
|
|
// 生成统计报告
|
|
report := p.generateStatsReport()
|
|
return report, nil
|
|
|
|
default:
|
|
return nil, fmt.Errorf("未知的操作: %s", action)
|
|
}
|
|
}
|
|
|
|
// generateStatsReport 生成统计报告
|
|
func (p *StatsPlugin) generateStatsReport() map[string]interface{} {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
|
|
uptime := time.Since(p.startTime).Seconds()
|
|
report := map[string]interface{}{
|
|
"uptime_seconds": uptime,
|
|
"stats": p.stats,
|
|
}
|
|
|
|
if uptime > 0 && p.stats["requests"] > 0 {
|
|
report["requests_per_second"] = float64(p.stats["requests"]) / uptime
|
|
report["error_rate"] = float64(p.stats["errors"]) * 100 / float64(p.stats["requests"])
|
|
}
|
|
|
|
return report
|
|
}
|
|
|
|
// logStats 记录当前统计信息
|
|
func (p *StatsPlugin) logStats() {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
|
|
uptime := time.Since(p.startTime).Seconds()
|
|
|
|
fmt.Printf("===== 系统统计信息 =====\n")
|
|
fmt.Printf("运行时间: %.2f 秒\n", uptime)
|
|
fmt.Printf("总请求数: %d\n", p.stats["requests"])
|
|
fmt.Printf("错误数: %d\n", p.stats["errors"])
|
|
fmt.Printf("发送字节: %d\n", p.stats["bytes_sent"])
|
|
fmt.Printf("接收字节: %d\n", p.stats["bytes_received"])
|
|
|
|
if uptime > 0 && p.stats["requests"] > 0 {
|
|
fmt.Printf("平均请求/秒: %.2f\n", float64(p.stats["requests"])/uptime)
|
|
fmt.Printf("错误率: %.2f%%\n", float64(p.stats["errors"])*100/float64(p.stats["requests"]))
|
|
}
|
|
|
|
fmt.Printf("=======================\n")
|
|
}
|
|
|
|
// IncrementStat 增加统计值
|
|
func (p *StatsPlugin) IncrementStat(name string, value int64) {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
|
|
if _, exists := p.stats[name]; exists {
|
|
p.stats[name] += value
|
|
} else {
|
|
p.stats[name] = value
|
|
}
|
|
}
|
|
|
|
// GetStat 获取统计值
|
|
func (p *StatsPlugin) GetStat(name string) int64 {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
|
|
if value, exists := p.stats[name]; exists {
|
|
return value
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// RecordRequest 记录请求
|
|
func (p *StatsPlugin) RecordRequest(bytesReceived, bytesSent int64, isError bool) {
|
|
p.IncrementStat("requests", 1)
|
|
p.IncrementStat("bytes_received", bytesReceived)
|
|
p.IncrementStat("bytes_sent", bytesSent)
|
|
|
|
if isError {
|
|
p.IncrementStat("errors", 1)
|
|
}
|
|
}
|
|
|
|
// GetAllStats 获取所有统计数据
|
|
func (p *StatsPlugin) GetAllStats() map[string]int64 {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
|
|
// 创建一个副本
|
|
statsCopy := make(map[string]int64, len(p.stats))
|
|
for k, v := range p.stats {
|
|
statsCopy[k] = v
|
|
}
|
|
|
|
// 添加运行时间
|
|
statsCopy["uptime_seconds"] = int64(time.Since(p.startTime).Seconds())
|
|
|
|
return statsCopy
|
|
}
|
|
|
|
// main 函数是必须的,但不会被调用
|
|
func main() {
|
|
// 不会被执行,仅用于编译插件
|
|
}
|