This commit is contained in:
WJQSERVER 2025-02-08 20:09:11 +08:00
parent c184e46917
commit efdf5b0221
8 changed files with 136 additions and 4 deletions

View file

@ -1,5 +1,12 @@
# 更新日志
25w12b
---
- PRE-RELEASE: 此版本是v2.0.8/v2.1.0的预发布版本,请勿在生产环境中使用;
- ADD: 加入`timing`中间件记录响应时间
- ADD: 加入`loggin`中间件包装日志输出
- CHANGE: 更新安全政策, v1和24w版本序列生命周期正式结束
25w12a
---
- PRE-RELEASE: 此版本是v2.0.8/v2.1.0的预发布版本,请勿在生产环境中使用;

View file

@ -1 +1 @@
25w12a
25w12b

View file

@ -6,8 +6,10 @@
| 版本 | 是否支持 |
| --- | --- |
| v1.x.x | :white_check_mark: |
| 24w*a/b/c... | :warning: 此为PRE-RELEASE版本,用于开发与测试,可能存在未知的问题 |
| v2.x.x | :white_check_mark: 当前最新版本序列, 受支持 |
| v1.x.x | :x: 这些版本已结束生命周期,不再受支持 |
| 25w*a/b/c... | :warning: 此为PRE-RELEASE版本,用于开发与测试,可能存在未知的问题 |
| 24w*a/b/c... | :warning: 此为PRE-RELEASE版本,用于开发与测试,可能存在未知的问题 生命周期已完全结束 |
| v0.x.x | :x: 这些版本不再受支持 |
### 用户须知

34
loggin/loggin.go Normal file
View file

@ -0,0 +1,34 @@
package loggin
import (
"ghproxy/timing"
"time"
"github.com/WJQSERVER-STUDIO/go-utils/logger"
"github.com/gin-gonic/gin"
)
var (
logw = logger.Logw
LogDump = logger.LogDump
logDebug = logger.LogDebug
logInfo = logger.LogInfo
logWarning = logger.LogWarning
logError = logger.LogError
)
// 日志中间件
func Middleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 处理请求
c.Next()
var timingResults time.Duration
// 获取计时结果
timingResults, _ = timing.Get(c)
// 记录日志 IP METHOD URL USERAGENT PROTOCOL STATUS TIMING
logInfo("%s %s %s %s %d %s ", c.ClientIP(), c.Request.Method, c.Request.URL.Path, c.Request.UserAgent(), c.Writer.Status(), timingResults)
}
}

11
main.go
View file

@ -12,8 +12,10 @@ import (
"ghproxy/api"
"ghproxy/auth"
"ghproxy/config"
"ghproxy/loggin"
"ghproxy/proxy"
"ghproxy/rate"
"ghproxy/timing"
"github.com/WJQSERVER-STUDIO/go-utils/logger"
@ -124,7 +126,16 @@ func init() {
gin.LoggerWithWriter(io.Discard)
router = gin.New()
// 添加recovery中间件
router.Use(gin.Recovery())
// 添加log中间件
router.Use(loggin.Middleware())
// 添加计时中间件
router.Use(timing.Middleware())
//H2C默认值为true而后遵循cfg.Server.EnableH2C的设置
if cfg.Server.EnableH2C == "on" {
router.UseH2C = true

View file

@ -54,7 +54,6 @@ func initChunkedHTTPClient() {
func ChunkedProxyRequest(c *gin.Context, u string, cfg *config.Config, mode string, runMode string) {
method := c.Request.Method
logInfo("%s %s %s %s %s Chunked-Proxy-Request", c.ClientIP(), method, u, c.Request.Header.Get("User-Agent"), c.Request.Proto)
// 发送HEAD请求, 预获取Content-Length
headReq, err := http.NewRequest("HEAD", u, nil)

View file

@ -14,6 +14,7 @@ import (
func NoRouteHandler(cfg *config.Config, limiter *rate.RateLimiter, iplimiter *rate.IPRateLimiter, runMode string) gin.HandlerFunc {
return func(c *gin.Context) {
// 限制访问频率
if cfg.RateLimit.Enabled {

78
timing/timing.go Normal file
View file

@ -0,0 +1,78 @@
package timing
import (
"sync"
"time"
"github.com/gin-gonic/gin"
)
// 阶段计时结构(固定数组优化)
type timingData struct {
phases [8]struct { // 预分配8个阶段存储
name string
dur time.Duration
}
count int
start time.Time
}
// 对象池(内存重用优化)
var pool = sync.Pool{
New: func() interface{} {
return new(timingData)
},
}
// 中间件入口
func Middleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 从池中获取计时器
td := pool.Get().(*timingData)
td.start = time.Now()
td.count = 0
// 存储到上下文
c.Set("timing", td)
// 请求完成后回收对象
defer func() {
pool.Put(td)
}()
c.Next()
}
}
// 记录阶段耗时
func Record(c *gin.Context, name string) {
if val, exists := c.Get("timing"); exists {
td := val.(*timingData)
if td.count < len(td.phases) {
td.phases[td.count].name = name
td.phases[td.count].dur = time.Since(td.start) // 直接记录当前时间
td.count++
}
}
}
// 获取计时结果(日志输出用)
func Get(c *gin.Context) (total time.Duration, phases []struct {
Name string
Dur time.Duration
}) {
if val, exists := c.Get("timing"); exists {
td := val.(*timingData)
for i := 0; i < td.count; i++ {
phases = append(phases, struct {
Name string
Dur time.Duration
}{
Name: td.phases[i].name,
Dur: td.phases[i].dur,
})
}
total = time.Since(td.start)
}
return
}