package middleware import ( "fmt" "log" "time" "github.com/gin-gonic/gin" ) // LoggingMiddleware creates a custom logging middleware with detailed request information func LoggingMiddleware() gin.HandlerFunc { return gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string { // Custom log format with more details return fmt.Sprintf("[%s] %s %s %s %d %s \"%s\" %s \"%s\" %s\n", param.TimeStamp.Format("2006-01-02 15:04:05"), param.ClientIP, param.Method, param.Path, param.StatusCode, param.Latency, param.Request.UserAgent(), param.ErrorMessage, param.Request.Referer(), formatBodySize(param.BodySize), ) }) } // StructuredLoggingMiddleware creates a structured logging middleware for better log parsing func StructuredLoggingMiddleware() gin.HandlerFunc { return func(c *gin.Context) { // Start timer start := time.Now() path := c.Request.URL.Path raw := c.Request.URL.RawQuery // Process request c.Next() // Calculate latency latency := time.Since(start) // Get client IP clientIP := c.ClientIP() // Get method method := c.Request.Method // Get status code statusCode := c.Writer.Status() // Get body size bodySize := c.Writer.Size() // Build full path with query string if raw != "" { path = path + "?" + raw } // Log structured information log.Printf("REQUEST: method=%s path=%s status=%d latency=%v client_ip=%s body_size=%d user_agent=\"%s\"", method, path, statusCode, latency, clientIP, bodySize, c.Request.UserAgent(), ) // Log errors if any if len(c.Errors) > 0 { log.Printf("ERRORS: %v", c.Errors.String()) } } } // formatBodySize formats body size in human readable format func formatBodySize(size int) string { if size == 0 { return "0B" } const unit = 1024 if size < unit { return fmt.Sprintf("%dB", size) } div, exp := int64(unit), 0 for n := size / unit; n >= unit; n /= unit { div *= unit exp++ } return fmt.Sprintf("%.1f%cB", float64(size)/float64(div), "KMGTPE"[exp]) }