From fec832402625d856aba0cc2fbdec9e773469ad87 Mon Sep 17 00:00:00 2001 From: a1012112796 <1012112796@qq.com> Date: Sat, 22 May 2021 05:37:16 +0800 Subject: [PATCH] add a new internal hook to save ssh log (#15787) * add a new internal hook to save ssh log as title, when a ssh error ocure like #15785. only when switch ``RUN_MODE`` to dev can we found which error is ocure. But this way is not a good idea for production envirment. this changes try save ssh error mesage to the log file like other log by a new internal hook. I think it's usefull for find error message in production envirment. Thanks. Signed-off-by: a1012112796 <1012112796@qq.com> * rename and fix nit * Update modules/private/hook.go Co-authored-by: silverwind Co-authored-by: techknowlogick Co-authored-by: silverwind Co-authored-by: techknowlogick --- cmd/serv.go | 4 +++ custom/conf/app.example.ini | 5 +++ .../doc/advanced/config-cheat-sheet.en-us.md | 1 + modules/private/hook.go | 31 +++++++++++++++++ modules/setting/log.go | 1 + modules/setting/setting.go | 1 + routers/private/internal.go | 1 + routers/private/ssh_log.go | 34 +++++++++++++++++++ 8 files changed, 78 insertions(+) create mode 100644 routers/private/ssh_log.go diff --git a/cmd/serv.go b/cmd/serv.go index 56167f63a8..1c9f5dc44e 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -81,6 +81,10 @@ func fail(userMessage, logMessage string, args ...interface{}) { } } + if len(logMessage) > 0 { + _ = private.SSHLog(true, fmt.Sprintf(logMessage+": ", args...)) + } + os.Exit(1) } diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index b1fe95e6e2..f37157c3b1 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -444,6 +444,11 @@ ROUTER = console ;ACCESS_LOG_TEMPLATE = {{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}" ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; SSH log (Creates log from ssh git request) +;; +;ENABLE_SSH_LOG = false +;; ;; Other Settings ;; ;; Print Stacktraces with logs. (Rarely helpful.) Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "None" diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 9bb790f4c9..ee701b6572 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -657,6 +657,7 @@ Default templates for project boards: - `ROUTER`: **console**: The mode or name of the log the router should log to. (If you set this to `,` it will log to default gitea logger.) NB: You must have `DISABLE_ROUTER_LOG` set to `false` for this option to take effect. Configure each mode in per mode log subsections `\[log.modename.router\]`. - `ENABLE_ACCESS_LOG`: **false**: Creates an access.log in NCSA common log format, or as per the following template +- `ENABLE_SSH_LOG`: **false**: save ssh log to log file - `ACCESS`: **file**: Logging mode for the access logger, use a comma to separate values. Configure each mode in per mode log subsections `\[log.modename.access\]`. By default the file mode will log to `$ROOT_PATH/access.log`. (If you set this to `,` it will log to the default gitea logger.) - `ACCESS_LOG_TEMPLATE`: **`{{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}"`**: Sets the template used to create the access log. - The following variables are available: diff --git a/modules/private/hook.go b/modules/private/hook.go index 178500f736..cb8fe25708 100644 --- a/modules/private/hook.go +++ b/modules/private/hook.go @@ -5,6 +5,7 @@ package private import ( + "encoding/json" "fmt" "net/http" "net/url" @@ -57,6 +58,12 @@ type HookOptions struct { IsDeployKey bool } +// SSHLogOption ssh log options +type SSHLogOption struct { + IsError bool + Message string +} + // HookPostReceiveResult represents an individual result from PostReceive type HookPostReceiveResult struct { Results []HookPostReceiveBranchResult @@ -146,3 +153,27 @@ func SetDefaultBranch(ownerName, repoName, branch string) error { } return nil } + +// SSHLog sends ssh error log response +func SSHLog(isErr bool, msg string) error { + reqURL := setting.LocalURL + "api/internal/ssh/log" + req := newInternalRequest(reqURL, "POST") + req = req.Header("Content-Type", "application/json") + + jsonBytes, _ := json.Marshal(&SSHLogOption{ + IsError: isErr, + Message: msg, + }) + req.Body(jsonBytes) + + req.SetTimeout(60*time.Second, 60*time.Second) + resp, err := req.Response() + if err != nil { + return fmt.Errorf("unable to contact gitea: %v", err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("Error returned from gitea: %v", decodeJSONError(resp).Err) + } + return nil +} diff --git a/modules/setting/log.go b/modules/setting/log.go index 44017b1138..0fb108c93d 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -287,6 +287,7 @@ func newLogService() { options := newDefaultLogOptions() options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000) + EnableSSHLog = Cfg.Section("log").Key("ENABLE_SSH_LOG").MustBool(false) description := LogDescription{ Name: log.DEFAULT, diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 4244b55939..ec8e64578b 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -319,6 +319,7 @@ var ( DisableRouterLog bool RouterLogLevel log.Level EnableAccessLog bool + EnableSSHLog bool AccessLogTemplate string EnableXORMLog bool diff --git a/routers/private/internal.go b/routers/private/internal.go index c6cc61fc29..9202e67218 100644 --- a/routers/private/internal.go +++ b/routers/private/internal.go @@ -55,6 +55,7 @@ func Routes() *web.Route { r.Post("/ssh/authorized_keys", AuthorizedPublicKeyByContent) r.Post("/ssh/{id}/update/{repoid}", UpdatePublicKeyInRepo) + r.Post("/ssh/log", bind(private.SSHLogOption{}), SSHLog) r.Post("/hook/pre-receive/{owner}/{repo}", bind(private.HookOptions{}), HookPreReceive) r.Post("/hook/post-receive/{owner}/{repo}", bind(private.HookOptions{}), HookPostReceive) r.Post("/hook/set-default-branch/{owner}/{repo}/{branch}", SetDefaultBranch) diff --git a/routers/private/ssh_log.go b/routers/private/ssh_log.go new file mode 100644 index 0000000000..2f1793a0e0 --- /dev/null +++ b/routers/private/ssh_log.go @@ -0,0 +1,34 @@ +// Copyright 2021 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 private + +import ( + "net/http" + + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/private" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/web" +) + +// SSHLog hook to response ssh log +func SSHLog(ctx *context.PrivateContext) { + if !setting.EnableSSHLog { + ctx.Status(http.StatusOK) + return + } + + opts := web.GetForm(ctx).(*private.SSHLogOption) + + if opts.IsError { + log.Error("ssh: %v", opts.Message) + ctx.Status(http.StatusOK) + return + } + + log.Debug("ssh: %v", opts.Message) + ctx.Status(http.StatusOK) +}