From c996d71378a43b172ae392a04fa8a30b60bb75e0 Mon Sep 17 00:00:00 2001 From: Dan Sosedoff Date: Thu, 1 Dec 2022 12:35:02 -0600 Subject: [PATCH 1/2] Implement gin request logger with param filtering --- go.mod | 1 + go.sum | 3 +++ pkg/api/logger.go | 54 +++++++++++++++++++++++++++++++++++++++++++++++ pkg/cli/cli.go | 6 +++++- 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 pkg/api/logger.go diff --git a/go.mod b/go.mod index 4aff634..a781f27 100644 --- a/go.mod +++ b/go.mod @@ -32,6 +32,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/sirupsen/logrus v1.9.0 // indirect github.com/ugorji/go/codec v1.2.6 // indirect golang.org/x/sys v0.2.0 // indirect golang.org/x/text v0.3.7 // indirect diff --git a/go.sum b/go.sum index 98211ef..d5cc007 100644 --- a/go.sum +++ b/go.sum @@ -74,6 +74,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -111,6 +113,7 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210923061019-b8560ed6a9b7 h1:c20P3CcPbopVp2f7099WLOqSNKURf30Z0uq66HpijZY= golang.org/x/sys v0.0.0-20210923061019-b8560ed6a9b7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= diff --git a/pkg/api/logger.go b/pkg/api/logger.go new file mode 100644 index 0000000..5aa2a45 --- /dev/null +++ b/pkg/api/logger.go @@ -0,0 +1,54 @@ +package api + +import ( + "net/http" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" +) + +const loggerMessage = "http_request" + +func RequestLogger(logger *logrus.Logger) gin.HandlerFunc { + return func(c *gin.Context) { + start := time.Now() + path := c.Request.URL.Path + + // Process request + c.Next() + + // Skip logging static assets + if strings.Contains(path, "/static/") { + return + } + + status := c.Writer.Status() + end := time.Now() + latency := end.Sub(start) + + fields := logrus.Fields{ + "status": status, + "method": c.Request.Method, + "path": path, + "remote_addr": c.ClientIP(), + "duration": latency, + } + + if err := c.Errors.Last(); err != nil { + fields["error"] = err.Error() + } + + entry := logrus.WithFields(fields) + + switch { + case status >= http.StatusBadRequest && status < http.StatusInternalServerError: + entry.Warn(loggerMessage) + case status >= http.StatusInternalServerError: + entry.Error(loggerMessage) + default: + entry.Info(loggerMessage) + } + } +} diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index c3e140c..0ce7a20 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -11,6 +11,7 @@ import ( "github.com/gin-gonic/gin" "github.com/jessevdk/go-flags" + "github.com/sirupsen/logrus" "github.com/sosedoff/pgweb/pkg/api" "github.com/sosedoff/pgweb/pkg/bookmarks" @@ -183,7 +184,10 @@ func printVersion() { } func startServer() { - router := gin.Default() + router := gin.New() + + router.Use(api.RequestLogger(logrus.New())) + router.Use(gin.Recovery()) // Enable HTTP basic authentication only if both user and password are set if options.AuthUser != "" && options.AuthPass != "" { From 72ecd20dd1b056ca4f9caa712da3b1a53e7c8b55 Mon Sep 17 00:00:00 2001 From: Dan Sosedoff Date: Thu, 1 Dec 2022 12:49:24 -0600 Subject: [PATCH 2/2] Handle logger levels --- pkg/api/logger.go | 9 ++++++++- pkg/cli/cli.go | 8 ++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/pkg/api/logger.go b/pkg/api/logger.go index 5aa2a45..9f87d0b 100644 --- a/pkg/api/logger.go +++ b/pkg/api/logger.go @@ -12,6 +12,8 @@ import ( const loggerMessage = "http_request" func RequestLogger(logger *logrus.Logger) gin.HandlerFunc { + debug := logger.Level > logrus.InfoLevel + return func(c *gin.Context) { start := time.Now() path := c.Request.URL.Path @@ -20,7 +22,7 @@ func RequestLogger(logger *logrus.Logger) gin.HandlerFunc { c.Next() // Skip logging static assets - if strings.Contains(path, "/static/") { + if strings.Contains(path, "/static/") && !debug { return } @@ -40,6 +42,11 @@ func RequestLogger(logger *logrus.Logger) gin.HandlerFunc { fields["error"] = err.Error() } + // Additional fields for debugging + if debug { + fields["raw_query"] = c.Request.URL.RawQuery + } + entry := logrus.WithFields(fields) switch { diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index 0ce7a20..8247da8 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -184,9 +184,13 @@ func printVersion() { } func startServer() { - router := gin.New() + logger := logrus.New() + if options.Debug { + logger.SetLevel(logrus.DebugLevel) + } - router.Use(api.RequestLogger(logrus.New())) + router := gin.New() + router.Use(api.RequestLogger(logger)) router.Use(gin.Recovery()) // Enable HTTP basic authentication only if both user and password are set