update: 2023-03-15
1. 添加URL重写器 2. 添加插件系统
This commit is contained in:
22
examples/plugin/plugins/build.sh
Normal file
22
examples/plugin/plugins/build.sh
Normal file
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 编译插件
|
||||
go build -buildmode=plugin -o stats.so ./stats/stats.go
|
||||
|
||||
# 检查编译结果
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "插件编译成功: stats.so"
|
||||
else
|
||||
echo "插件编译失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
go build -buildmode=plugin -o logger.so ./logger/logger.go
|
||||
# 检查编译结果
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "插件编译成功: logger.so"
|
||||
else
|
||||
echo "插件编译失败"
|
||||
exit 1
|
||||
fi
|
126
examples/plugin/plugins/logger/logger_plugin.go
Normal file
126
examples/plugin/plugins/logger/logger_plugin.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/darkit/goproxy/examples/plugin"
|
||||
)
|
||||
|
||||
// LoggerPlugin 日志插件
|
||||
// 提供文件日志和控制台日志功能
|
||||
type LoggerPlugin struct {
|
||||
*plugin.BasePlugin // 嵌入基本插件结构
|
||||
logFile *os.File // 日志文件
|
||||
logger *log.Logger // 日志记录器
|
||||
config map[string]interface{} // 配置
|
||||
}
|
||||
|
||||
// Plugin 导出的插件变量
|
||||
// 注意:变量名必须是Plugin,大小写敏感
|
||||
var Plugin = &LoggerPlugin{
|
||||
BasePlugin: plugin.NewBasePlugin(
|
||||
"LoggerPlugin",
|
||||
"1.0.0",
|
||||
"简单的日志记录插件",
|
||||
"开发者",
|
||||
),
|
||||
}
|
||||
|
||||
// Init 初始化插件
|
||||
func (p *LoggerPlugin) Init(config map[string]interface{}) error {
|
||||
p.config = config
|
||||
|
||||
// 获取日志文件路径
|
||||
logPath, ok := config["log_path"].(string)
|
||||
if !ok {
|
||||
// 使用默认路径
|
||||
logPath = "logs"
|
||||
}
|
||||
|
||||
// 确保日志目录存在
|
||||
if err := os.MkdirAll(logPath, 0o755); err != nil {
|
||||
return fmt.Errorf("创建日志目录失败: %v", err)
|
||||
}
|
||||
|
||||
// 创建日志文件
|
||||
logFilePath := filepath.Join(logPath, fmt.Sprintf("app_%s.log", time.Now().Format("2006-01-02")))
|
||||
logFile, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("打开日志文件失败: %v", err)
|
||||
}
|
||||
|
||||
p.logFile = logFile
|
||||
p.logger = log.New(logFile, "[LoggerPlugin] ", log.LstdFlags)
|
||||
|
||||
p.logger.Println("日志插件初始化完成")
|
||||
fmt.Println("日志插件初始化完成,日志文件:", logFilePath)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start 启动插件
|
||||
func (p *LoggerPlugin) Start() error {
|
||||
if p.logger == nil {
|
||||
return fmt.Errorf("插件未初始化")
|
||||
}
|
||||
|
||||
p.logger.Println("日志插件已启动")
|
||||
fmt.Println("日志插件已启动")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop 停止插件
|
||||
func (p *LoggerPlugin) Stop() error {
|
||||
if p.logger != nil {
|
||||
p.logger.Println("日志插件正在停止")
|
||||
}
|
||||
|
||||
if p.logFile != nil {
|
||||
if err := p.logFile.Close(); err != nil {
|
||||
return fmt.Errorf("关闭日志文件失败: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("日志插件已停止")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Log 记录日志
|
||||
func (p *LoggerPlugin) Log(level, message string) {
|
||||
if p.logger == nil {
|
||||
fmt.Printf("[%s] %s\n", level, message)
|
||||
return
|
||||
}
|
||||
|
||||
logMsg := fmt.Sprintf("[%s] %s", level, message)
|
||||
p.logger.Println(logMsg)
|
||||
|
||||
// 如果配置了同时输出到控制台
|
||||
if consoleOutput, ok := p.config["console_output"].(bool); ok && consoleOutput {
|
||||
fmt.Println(logMsg)
|
||||
}
|
||||
}
|
||||
|
||||
// Info 记录信息日志
|
||||
func (p *LoggerPlugin) Info(message string) {
|
||||
p.Log("INFO", message)
|
||||
}
|
||||
|
||||
// Warn 记录警告日志
|
||||
func (p *LoggerPlugin) Warn(message string) {
|
||||
p.Log("WARN", message)
|
||||
}
|
||||
|
||||
// Error 记录错误日志
|
||||
func (p *LoggerPlugin) Error(message string) {
|
||||
p.Log("ERROR", message)
|
||||
}
|
||||
|
||||
// main 函数是必须的,但不会被调用
|
||||
func main() {
|
||||
// 不会被执行,仅用于编译插件
|
||||
}
|
170
examples/plugin/plugins/stats/stats_plugin.go
Normal file
170
examples/plugin/plugins/stats/stats_plugin.go
Normal file
@@ -0,0 +1,170 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"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.NewBasePlugin(
|
||||
"StatsPlugin",
|
||||
"1.0.0",
|
||||
"系统运行时统计插件",
|
||||
"开发者",
|
||||
),
|
||||
stats: make(map[string]int64),
|
||||
tickerStop: make(chan bool),
|
||||
}
|
||||
|
||||
// Init 初始化插件
|
||||
func (p *StatsPlugin) Init(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() 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
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
fmt.Println("统计插件已启动")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop 停止插件
|
||||
func (p *StatsPlugin) Stop() error {
|
||||
if p.ticker != nil {
|
||||
p.tickerStop <- true
|
||||
}
|
||||
|
||||
// 输出最终统计信息
|
||||
p.logStats()
|
||||
|
||||
fmt.Println("统计插件已停止")
|
||||
return 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")
|
||||
}
|
||||
|
||||
// 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() {
|
||||
// 不会被执行,仅用于编译插件
|
||||
}
|
Reference in New Issue
Block a user