package middleware import ( "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" ) // AccessLogMiddleware 访问日志中间件 (用于流量统计) func AccessLogMiddleware() gin.HandlerFunc { return func(c *gin.Context) { // 添加 panic recover 保护整个中间件 defer func() { if r := recover(); r != nil { log.Printf("Panic in AccessLogMiddleware: %v", r) } }() start := time.Now() c.Next() // 过滤静态资源和API调用 // 这里只记录主要页面访问,或者我们可以记录所有非静态资源 // 简化起见,记录所有请求,分析时再过滤 // 获取IP ip := c.ClientIP() // 获取归属地 (需要先初始化ip2region) // 使用 recover 保护,确保即使 GetRegion 失败也能继续记录日志 var region string func() { defer func() { if r := recover(); r != nil { log.Printf("Panic in GetRegion for IP %s (access log): %v", ip, r) region = "Unknown" } }() region = utils.GetRegion(ip) }() // 如果 region 为空,设置为 Unknown if region == "" { region = "Unknown" } // 记录调试信息 log.Printf("Creating access log: IP=%s, Region=%s, Path=%s, Method=%s", ip, region, c.Request.URL.Path, c.Request.Method) logEntry := &models.AccessLog{ IP: ip, UserAgent: c.Request.UserAgent(), Path: c.Request.URL.Path, Method: c.Request.Method, StatusCode: c.Writer.Status(), ResponseTime: time.Since(start).Milliseconds(), Region: region, } // 异步入库,添加错误处理和 panic 保护 go func() { defer func() { if r := recover(); r != nil { log.Printf("Panic in CreateAccessLog goroutine: %v", r) } }() if err := repositories.CreateAccessLog(logEntry); err != nil { log.Printf("Error creating access log for IP=%s, Region=%s, Path=%s: %v", ip, region, c.Request.URL.Path, err) } else { log.Printf("Successfully created access log: IP=%s, Region=%s, Path=%s", ip, region, c.Request.URL.Path) } }() } }