for debugging my program, I need to logging request body so write the below middleware
but it's wasn't called by gin
gin version f931d1ea80ae95a6fc739213cdd9399bd2967fb6
type MyReadCloser struct {
rc io.ReadCloser
w io.Writer
}
func (rc *MyReadCloser) Read(p []byte) (n int, err error) {
n, err = rc.rc.Read(p)
log.Println("run here", n, err)
if n > 0 {
if n, err := rc.w.Write(p[:n]); err != nil {
return n, err
}
}
return n, err
}
func (rc *MyReadCloser) Close() error {
return rc.rc.Close()
}
func DebugLogger() gin.HandlerFunc {
return func(c *gin.Context) {
log.Println(c.Request.RequestURI)
if c.Request.Method == http.MethodPost {
var buf bytes.Buffer
newBody := &MyReadCloser{c.Request.Body, &buf}
c.Request.Body = newBody
c.Next()
log.Println(buf.String())
} else {
c.Next()
}
}
}
r := gin.New()
if cfg.Debug {
r.Use(middleware.DebugLogger())
}
Your MyReadCloser is not called because Read(b []byte) (n int, err error) is called before you set &MyReadCloser on c.Request.Body.
As you know, log.Println(c.Request.RequestURI) on DebugLogger() is working as you want.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] Environment variable PORT is undefined. Using port:8080 by default
[GIN-debug] Listening and serving HTTP on :8080
/test
@tfzxyinhao I prefer using gin model binding, but if you just want to logging the request body, you can create RequestLogger middleware as follows:
package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.New()
r.Use(RequestLogger())
r.POST("/postpath", func(c *gin.Context) {
//...
})
r.Run()
}
func RequestLogger() gin.HandlerFunc {
return func(c *gin.Context) {
buf, _ := ioutil.ReadAll(c.Request.Body)
rdr1 := ioutil.NopCloser(bytes.NewBuffer(buf))
rdr2 := ioutil.NopCloser(bytes.NewBuffer(buf)) //We have to create a new Buffer, because rdr1 will be read.
fmt.Println(readBody(rdr1)) // Print request body
c.Request.Body = rdr2
c.Next()
}
}
func readBody(reader io.Reader) string {
buf := new(bytes.Buffer)
buf.ReadFrom(reader)
s := buf.String()
return s
}
thanks @suzuken @easonlin404
i think replace c.Request.Body at first is the perfect way
Simple LoggingMiddleware
func RequestLoggerMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
var buf bytes.Buffer
tee := io.TeeReader(c.Request.Body, &buf)
body, _ := ioutil.ReadAll(tee)
c.Request.Body = ioutil.NopCloser(&buf)
log.Debug(string(body))
log.Debug(c.Request.Header)
c.Next()
}
}
@BogdanRuzh do you know how to implement that using LoggerWithFormatter ? :eyes: e.g. https://github.com/gin-gonic/gin#custom-log-format
Most helpful comment
@tfzxyinhao I prefer using gin model binding, but if you just want to logging the request body, you can create
RequestLoggermiddleware as follows: