Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
nowissan opened this issue May 30, 2018 · 9 comments
Open
Labels

Comments

@nowissan
Copy link

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)
@syssam
Copy link
Contributor

syssam commented May 30, 2018

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

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

@chainhelen
Copy link
Contributor

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

@nowissan
Copy link
Author

nowissan commented May 31, 2018

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.
--- ...

@chainhelen
Copy link
Contributor

chainhelen commented May 31, 2018

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).

@nowissan
Copy link
Author

nowissan commented May 31, 2018

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...
--- ...

@syssam
Copy link
Contributor

syssam commented May 31, 2018

@chainhelen All Right

@syssam
Copy link
Contributor

syssam commented May 31, 2018

@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

@nowissan
Copy link
Author

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

@syssam
Copy link
Contributor

syssam commented May 31, 2018

replace gin log, reference
https://github.com/szuecs/gin-glog/blob/master/ginglog.go

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants