diff --git a/api/logger.go b/api/logger.go index b04170d..05154e7 100644 --- a/api/logger.go +++ b/api/logger.go @@ -1,34 +1,74 @@ package api import ( + "bytes" "fmt" + "io" "log/slog" "time" "github.com/gin-gonic/gin" ) -func Logger(logger *slog.Logger) gin.HandlerFunc { +type responseBodyWriter struct { + gin.ResponseWriter + body *bytes.Buffer +} + +func (r responseBodyWriter) Write(b []byte) (int, error) { + r.body.Write(b) + return r.ResponseWriter.Write(b) +} + +func Logger() gin.HandlerFunc { return func(c *gin.Context) { t := time.Now() - var log []slog.Attr + var body []byte + var w *responseBodyWriter + + if c.Request.Method != "GET" { + body, _ = io.ReadAll(c.Request.Body) + w = &responseBodyWriter{body: &bytes.Buffer{}, ResponseWriter: c.Writer} + c.Writer = w + c.Request.Body = io.NopCloser(bytes.NewReader(body)) + } c.Next() duration := time.Since(t).Milliseconds() - log = append(log, - slog.Int("STATUS", c.Writer.Status()), - slog.String("METHOD", c.Request.Method), - slog.String("PATH", c.Request.RequestURI), - slog.String("DURATION", fmt.Sprintf("%d ms", duration)), - ) + if c.Request.Method != "GET" { + slog.LogAttrs( + c, + slog.LevelDebug, + "http", + slog.Group( + "request", + slog.Int("STATUS", c.Writer.Status()), + slog.String("METHOD", c.Request.Method), + slog.String("PATH", c.Request.RequestURI), + slog.String("DURATION", fmt.Sprintf("%d ms", duration)), + slog.String("BODY", string(body)), + ), + slog.Group( + "response", + slog.String("BODY", w.body.String()), + ), + ) + } else { + slog.LogAttrs( + c, + slog.LevelDebug, + "http", + slog.Group( + "request", + slog.Int("STATUS", c.Writer.Status()), + slog.String("METHOD", c.Request.Method), + slog.String("PATH", c.Request.RequestURI), + slog.String("DURATION", fmt.Sprintf("%d ms", duration)), + ), + ) - logger.LogAttrs( - c, - slog.LevelDebug, - "http", - log..., - ) + } } } diff --git a/api/server.go b/api/server.go index 518523b..4f09c5c 100644 --- a/api/server.go +++ b/api/server.go @@ -31,12 +31,19 @@ func NewServer(config util.Config, store db.Store) *Server { opts := slog.HandlerOptions{ Level: logLevel, } - logger := slog.New(slog.NewJSONHandler(os.Stdout, &opts)) + logger := slog.New(slog.NewTextHandler(os.Stdout, &opts)) + + if config.LogOutput == "json" { + logger = slog.New(slog.NewJSONHandler(os.Stdout, &opts)) + } + + slog.SetDefault(logger) + router := gin.New() router.Use(gin.Recovery()) - router.Use(Logger(logger)) + router.Use(Logger()) router.POST("/accounts", server.createAccount) router.GET("/accounts/:id", server.getAccount) diff --git a/app.env b/app.env index 3f75af2..915cf9c 100644 --- a/app.env +++ b/app.env @@ -1,4 +1,5 @@ DB_SOURCE=postgresql://root:secret@localhost:5432/df?sslmode=disable DB_DRIVER=postgres SERVER_ADDRESS=0.0.0.0:8080 -ENVIRONMENT=development \ No newline at end of file +ENVIRONMENT=development +LOG_OUTPUT=text \ No newline at end of file diff --git a/util/config.go b/util/config.go index 0d929f3..5dd256a 100644 --- a/util/config.go +++ b/util/config.go @@ -7,6 +7,7 @@ type Config struct { DBDriver string `mapstructure:"DB_DRIVER"` ServerAddress string `mapstructure:"SERVER_ADDRESS"` Environment string `mapstructure:"ENVIRONMENT"` + LogOutput string `mapstructure:"LOG_OUTPUT"` } func LoadConfig(path string) (config Config, err error) {