54 lines
1.3 KiB
Go
54 lines
1.3 KiB
Go
package middleware
|
||
|
||
import (
|
||
"time"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
"log/slog"
|
||
)
|
||
|
||
// GinLogger 用结构化日志(slog,由 main 设为 JSON handler)记录每个请求,
|
||
// 替代 gin 默认的 text logger,便于生产环境集中采集与检索。
|
||
func GinLogger() gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
start := time.Now()
|
||
path := c.Request.URL.Path
|
||
raw := c.Request.URL.RawQuery
|
||
|
||
c.Next()
|
||
|
||
// 跳过健康检查等高频噪声路径
|
||
if path == "/api/health" || path == "/api/v1/health" {
|
||
return
|
||
}
|
||
|
||
latency := time.Since(start)
|
||
status := c.Writer.Status()
|
||
clientIP := c.ClientIP()
|
||
method := c.Request.Method
|
||
if raw != "" {
|
||
path = path + "?" + raw
|
||
}
|
||
|
||
attrs := []slog.Attr{
|
||
slog.String("method", method),
|
||
slog.String("path", path),
|
||
slog.Int("status", status),
|
||
slog.String("ip", clientIP),
|
||
slog.Duration("latency", latency),
|
||
}
|
||
if len(c.Errors) > 0 {
|
||
attrs = append(attrs, slog.String("error", c.Errors.ByType(gin.ErrorTypePrivate).String()))
|
||
}
|
||
|
||
switch {
|
||
case status >= 500:
|
||
slog.LogAttrs(c.Request.Context(), slog.LevelError, "request", attrs...)
|
||
case status >= 400:
|
||
slog.LogAttrs(c.Request.Context(), slog.LevelWarn, "request", attrs...)
|
||
default:
|
||
slog.LogAttrs(c.Request.Context(), slog.LevelInfo, "request", attrs...)
|
||
}
|
||
}
|
||
}
|