package api import ( "bytes" "encoding/json" "io" "log" "time" "github.com/gin-gonic/gin" ) // VerboseLoggingMiddleware logs all requests and responses when verbose mode is enabled func VerboseLoggingMiddleware(verbose bool) gin.HandlerFunc { return func(c *gin.Context) { if !verbose { c.Next() return } // Log request var requestBody []byte if c.Request.Body != nil { requestBody, _ = io.ReadAll(c.Request.Body) // Restore the body for the handler c.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody)) } log.Printf("\n========== INCOMING REQUEST ==========") log.Printf("Method: %s", c.Request.Method) log.Printf("Path: %s", c.Request.URL.Path) log.Printf("Headers: %v", c.Request.Header) if len(requestBody) > 0 { var prettyJSON bytes.Buffer if err := json.Indent(&prettyJSON, requestBody, "", " "); err == nil { log.Printf("Body:\n%s", prettyJSON.String()) } else { log.Printf("Body: %s", string(requestBody)) } } log.Printf("======================================\n") // Create a custom response writer to capture the response blw := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer} c.Writer = blw start := time.Now() c.Next() duration := time.Since(start) // Log response log.Printf("\n========== OUTGOING RESPONSE ==========") log.Printf("Status: %d", c.Writer.Status()) log.Printf("Duration: %v", duration) log.Printf("Headers: %v", c.Writer.Header()) if blw.body.Len() > 0 { var prettyJSON bytes.Buffer if err := json.Indent(&prettyJSON, blw.body.Bytes(), "", " "); err == nil { log.Printf("Body:\n%s", prettyJSON.String()) } else { log.Printf("Body: %s", blw.body.String()) } } log.Printf("======================================\n") } } // bodyLogWriter is a custom response writer that captures the response body type bodyLogWriter struct { gin.ResponseWriter body *bytes.Buffer } func (w bodyLogWriter) Write(b []byte) (int, error) { w.body.Write(b) return w.ResponseWriter.Write(b) }