78 lines
1.9 KiB
Go
78 lines
1.9 KiB
Go
package middleware
|
||
|
||
import (
|
||
"log/slog"
|
||
"net/http"
|
||
"net/url"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// sanitizeQuery 对 query 中的敏感参数值脱敏,避免日志泄露 token/code/密钥等。
|
||
func sanitizeQuery(query string) string {
|
||
if query == "" {
|
||
return ""
|
||
}
|
||
values, err := url.ParseQuery(query)
|
||
if err != nil {
|
||
return "***"
|
||
}
|
||
sensitive := map[string]bool{
|
||
"token": true, "code": true, "secret": true, "password": true,
|
||
"access_token": true, "refresh_token": true, "key": true,
|
||
}
|
||
for k := range values {
|
||
if sensitive[strings.ToLower(k)] {
|
||
values.Set(k, "***")
|
||
}
|
||
}
|
||
return values.Encode()
|
||
}
|
||
|
||
// maxUserAgentLen user_agent 日志字段最大长度:超出截断,避免异常长 UA 撑大日志体积。
|
||
const maxUserAgentLen = 256
|
||
|
||
// truncateUserAgent 截断超长 User-Agent(仅用于日志展示)。
|
||
func truncateUserAgent(ua string) string {
|
||
if len(ua) <= maxUserAgentLen {
|
||
return ua
|
||
}
|
||
return ua[:maxUserAgentLen] + "...(truncated)"
|
||
}
|
||
|
||
func GinSlogMiddleware() gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
|
||
start := time.Now()
|
||
path := c.Request.URL.Path
|
||
query := sanitizeQuery(c.Request.URL.RawQuery)
|
||
|
||
// 处理请求
|
||
c.Next()
|
||
|
||
// 请求结束后按状态码分级打日志:5xx=Error、4xx(除 401)=Warn、其余=Info。
|
||
ctx := c.Request.Context()
|
||
status := c.Writer.Status()
|
||
attrs := []any{
|
||
"request_id", GetRequestID(ctx),
|
||
"method", c.Request.Method,
|
||
"path", path,
|
||
"query", query,
|
||
"status", status,
|
||
"ip", c.ClientIP(),
|
||
"latency", time.Since(start).String(),
|
||
"user_agent", truncateUserAgent(c.Request.UserAgent()),
|
||
}
|
||
switch {
|
||
case status >= http.StatusInternalServerError:
|
||
slog.ErrorContext(ctx, "GIN_REQUEST", attrs...)
|
||
case status >= http.StatusBadRequest && status != http.StatusUnauthorized:
|
||
slog.WarnContext(ctx, "GIN_REQUEST", attrs...)
|
||
default:
|
||
slog.InfoContext(ctx, "GIN_REQUEST", attrs...)
|
||
}
|
||
}
|
||
}
|