How to customise the logger format of Gin api app ?
I tried to do it with the logrus package, but my problem is that : when I intentionally made 404 or 400 error, there's no error message printing in the console.
Also I want the logger to display response body in the logger.
func requestLoggingMiddleware(logger *logrus.Logger) gin.HandlerFunc {
return func(c *gin.Context) {
// Read the request body
bodyBytes, _ := ioutil.ReadAll(c.Request.Body)
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
bodyString := string(bodyBytes)
// Process request
c.Next()
// Log request details
// Include Request error message
logger.WithFields(logrus.Fields{
"status": c.Writer.Status(),
"method": c.Request.Method,
"path": c.Request.URL.Path,
"query_params": c.Request.URL.Query(),
"req_body": bodyString,
// "res_error_1": c.Errors.ByType(gin.ErrorTypePrivate).String(),
"res_error_2": c.Errors.String(),
}).Info("Request details")
}
}
func main() {
logrus.Info("Starting the application...")
// 1. Create a new instance of the application.
app := gin.New()
// OPTION 1
logger := logrus.New()
logger.SetLevel(logrus.InfoLevel)
app.Use(gin.LoggerWithWriter(logger.Writer()))
app.Use(requestLoggingMiddleware(logger))
...
}
This is what displayed on the console :
INFO[0015] Request details body="{\"d\":\"D\"}" error= method=POST path=/ping query_params="map[]" status=404
as suggested by @PRATHEESH PC, I put together a small example based on your needs. The code is divided up into three parts: the middleware, the HTTP handler, and the main package. Let's start with the HTTP handler.
handlers/handlers.gofileThe only thing to mention here is the usage of the
ShouldBindBodyWithmethod that gives you the possibility to read the request payload multiple times. In fact, the first time it has been called (within the middleware), it copies the request body into the context. The subsequent calls will read the body from there (e.g. the call in the HTTP handler).middlewares/middlewares.gofileHere, we did three main things.
First, we defined the
ginBodyLoggerstruct that embeds thegin.ResponseWriterstruct and adds abytes.Bufferto record the response payload we care about.Then, we provided a custom implementation for the method
Writethat will be called when writing to the response stream. Before writing to it, we'll save the information in the buffer that belongs to theginBodyLoggerstruct.Finally, we trace this information through the
loggerwe provided to the middleware function.main.gofileThe
mainpackage is in charge of initializing everything we need in our program. It involves two functions:initandmain.Within the
initfunction, we initialize the logger.Within the
mainfunction, we initialize thegin.Engineinstance, instrument it, and run.If you run the code, you should have the logs as desired. If that's not the case, just let me know and I'll come back to you, thanks!