diff --git a/zap.go b/zap.go index cfa31b4..b0d631e 100644 --- a/zap.go +++ b/zap.go @@ -18,6 +18,9 @@ import ( type Fn func(c *gin.Context) []zapcore.Field +// Skipper is a function to skip logs based on provided Context +type Skipper func(c *gin.Context) bool + // ZapLogger is the minimal logger interface compatible with zap.Logger type ZapLogger interface { Info(msg string, fields ...zap.Field) @@ -31,6 +34,9 @@ type Config struct { SkipPaths []string Context Fn DefaultLevel zapcore.Level + // skip is a Skipper that indicates which logs should not be written. + // Optional. + Skipper Skipper } // Ginzap returns a gin.HandlerFunc (middleware) that logs requests using uber-go/zap. @@ -58,8 +64,13 @@ func GinzapWithConfig(logger ZapLogger, conf *Config) gin.HandlerFunc { path := c.Request.URL.Path query := c.Request.URL.RawQuery c.Next() + track := true + + if _, ok := skipPaths[path]; ok || (conf.Skipper != nil && conf.Skipper(c)) { + track = false + } - if _, ok := skipPaths[path]; !ok { + if track { end := time.Now() latency := end.Sub(start) if conf.UTC { diff --git a/zap_test.go b/zap_test.go index 70e4ff7..7b71a0e 100644 --- a/zap_test.go +++ b/zap_test.go @@ -129,3 +129,46 @@ func TestGinzapWithConfig(t *testing.T) { t.Fatalf("log level should be warn but was %s", logLine.Level.String()) } } + +func TestLoggerSkipper(t *testing.T) { + r := gin.New() + + utcLogger, utcLoggerObserved := buildDummyLogger() + r.Use(GinzapWithConfig(utcLogger, &Config{ + TimeFormat: time.RFC3339, + UTC: true, + Skipper: func(c *gin.Context) bool { + return c.Request.URL.Path == "/no_log" + }, + })) + + r.GET("/test", func(c *gin.Context) { + c.JSON(204, nil) + }) + + r.GET("/no_log", func(c *gin.Context) { + c.JSON(204, nil) + }) + + res1 := httptest.NewRecorder() + req1, _ := http.NewRequest("GET", "/test", nil) + r.ServeHTTP(res1, req1) + + res2 := httptest.NewRecorder() + req2, _ := http.NewRequest("GET", "/no_log", nil) + r.ServeHTTP(res2, req2) + + if res2.Code != 204 { + t.Fatalf("request /no_log is failed (%d)", res2.Code) + } + + if len(utcLoggerObserved.All()) != 1 { + t.Fatalf("Log should be 1 line but there're %d", len(utcLoggerObserved.All())) + } + + logLine := utcLoggerObserved.All()[0] + pathStr := logLine.Context[2].String + if pathStr != "/test" { + t.Fatalf("logged path should be /test but %s", pathStr) + } +}