package middleware import ( "bytes" "io/ioutil" "log" "time" "github.com/gin-gonic/gin" "github.com/niangaodev/art-code/models" "github.com/niangaodev/art-code/repositories" "github.com/niangaodev/art-code/utils" ) // OperationLogMiddleware 操作日志中间件 func OperationLogMiddleware() gin.HandlerFunc { return func(c *gin.Context) { // 开始时间 startTime := time.Now() // 读取请求参数 var requestBody []byte if c.Request.Method != "GET" { body, err := ioutil.ReadAll(c.Request.Body) if err != nil { log.Printf("Error reading request body: %v", err) } else { requestBody = body // 重置请求体,以便后续处理 c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(requestBody)) } } // 执行请求 c.Next() // 结束时间 endTime := time.Now() // 计算请求持续时间(毫秒) duration := int(endTime.Sub(startTime).Milliseconds()) // 获取用户信息 userID, exists := c.Get("userID") if !exists { return } username, _ := c.Get("username") // 获取IP归属地 ip := c.ClientIP() var region string // 使用 recover 保护 GetRegion 调用 func() { defer func() { if r := recover(); r != nil { log.Printf("Panic in GetRegion for IP %s (operation log): %v", ip, r) region = "Unknown" } }() region = utils.GetRegion(ip) }() // 确保 region 不为空,如果为空则设置为 "Unknown" if region == "" { region = "Unknown" } // 记录调试信息 log.Printf("Creating operation log: UserID=%d, IP=%s, Region=%s, Path=%s", userID.(uint), ip, region, c.Request.URL.Path) // 构建操作日志 path := c.Request.URL.Path method := c.Request.Method operationLog := &models.OperationLog{ UserID: userID.(uint), Username: username.(string), IP: ip, Region: region, Path: path, Method: method, Action: utils.GetOperationAction(path, method), Params: string(requestBody), Status: c.Writer.Status(), Duration: duration, } // 异步记录日志,避免影响响应 go func() { defer func() { if r := recover(); r != nil { log.Printf("Panic in CreateOperationLog goroutine: %v", r) } }() if err := repositories.CreateOperationLog(operationLog); err != nil { log.Printf("Error creating operation log for UserID=%d, IP=%s, Region=%s: %v", userID.(uint), ip, region, err) } else { log.Printf("Successfully created operation log: UserID=%d, IP=%s, Region=%s", userID.(uint), ip, region) } }() } }