- 新增用户与上传错误码文件及 Recovery 中间件 - 修复 router.go 导入与中间件链,注册用户路由并补 handler 错误码导入 - 补充用户状态常量与 UserGetByWechatOpenID 查询,修订刷新令牌 dto - 移除 upload 包 OTel 调用,新增 FileUploadCos 上传封装 - 实现 UserService 微信登录/刷新令牌/我的信息/改资料/上传头像 - 裁剪 main.go 配置段并移除 OTel 桥接,补启动与优雅退出 - 新增 configs 示例配置、global 配置结构及 go.mod 依赖
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...)
|
||
}
|
||
}
|
||
}
|