feat():learning后台管理项目初始化
This commit is contained in:
141
internal/api/middlewares/api_log_middleware.go
Normal file
141
internal/api/middlewares/api_log_middleware.go
Normal file
@@ -0,0 +1,141 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
"goalfymax-admin/internal/models"
|
||||
"goalfymax-admin/pkg/utils"
|
||||
)
|
||||
|
||||
// API日志中间件 - 记录所有接口的调用信息
|
||||
func APILogMiddleware(logger *utils.Logger) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// 排除健康检查接口
|
||||
if c.Request.URL.Path == "/health" {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
// 记录开始时间
|
||||
startTime := time.Now()
|
||||
|
||||
// 读取请求体(需要保存以便后续使用)
|
||||
var requestBody []byte
|
||||
if c.Request.Body != nil {
|
||||
requestBody, _ = io.ReadAll(c.Request.Body)
|
||||
c.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody))
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
userID := 0
|
||||
userEmail := "unknown"
|
||||
if userInfo, exists := c.Get("user"); exists {
|
||||
if user, ok := userInfo.(*models.UserInfo); ok && user != nil {
|
||||
if user.Email != "" {
|
||||
userEmail = user.Email
|
||||
} else if user.PreferredUsername != "" {
|
||||
userEmail = user.PreferredUsername + "@goalfy.com"
|
||||
}
|
||||
// 尝试获取用户ID
|
||||
if id, exists := c.Get("user_id"); exists {
|
||||
switch v := id.(type) {
|
||||
case int:
|
||||
userID = v
|
||||
case uint:
|
||||
userID = int(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建响应写入器包装器以捕获响应
|
||||
responseWriter := &responseBodyWriter{
|
||||
ResponseWriter: c.Writer,
|
||||
body: &bytes.Buffer{},
|
||||
}
|
||||
c.Writer = responseWriter
|
||||
|
||||
// 处理请求
|
||||
c.Next()
|
||||
|
||||
// 计算耗时
|
||||
duration := time.Since(startTime)
|
||||
|
||||
// 获取响应信息
|
||||
responseCode := c.Writer.Status()
|
||||
responseBody := responseWriter.body.String()
|
||||
|
||||
// 限制响应体大小(避免打印过大的响应)
|
||||
if len(responseBody) > 1000 {
|
||||
responseBody = responseBody[:1000] + "...(truncated)"
|
||||
}
|
||||
|
||||
// 限制请求体大小
|
||||
requestBodyStr := string(requestBody)
|
||||
if len(requestBodyStr) > 1000 {
|
||||
requestBodyStr = requestBodyStr[:1000] + "...(truncated)"
|
||||
}
|
||||
|
||||
// 获取请求信息
|
||||
method := c.Request.Method
|
||||
path := c.Request.URL.Path
|
||||
|
||||
// 提取模块名称
|
||||
module := extractModule(path)
|
||||
|
||||
// 打印日志
|
||||
logger.Info("📝 [API日志] 接口调用记录",
|
||||
zap.String("method", method),
|
||||
zap.String("path", path),
|
||||
zap.String("full_path", c.Request.URL.String()),
|
||||
zap.String("module", module),
|
||||
zap.Int("user_id", userID),
|
||||
zap.String("user_email", userEmail),
|
||||
zap.String("ip_address", c.ClientIP()),
|
||||
zap.String("user_agent", c.Request.UserAgent()),
|
||||
zap.String("request_body", requestBodyStr),
|
||||
zap.Int("response_code", responseCode),
|
||||
zap.String("response_body", responseBody),
|
||||
zap.Duration("duration", duration),
|
||||
zap.Int64("duration_ms", duration.Milliseconds()),
|
||||
zap.String("status", getStatus(responseCode)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// responseBodyWriter 用于捕获响应体
|
||||
type responseBodyWriter struct {
|
||||
gin.ResponseWriter
|
||||
body *bytes.Buffer
|
||||
}
|
||||
|
||||
func (w *responseBodyWriter) Write(b []byte) (int, error) {
|
||||
w.body.Write(b)
|
||||
return w.ResponseWriter.Write(b)
|
||||
}
|
||||
|
||||
// extractModule 从路径提取模块名称
|
||||
func extractModule(path string) string {
|
||||
parts := strings.Split(strings.Trim(path, "/"), "/")
|
||||
if len(parts) >= 3 {
|
||||
return parts[2] // /api/admin/{module}
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// getStatus 根据响应码获取状态
|
||||
func getStatus(code int) string {
|
||||
if code >= 200 && code < 300 {
|
||||
return "success"
|
||||
} else if code >= 400 && code < 500 {
|
||||
return "client_error"
|
||||
} else if code >= 500 {
|
||||
return "server_error"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
47
internal/api/middlewares/logging.go
Normal file
47
internal/api/middlewares/logging.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
"goalfymax-admin/pkg/utils"
|
||||
)
|
||||
|
||||
// LoggingMiddleware 日志中间件
|
||||
func LoggingMiddleware(logger *utils.Logger) gin.HandlerFunc {
|
||||
return gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
|
||||
// 记录请求日志
|
||||
logger.Info("HTTP请求",
|
||||
zap.String("method", param.Method),
|
||||
zap.String("path", param.Path),
|
||||
zap.Int("status", param.StatusCode),
|
||||
zap.Duration("latency", param.Latency),
|
||||
zap.String("client_ip", param.ClientIP),
|
||||
zap.String("user_agent", param.Request.UserAgent()),
|
||||
)
|
||||
return ""
|
||||
})
|
||||
}
|
||||
|
||||
// RequestLogMiddleware 请求日志中间件
|
||||
func RequestLogMiddleware(logger *utils.Logger) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
start := time.Now()
|
||||
|
||||
// 处理请求
|
||||
c.Next()
|
||||
|
||||
// 记录请求信息
|
||||
latency := time.Since(start)
|
||||
|
||||
logger.Info("请求处理完成",
|
||||
zap.String("method", c.Request.Method),
|
||||
zap.String("path", c.Request.URL.Path),
|
||||
zap.Int("status", c.Writer.Status()),
|
||||
zap.Duration("latency", latency),
|
||||
zap.String("client_ip", c.ClientIP()),
|
||||
zap.String("user_agent", c.Request.UserAgent()),
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user