feat: 日志中心 + GRE协议支持 + 流量监控 + 部署脚本

- 新增日志中心功能 (api/logapi.go + Logs.vue)
- 新增GRE协议服务支持 (service/gre/)
- 新增流量监控组件 (TrafficChart.vue)
- 新增L2TP/IPSec测试用例
- 新增日志轮转服务 (logrotate.go)
- 新增部署脚本 (scripts/install.sh, uninstall.sh, service文件)
- 更新i18n国际化文件
- 优化后端API和前端路由
This commit is contained in:
opsx-tools committed 2026-07-25 08:50:34 +08:00
1 parent 7de1f70905
commit a14d9e62e6
25 files changed
+2285 -25

No files matched your search

+50
View File
@@ -3,10 +3,12 @@ package main
import (
"embed"
"fmt"
"io/fs"
"log"
"net/http"
"os"
"strconv"
"strings"
"time"
@@ -17,6 +19,7 @@ import (
"vpn-platform/backend/internal/monitor"
"vpn-platform/backend/internal/service"
"vpn-platform/backend/internal/service/custom"
"vpn-platform/backend/internal/service/gre"
"vpn-platform/backend/internal/service/frp"
"vpn-platform/backend/internal/service/ikev2"
"vpn-platform/backend/internal/service/ipsec"
@@ -55,11 +58,14 @@ func main() {
mgr.Register(ikev2.New())
mgr.Register(l2tp.New())
mgr.Register(frp.New())
mgr.Register(gre.New())
mgr.Register(openvpn.New())
// 加载数据库中的自定义协议插件
custom.LoadAll(mgr)
r := gin.New()
// HTTP 访问日志(带轮转,默认 20MB x 3 文件)
r.Use(accessLogger())
r.Use(gin.Recovery())
srv := api.NewServer(mgr)
@@ -93,6 +99,15 @@ func main() {
fileServer.ServeHTTP(c.Writer, c.Request)
})
// 启动时自动清理过期日志(默认保留 90 天,可通过 VPN_LOG_RETENTION_DAYS 覆盖)
retentionDays := 90
if v := os.Getenv("VPN_LOG_RETENTION_DAYS"); v != "" {
if d, err := strconv.Atoi(v); err == nil && d > 0 {
retentionDays = d
}
}
api.AutoCleanupLogs(retentionDays)
// 状态采集 + 自启恢复
monitor.Start(mgr, 15*time.Second)
monitor.AutoStartAll(mgr)
@@ -115,3 +130,38 @@ func main() {
log.Fatal(err)
}
}
// accessLogger 返回自定义的 HTTP 请求日志中间件(带日志轮转)
// 格式: [2006-01-02 15:04:05] "GET /api/tunnels 200 12.5ms 192.168.1.1"
func accessLogger() gin.HandlerFunc {
// 构造日志文件路径
dataDir := service.BaseDir()
logPath := fmt.Sprintf("%s/access.log", dataDir)
// 轮转配置:默认 20MB x 3 文件,可通过环境变量覆盖
cfg := service.DefaultRotateConfig("VPN_ACCESS_LOG_MAX_SIZE", 20*1024*1024, 3)
writer, err := service.NewRotatingWriter(logPath, cfg)
if err != nil {
// 降级到 stderr
log.Printf("警告: 无法创建访问日志文件 %s: %v,降级到标准输出", logPath, err)
return gin.Logger()
}
return func(c *gin.Context) {
start := time.Now()
path := c.Request.URL.Path
c.Next()
latency := time.Since(start)
status := c.Writer.Status()
line := fmt.Sprintf("[%s] %s %s %d %s %s\n",
time.Now().Format("2006-01-02 15:04:05"),
c.Request.Method,
path,
status,
latency.Round(time.Millisecond),
c.ClientIP(),
)
_, _ = writer.Write([]byte(line))
}
}