Files
goproxy/examples/plugin/plugins/stats/stats_plugin.go
DarkiT 557059b2d2 增强插件系统:优化插件管理和动态插件实现
- 在插件管理器中引入 DynamicPlugin 结构体,支持动态加载和管理插件,提升插件的灵活性和可扩展性。
- 更新插件接口,添加插件名称、版本、描述、作者、类型和启用状态的获取和设置方法,增强插件信息的管理能力。
- 修改现有插件实现,确保兼容新的动态插件结构,提升插件的统一性和可维护性。
- 更新示例程序,展示如何使用新的动态插件功能,提升用户体验。

此更新提升了插件系统的灵活性和可扩展性,便于开发者更好地管理和使用插件功能。
2025-03-14 07:12:05 +00:00

297 lines
7.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"context"
"fmt"
"sync"
"time"
"github.com/darkit/goproxy/examples/plugin"
)
// StatsPlugin 统计插件
// 用于收集和记录系统运行时统计数据
type StatsPlugin struct {
plugin.Plugin // 嵌入接口,确保类型检查
name string // 插件名称
version string // 插件版本
description string // 插件描述
author string // 插件作者
pluginType plugin.PluginType // 插件类型
enabled bool // 是否启用
stats map[string]int64
startTime time.Time
mu sync.RWMutex
tickerStop chan bool
ticker *time.Ticker
config map[string]interface{}
}
// StatsParams 统计请求参数结构体
// 允许通过结构体传递参数,简化调用
type StatsParams struct {
Name string `json:"name"` // 统计项名称
Value int64 `json:"value"` // 统计值
BytesReceived int64 `json:"bytesReceived"` // 接收字节数
BytesSent int64 `json:"bytesSent"` // 发送字节数
IsError bool `json:"isError"` // 是否为错误请求
}
// Plugin 导出的插件变量
var Plugin = &StatsPlugin{
name: "StatsPlugin",
version: "1.0.0",
description: "系统运行时统计插件",
author: "开发者",
pluginType: plugin.PluginTypeUtils, // 指定为工具类插件
enabled: true,
stats: make(map[string]int64),
tickerStop: make(chan bool),
}
// Name 返回插件名称
func (p *StatsPlugin) Name() string {
return p.name
}
// Version 返回插件版本
func (p *StatsPlugin) Version() string {
return p.version
}
// Description 返回插件描述
func (p *StatsPlugin) Description() string {
return p.description
}
// Author 返回插件作者
func (p *StatsPlugin) Author() string {
return p.author
}
// Type 返回插件类型
func (p *StatsPlugin) Type() plugin.PluginType {
return p.pluginType
}
// IsEnabled 返回插件是否启用
func (p *StatsPlugin) IsEnabled() bool {
return p.enabled
}
// SetEnabled 设置插件启用状态
func (p *StatsPlugin) SetEnabled(enabled bool) {
p.enabled = enabled
}
// GetOperationInfo 获取操作的参数信息
func (p *StatsPlugin) GetOperationInfo(operation string) (map[string]interface{}, error) {
return map[string]interface{}{}, nil
}
// GetAllOperations 获取所有操作及其参数信息
func (p *StatsPlugin) GetAllOperations() map[string]map[string]interface{} {
return map[string]map[string]interface{}{}
}
// 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调用的操作
// IncrementStat 增加统计值
// 会被自动注册为"incrementstat"操作
func (p *StatsPlugin) IncrementStat(name string, value int64) error {
p.mu.Lock()
defer p.mu.Unlock()
if _, exists := p.stats[name]; exists {
p.stats[name] += value
} else {
p.stats[name] = value
}
return nil
}
// GetStat 获取统计值
// 会被自动注册为"getstat"操作
func (p *StatsPlugin) GetStat(name string) (int64, error) {
p.mu.RLock()
defer p.mu.RUnlock()
if value, exists := p.stats[name]; exists {
return value, nil
}
return 0, fmt.Errorf("统计项 %s 不存在", name)
}
// RecordRequest 记录请求
// 会被自动注册为"recordrequest"操作
func (p *StatsPlugin) RecordRequest(ctx context.Context, params StatsParams) error {
p.IncrementStat("requests", 1)
p.IncrementStat("bytes_received", params.BytesReceived)
p.IncrementStat("bytes_sent", params.BytesSent)
if params.IsError {
p.IncrementStat("errors", 1)
}
return nil
}
// ResetStats 重置统计数据
// 会被自动注册为"resetstats"操作
func (p *StatsPlugin) ResetStats() error {
p.mu.Lock()
defer p.mu.Unlock()
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()
return nil
}
// GenerateStatsReport 生成统计报告
// 会被自动注册为"generatestatsreport"操作
func (p *StatsPlugin) GenerateStatsReport() (map[string]interface{}, error) {
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, nil
}
// GetAllStats 获取所有统计数据
// 会被自动注册为"getallstats"操作
func (p *StatsPlugin) GetAllStats() (map[string]int64, error) {
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, nil
}
// 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")
}
// GetAvailableOperations 获取可用操作列表
// 这是一个帮助方法列出所有可通过Execute调用的操作
func (p *StatsPlugin) GetAvailableOperations() []string {
// 返回硬编码的操作列表,而不是调用不存在的方法
return []string{
"incrementstat",
"getstat",
"recordrequest",
"resetstats",
"generatestatsreport",
"getallstats",
}
}
// main 函数是必须的,但不会被调用
func main() {
// 不会被执行,仅用于编译插件
}