feat(logger): ability to skip logs based on user-defined logic (#3593)

* log skipper

* do not call time.now() if logging should be skipped

* do not ignore skip func delay in latency calculation

* write docs

* write test
This commit is contained in:
Ghobad 2024-02-02 05:22:26 +03:30 committed by GitHub
parent a64286a776
commit c6ae2e6966
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 93 additions and 26 deletions

View File

@ -508,6 +508,44 @@ Sample Output
::1 - [Fri, 07 Dec 2018 17:04:38 JST] "GET /ping HTTP/1.1 200 122.767µs "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36" "
```
### Skip logging
```go
func main() {
router := gin.New()
// skip logging for desired paths by setting SkipPaths in LoggerConfig
loggerConfig := gin.LoggerConfig{SkipPaths: []string{"/metrics"}}
// skip logging based on your logic by setting Skip func in LoggerConfig
loggerConfig.Skip = func(c *gin.Context) bool {
// as an example skip non server side errors
return c.Writer.Status() < http.StatusInternalServerError
}
engine.Use(gin.LoggerWithConfig(loggerConfig))
router.Use(gin.Recovery())
// skipped
router.GET("/metrics", func(c *gin.Context) {
c.Status(http.StatusNotImplemented)
})
// skipped
router.GET("/ping", func(c *gin.Context) {
c.String(http.StatusOK, "pong")
})
// not skipped
router.GET("/data", func(c *gin.Context) {
c.Status(http.StatusNotImplemented)
})
router.Run(":8080")
}
```
### Controlling Log output coloring
By default, logs output on console should be colorized depending on the detected TTY.

View File

@ -47,8 +47,15 @@ type LoggerConfig struct {
// SkipPaths is an url path array which logs are not written.
// Optional.
SkipPaths []string
// Skip is a Skipper that indicates which logs should not be written.
// Optional.
Skip Skipper
}
// Skipper is a function to skip logs based on provided Context
type Skipper func(c *Context) bool
// LogFormatter gives the signature of the formatter function passed to LoggerWithFormatter
type LogFormatter func(params LogFormatterParams) string
@ -241,32 +248,34 @@ func LoggerWithConfig(conf LoggerConfig) HandlerFunc {
// Process request
c.Next()
// Log only when path is not being skipped
if _, ok := skip[path]; !ok {
param := LogFormatterParams{
Request: c.Request,
isTerm: isTerm,
Keys: c.Keys,
}
// Stop timer
param.TimeStamp = time.Now()
param.Latency = param.TimeStamp.Sub(start)
param.ClientIP = c.ClientIP()
param.Method = c.Request.Method
param.StatusCode = c.Writer.Status()
param.ErrorMessage = c.Errors.ByType(ErrorTypePrivate).String()
param.BodySize = c.Writer.Size()
if raw != "" {
path = path + "?" + raw
}
param.Path = path
fmt.Fprint(out, formatter(param))
// Log only when it is not being skipped
if _, ok := skip[path]; ok || (conf.Skip != nil && conf.Skip(c)) {
return
}
param := LogFormatterParams{
Request: c.Request,
isTerm: isTerm,
Keys: c.Keys,
}
// Stop timer
param.TimeStamp = time.Now()
param.Latency = param.TimeStamp.Sub(start)
param.ClientIP = c.ClientIP()
param.Method = c.Request.Method
param.StatusCode = c.Writer.Status()
param.ErrorMessage = c.Errors.ByType(ErrorTypePrivate).String()
param.BodySize = c.Writer.Size()
if raw != "" {
path = path + "?" + raw
}
param.Path = path
fmt.Fprint(out, formatter(param))
}
}

View File

@ -415,6 +415,26 @@ func TestLoggerWithConfigSkippingPaths(t *testing.T) {
assert.Contains(t, buffer.String(), "")
}
func TestLoggerWithConfigSkipper(t *testing.T) {
buffer := new(strings.Builder)
router := New()
router.Use(LoggerWithConfig(LoggerConfig{
Output: buffer,
Skip: func(c *Context) bool {
return c.Writer.Status() == http.StatusNoContent
},
}))
router.GET("/logged", func(c *Context) { c.Status(http.StatusOK) })
router.GET("/skipped", func(c *Context) { c.Status(http.StatusNoContent) })
PerformRequest(router, "GET", "/logged")
assert.Contains(t, buffer.String(), "200")
buffer.Reset()
PerformRequest(router, "GET", "/skipped")
assert.Contains(t, buffer.String(), "")
}
func TestDisableConsoleColor(t *testing.T) {
New()
assert.Equal(t, autoColor, consoleColorMode)