diff --git a/cmd/party/common/application.go b/cmd/party/common/application.go index 89cc7a5..45a374a 100644 --- a/cmd/party/common/application.go +++ b/cmd/party/common/application.go @@ -79,6 +79,7 @@ type contextKey string const userKey contextKey = "web_user" const permissionsKey contextKey = "web_permissions" +const RequestBodyKey contextKey = "request_body" func SetUser(r *http.Request, user *data.User) *http.Request { return r.WithContext(context.WithValue(r.Context(), userKey, user)) diff --git a/cmd/party/common/helpers.go b/cmd/party/common/helpers.go index 0da0d20..68c23c8 100644 --- a/cmd/party/common/helpers.go +++ b/cmd/party/common/helpers.go @@ -1,6 +1,7 @@ package common import ( + "bytes" "crypto/rand" "crypto/rsa" "crypto/x509" @@ -128,8 +129,12 @@ func ReadCSV(qs url.Values, key string, defaultValue []string) []string { // ── Error responses ────────────────────────────────────────────────────────── func (app *Application) LogError(r *http.Request, err error) { - app.Logger.PrintError(err, map[string]string{ + props := map[string]string{ "request_method": r.Method, "request_url": r.URL.String(), - }) + } + if buf, ok := r.Context().Value(RequestBodyKey).(*bytes.Buffer); ok && buf.Len() > 0 { + props["request_body"] = buf.String() + } + app.Logger.PrintError(err, props) } diff --git a/cmd/party/common/middleware.go b/cmd/party/common/middleware.go index b742ffc..ea38a3f 100644 --- a/cmd/party/common/middleware.go +++ b/cmd/party/common/middleware.go @@ -1,7 +1,10 @@ package common import ( + "bytes" + "context" "expvar" + "io" "net/http" "strconv" "sync" @@ -9,6 +12,15 @@ import ( "github.com/felixge/httpsnoop" ) +func (app *Application) CaptureBody(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + buf := &bytes.Buffer{} + r.Body = io.NopCloser(io.TeeReader(r.Body, buf)) + ctx := context.WithValue(r.Context(), RequestBodyKey, buf) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} + var ( metricsOnce sync.Once metricTotalRequests *expvar.Int diff --git a/cmd/party/routes.go b/cmd/party/routes.go index e1f83ee..250bb37 100644 --- a/cmd/party/routes.go +++ b/cmd/party/routes.go @@ -40,7 +40,7 @@ func routes(app *common.Application) http.Handler { apiMux.HandleFunc("GET /v1/parlament/votes/{path...}", api.GetParlVoteDetail) apiMux.Handle("GET /debug/vars", expvar.Handler()) - apiChain := app.Metrics(api.RecoverPanic(app.EnableCORS(api.RateLimit(api.Authenticate(apiMux))))) + apiChain := app.Metrics(api.RecoverPanic(app.CaptureBody(app.EnableCORS(api.RateLimit(api.Authenticate(apiMux)))))) // ── Web router ────────────────────────────────────────────────────────── web := web.Web{ diff --git a/internal/jsonlog/jsonlog.go b/internal/jsonlog/jsonlog.go index 9d0b15a..7879340 100644 --- a/internal/jsonlog/jsonlog.go +++ b/internal/jsonlog/jsonlog.go @@ -4,7 +4,6 @@ import ( "encoding/json" "io" "os" - "runtime/debug" "sync" "time" ) @@ -67,18 +66,13 @@ func (l *Logger) print(level Level, message string, properties map[string]string Time string `json:"time"` Message string `json:"message"` Properties map[string]string `json:"properties,omitempty"` - Trace string `json:"trace,omitempty"` }{ - Level: level.String(), - Time: time.Now().UTC().Format(time.RFC3339), - Message: message, + Level: level.String(), + Time: time.Now().UTC().Format(time.RFC3339), + Message: message, Properties: properties, } - if level >= LevelError { - aux.Trace = string(debug.Stack()) - } - var line []byte line, err := json.Marshal(aux)