feat: 添加请求追踪中间件并支持查询过期订阅
Build docker and publish / build (20.15.1) (push) Successful in 5m10s

添加请求追踪中间件以记录请求和响应内容
在用户订阅查询中新增includeExpired参数支持查询历史记录
完善配置系统以支持float64类型默认值解析
This commit is contained in:
2026-01-06 20:54:15 -08:00
parent 55c778b65b
commit ef64a876cd
8 changed files with 105 additions and 18 deletions
+46 -2
View File
@@ -1,8 +1,10 @@
package middleware
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"strings"
@@ -18,6 +20,17 @@ import (
"github.com/perfect-panel/server/pkg/trace"
)
// bodyLogWriter is a wrapper for gin.ResponseWriter to capture response body
type bodyLogWriter struct {
gin.ResponseWriter
body *bytes.Buffer
}
func (w bodyLogWriter) Write(b []byte) (int, error) {
w.body.Write(b)
return w.ResponseWriter.Write(b)
}
// statusByWriter returns a span status code and message for an HTTP status code
// value returned by a server. Status codes in the 400-499 range are not
// returned as errors.
@@ -59,6 +72,13 @@ func TraceMiddleware(_ *svc.ServiceContext) func(ctx *gin.Context) {
ctx := c.Request.Context()
tracer := trace.TracerFromContext(ctx)
// Capture Request Body
var reqBody []byte
if c.Request.Body != nil {
reqBody, _ = io.ReadAll(c.Request.Body)
c.Request.Body = io.NopCloser(bytes.NewBuffer(reqBody)) // Restore body
}
spanName := c.FullPath()
method := c.Request.Method
@@ -78,13 +98,39 @@ func TraceMiddleware(_ *svc.ServiceContext) func(ctx *gin.Context) {
attribute.String("http.request_id", requestId),
semconv.HTTPRouteKey.String(c.FullPath()),
)
// Record Request Body (limit to 1MB)
if len(reqBody) > 0 {
limit := 1048576
if len(reqBody) > limit {
span.SetAttributes(attribute.String("http.request.body", string(reqBody[:limit])+"...(truncated)"))
} else {
span.SetAttributes(attribute.String("http.request.body", string(reqBody)))
}
}
// context with request host
ctx = context.WithValue(ctx, constant.CtxKeyRequestHost, c.Request.Host)
// restructure context
c.Request = c.Request.WithContext(ctx)
// Wrap ResponseWriter to capture Response Body
blw := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
c.Writer = blw
c.Next()
// Record Response Body (limit to 1MB)
respBody := blw.body.String()
if len(respBody) > 0 {
limit := 1048576
if len(respBody) > limit {
span.SetAttributes(attribute.String("http.response.body", respBody[:limit]+"...(truncated)"))
} else {
span.SetAttributes(attribute.String("http.response.body", respBody))
}
}
// handle response related attributes
status := c.Writer.Status()
span.SetStatus(statusByWriter(status))
@@ -97,7 +143,5 @@ func TraceMiddleware(_ *svc.ServiceContext) func(ctx *gin.Context) {
span.RecordError(err.Err)
}
}
span.SetAttributes(semconv.HTTPResponseBodySizeKey.Int(c.Writer.Size()))
}
}