Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

loggerConfig supports request body #3732

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 14 additions & 0 deletions logger.go
Expand Up @@ -5,6 +5,7 @@
package gin

import (
"bytes"
"fmt"
"io"
"net/http"
Expand Down Expand Up @@ -47,6 +48,10 @@ type LoggerConfig struct {
// SkipPaths is an url path array which logs are not written.
// Optional.
SkipPaths []string

// RequestBody is a bool to enable request body logging
// Optional. Default value is false
RequestBody bool
}

// LogFormatter gives the signature of the formatter function passed to LoggerWithFormatter
Expand Down Expand Up @@ -236,11 +241,20 @@ func LoggerWithConfig(conf LoggerConfig) HandlerFunc {
path := c.Request.URL.Path
raw := c.Request.URL.RawQuery

var body []byte
if conf.RequestBody {
body, _ = io.ReadAll(c.Request.Body)
c.Request.Body = io.NopCloser(bytes.NewBuffer(body))
}

// Process request
c.Next()

// Log only when path is not being skipped
if _, ok := skip[path]; !ok {
if conf.RequestBody {
c.Request.Body = io.NopCloser(bytes.NewBuffer(body))
}
param := LogFormatterParams{
Request: c.Request,
isTerm: isTerm,
Expand Down
20 changes: 18 additions & 2 deletions logger_test.go
Expand Up @@ -5,8 +5,10 @@
package gin

import (
"bytes"
"errors"
"fmt"
"io"
"net/http"
"strings"
"testing"
Expand Down Expand Up @@ -182,25 +184,29 @@ func TestLoggerWithFormatter(t *testing.T) {
func TestLoggerWithConfigFormatting(t *testing.T) {
var gotParam LogFormatterParams
var gotKeys map[string]any
var gotBody []byte
buffer := new(strings.Builder)

router := New()
router.engine.trustedCIDRs, _ = router.engine.prepareTrustedCIDRs()

router.Use(LoggerWithConfig(LoggerConfig{
Output: buffer,
Output: buffer,
RequestBody: true,
Formatter: func(param LogFormatterParams) string {
// for assert test
gotParam = param
gotBody, _ = io.ReadAll(param.Request.Body)

return fmt.Sprintf("[FORMATTER TEST] %v | %3d | %13v | %15s | %-7s %s\n%s",
return fmt.Sprintf("[FORMATTER TEST] %v | %3d | %13v | %15s | %-7s %s %s\n%s",
param.TimeStamp.Format("2006/01/02 - 15:04:05"),
param.StatusCode,
param.Latency,
param.ClientIP,
param.Method,
param.Path,
param.ErrorMessage,
string(gotBody),
)
},
}))
Expand Down Expand Up @@ -229,6 +235,16 @@ func TestLoggerWithConfigFormatting(t *testing.T) {
assert.Equal(t, "/example?a=100", gotParam.Path)
assert.Empty(t, gotParam.ErrorMessage)
assert.Equal(t, gotKeys, gotParam.Keys)

router.POST("/example", func(c *Context) {
// set dummy ClientIP
c.Request.Header.Set("X-Forwarded-For", "20.20.20.20")
time.Sleep(time.Millisecond)
})
PerformBodyRequest(router, "POST", "/example", []header{}, bytes.NewBufferString(`{"name":"test"}`))

// LogFormatterParams post body test
assert.Equal(t, string(gotBody), `{"name":"test"}`)
}

func TestDefaultLogFormatter(t *testing.T) {
Expand Down
11 changes: 10 additions & 1 deletion routes_test.go
Expand Up @@ -6,6 +6,7 @@ package gin

import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"os"
Expand All @@ -30,7 +31,15 @@ func PerformRequest(r http.Handler, method, path string, headers ...header) *htt
r.ServeHTTP(w, req)
return w
}

func PerformBodyRequest(r http.Handler, method, path string, headers []header, body io.Reader) *httptest.ResponseRecorder {
req := httptest.NewRequest(method, path, body)
for _, h := range headers {
req.Header.Add(h.Key, h.Value)
}
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
return w
}
func testRouteOK(method string, t *testing.T) {
passed := false
passedAny := false
Expand Down