diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2021-01-28 01:46:35 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-27 18:46:35 +0100 |
commit | a51cc6dea41b154b946e982fde6cc1a600210a71 (patch) | |
tree | 07e9f38a2f3572bb8ed9a666d33dd30e976bd5e6 /modules/context | |
parent | 4c6e0295069a3c2f0df3d9f30560906bc2aa73a8 (diff) | |
download | gitea-a51cc6dea41b154b946e982fde6cc1a600210a71.tar.gz gitea-a51cc6dea41b154b946e982fde6cc1a600210a71.zip |
Fix access log (#14475)
Fix #14121, #14478.
The `AccessLog` middleware has to be after `Contexter` or `APIContexter` so that we can get `LoginUserName` if possible.
And also there is a **BREAK** change that it removed internal API access log.
Diffstat (limited to 'modules/context')
-rw-r--r-- | modules/context/access_log.go | 60 | ||||
-rw-r--r-- | modules/context/context.go | 25 | ||||
-rw-r--r-- | modules/context/response.go | 10 |
3 files changed, 94 insertions, 1 deletions
diff --git a/modules/context/access_log.go b/modules/context/access_log.go new file mode 100644 index 0000000000..97bb32f4c5 --- /dev/null +++ b/modules/context/access_log.go @@ -0,0 +1,60 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package context + +import ( + "bytes" + "html/template" + "net/http" + "time" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" +) + +type routerLoggerOptions struct { + req *http.Request + Identity *string + Start *time.Time + ResponseWriter http.ResponseWriter + Ctx map[string]interface{} +} + +// AccessLogger returns a middleware to log access logger +func AccessLogger() func(http.Handler) http.Handler { + logger := log.GetLogger("access") + logTemplate, _ := template.New("log").Parse(setting.AccessLogTemplate) + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + start := time.Now() + next.ServeHTTP(w, req) + identity := "-" + if val := SignedUserName(req); val != "" { + identity = val + } + rw := w.(ResponseWriter) + + buf := bytes.NewBuffer([]byte{}) + err := logTemplate.Execute(buf, routerLoggerOptions{ + req: req, + Identity: &identity, + Start: &start, + ResponseWriter: rw, + Ctx: map[string]interface{}{ + "RemoteAddr": req.RemoteAddr, + "Req": req, + }, + }) + if err != nil { + log.Error("Could not set up chi access logger: %v", err.Error()) + } + + err = logger.SendLog(log.INFO, "", "", 0, buf.String(), "") + if err != nil { + log.Error("Could not set up chi access logger: %v", err.Error()) + } + }) + } +} diff --git a/modules/context/context.go b/modules/context/context.go index e5025205c9..d02339d5b0 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -485,6 +485,31 @@ func GetContext(req *http.Request) *Context { return req.Context().Value(contextKey).(*Context) } +// SignedUserName returns signed user's name via context +func SignedUserName(req *http.Request) string { + if middlewares.IsInternalPath(req) { + return "" + } + if middlewares.IsAPIPath(req) { + ctx, ok := req.Context().Value(apiContextKey).(*APIContext) + if ok { + v := ctx.Data["SignedUserName"] + if res, ok := v.(string); ok { + return res + } + } + } else { + ctx, ok := req.Context().Value(contextKey).(*Context) + if ok { + v := ctx.Data["SignedUserName"] + if res, ok := v.(string); ok { + return res + } + } + } + return "" +} + func getCsrfOpts() CsrfOptions { return CsrfOptions{ Secret: setting.SecretKey, diff --git a/modules/context/response.go b/modules/context/response.go index 1881ec7b33..bdbbb97af7 100644 --- a/modules/context/response.go +++ b/modules/context/response.go @@ -12,6 +12,7 @@ type ResponseWriter interface { Flush() Status() int Before(func(ResponseWriter)) + Size() int } var ( @@ -21,11 +22,17 @@ var ( // Response represents a response type Response struct { http.ResponseWriter + written int status int befores []func(ResponseWriter) beforeExecuted bool } +// Size return written size +func (r *Response) Size() int { + return r.written +} + // Write writes bytes to HTTP endpoint func (r *Response) Write(bs []byte) (int, error) { if !r.beforeExecuted { @@ -35,8 +42,9 @@ func (r *Response) Write(bs []byte) (int, error) { r.beforeExecuted = true } size, err := r.ResponseWriter.Write(bs) + r.written += size if err != nil { - return 0, err + return size, err } if r.status == 0 { r.WriteHeader(200) |