Gin: Question: How to write request log and error log in a separate manner.

Created on 30 May 2018  路  9Comments  路  Source: gin-gonic/gin

I could write everything into a file with #805 post.
Related to this, how could it be possible to write error into a separate log?

--
I assume to use gin.DefaultErrorWriter, but it seems that log.SetOuput is only possible with a single file.

Current output (everything into a single file)

[GIN] 2018/05/30 - 19:21:17 | 404 |     114.656碌s |             ::1 |  GET     /comment/view/99999
Error #01: th size of input parameter is not 40
[GIN] 2018/05/30 - 19:21:20 | 200 |     1.82468ms |             ::1 |  GET     /comment/view/00001

Current code

logfile, err := os.OpenFile(c.GinLogPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
    log.Fatalln("Failed to create request log file:", err)                                 
}

errlogfile, err := os.OpenFile(c.GinErrorLogPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
    log.Fatalln("Failed to create request log file:", err)
}

// set request logging
gin.DefaultWriter = io.MultiWriter(logfile)
gin.DefaultErrorWriter = io.MultiWriter(errlogfile)
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
log.SetOutput(gin.DefaultWriter)
question

Most helpful comment

En. Maybe You have a misconception about issues 805

1. The request log will be fomartted and logged by gin.DefaultWriter or gin.DefaultErrorWriter (the logger.go of gin , not the the log package of go ).So you needn't to care about log(removing it).

2. If just want everything into a single file, it is unnecessary to use io.MultiWriter

Based on the above two points

// set request logging
gin.DefaultWriter = logfile
gin.DefaultErrorWriter = errlogfile

is enough

All 9 comments

logfile, _ := os.Create("request.log")
gin.DefaultWriter = io.MultiWriter(logfile)

errlogfile, _ := os.Create("error.log")
gin.DefaultErrorWriter = io.MultiWriter(errlogfile)

En. Maybe You have a misconception about issues 805

1. The request log will be fomartted and logged by gin.DefaultWriter or gin.DefaultErrorWriter (the logger.go of gin , not the the log package of go ).So you needn't to care about log(removing it).

2. If just want everything into a single file, it is unnecessary to use io.MultiWriter

Based on the above two points

// set request logging
gin.DefaultWriter = logfile
gin.DefaultErrorWriter = errlogfile

is enough

Hi, Thanks for your reply!
I removed log.Setflags and log.Setoutput.
However, the error log is still empty.

Just log.Println(err) doesn't make records in the error log.
This might be very basic, but could you give me any advice about howto write to error log (gin.DefaultErrorWriter)?

--
I tried c.AbortWithError(http.StatusNotFound, err) and c.Error(err) in my handler function.
still got nothing in error log (only gin.DefaultWriter log).

- project<dir>
--- main.go                  <- gin.DefaultWriter, gin.DefaultErrorWriter setting is here.
--- handlers<dir>
----- view_handler.go        <- c.AbortWithError is here.
--- ...

DefaultErrorWriter

// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one.
func Recovery() HandlerFunc {
    return RecoveryWithWriter(DefaultErrorWriter)
}

Because gin.DefaultErrorWriter are used to do this, this mean only log panic
c.Error(err) you reference does not belong to this situation, and so only gin.DefaultWriter log.

--

Actually, you can use gin.DefaultErrorWriter and add some log what you want into error log.

package main

import (
        "github.com/gin-gonic/gin"
        "os"
)
func main() {
        r := gin.Default()
        errlogfile, _ := os.Create("error.log")
        gin.DefaultErrorWriter = errlogfile
        r.GET("t", func(c *gin.Context) {
                errLogger := gin.DefaultErrorWriter
                errLogger.Write([]byte("[DIY ERROR] HELLO ERROR!\n"))
                c.JSON(200, gin.H{"hello": "world"})
        })
        r.Run(":8080")
}

But it depend on you(developer).

Thanks.
So, recovery from panic is the case to use DefaultErrorWriter.
(A) If so, appropriate approach is to define logger for error in handler function and use it.
I'll take this approach.

(B) I suppose another approach could be to use fmt.Fprinln(gin.DefaultErrorWriter, "some error message") directly, and confirmed this would write error to error log.

--
(C) I confirmed I could write with your suggestion(I used gin.DefaultErrorWriter.Write(...) directly in handler) successfuly.

In summary (A), (B), or (C) could be solution.

@chainhelen thanks again!!

--
I am not sure if this would help others but I'll write the detail of my approach to write separate logs for handler functions.
detail of (A):
(a) for default request log: set gin.DefaultWriter (in main())
(b) for other log (which includes errors, and is separate from (a)): as follows

in handlers.go
var (
    Debug   *log.Logger
    Info    *log.Logger
    Warning *log.Logger
    Error   *log.Logger
)
...
func init() {
  ...
    // set package-internal logger
    Info = log.New(logfile, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
    Warning = log.New(logfile, "WARN: ", log.Ldate|log.Ltime|log.Lshortfile)
    Error = log.New(logfile, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)
}
in each xxx_handler.go (functions called from main route.GET(xxxx))
if someobjects, err := somedbfunction(); err == nil {
    c.JSON ...
} else {
    Error.Println(err)
    c.AbortWithStatus(http.StatusNotFound)  
}

the structure of directory is 
- project<dir>
--- main.go                  <- gin.DefaultWriter, gin.DefaultErrorWriter setting is here.
--- handlers<dir>
----- handlers.go            <- define package internal logger (var Error or Info or Warn ... )
----- view_handler.go        <- use logger here like Error.Println, Info.Println, Warn.Println...
--- ...

@chainhelen All Right

@nowissan
Gin does not provide log level type, you can add other golang package on your project simply.
https://github.com/avelino/awesome-go#logging

@syssam
thanks! this is helpful.
I thought about using zap or zerolog from performance reason.
they could be options for structured.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

olegsobchuk picture olegsobchuk  路  3Comments

sofish picture sofish  路  3Comments

nxvl picture nxvl  路  3Comments

mastrolinux picture mastrolinux  路  3Comments

boneq picture boneq  路  3Comments