mirror of https://github.com/gin-gonic/gin.git
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:
parent
a64286a776
commit
c6ae2e6966
38
docs/doc.md
38
docs/doc.md
|
@ -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" "
|
::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
|
### Controlling Log output coloring
|
||||||
|
|
||||||
By default, logs output on console should be colorized depending on the detected TTY.
|
By default, logs output on console should be colorized depending on the detected TTY.
|
||||||
|
|
61
logger.go
61
logger.go
|
@ -47,8 +47,15 @@ type LoggerConfig struct {
|
||||||
// SkipPaths is an url path array which logs are not written.
|
// SkipPaths is an url path array which logs are not written.
|
||||||
// Optional.
|
// Optional.
|
||||||
SkipPaths []string
|
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
|
// LogFormatter gives the signature of the formatter function passed to LoggerWithFormatter
|
||||||
type LogFormatter func(params LogFormatterParams) string
|
type LogFormatter func(params LogFormatterParams) string
|
||||||
|
|
||||||
|
@ -241,32 +248,34 @@ func LoggerWithConfig(conf LoggerConfig) HandlerFunc {
|
||||||
// Process request
|
// Process request
|
||||||
c.Next()
|
c.Next()
|
||||||
|
|
||||||
// Log only when path is not being skipped
|
// Log only when it is not being skipped
|
||||||
if _, ok := skip[path]; !ok {
|
if _, ok := skip[path]; ok || (conf.Skip != nil && conf.Skip(c)) {
|
||||||
param := LogFormatterParams{
|
return
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -415,6 +415,26 @@ func TestLoggerWithConfigSkippingPaths(t *testing.T) {
|
||||||
assert.Contains(t, buffer.String(), "")
|
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) {
|
func TestDisableConsoleColor(t *testing.T) {
|
||||||
New()
|
New()
|
||||||
assert.Equal(t, autoColor, consoleColorMode)
|
assert.Equal(t, autoColor, consoleColorMode)
|
||||||
|
|
Loading…
Reference in New Issue