mirror of
https://github.com/go-gitea/gitea.git
synced 2024-12-04 14:46:57 -05:00
* Panic don't fatal on create new logger Fixes #5854 Signed-off-by: Andrew Thornton <art27@cantab.net> * partial broken * Update the logging infrastrcture Signed-off-by: Andrew Thornton <art27@cantab.net> * Reset the skip levels for Fatal and Error Signed-off-by: Andrew Thornton <art27@cantab.net> * broken ncsa * More log.Error fixes Signed-off-by: Andrew Thornton <art27@cantab.net> * Remove nal * set log-levels to lowercase * Make console_test test all levels * switch to lowercased levels * OK now working * Fix vetting issues * Fix lint * Fix tests * change default logging to match current gitea * Improve log testing Signed-off-by: Andrew Thornton <art27@cantab.net> * reset error skip levels to 0 * Update documentation and access logger configuration * Redirect the router log back to gitea if redirect macaron log but also allow setting the log level - i.e. TRACE * Fix broken level caching * Refactor the router log * Add Router logger * Add colorizing options * Adjust router colors * Only create logger if they will be used * update app.ini.sample * rename Attribute ColorAttribute * Change from white to green for function * Set fatal/error levels * Restore initial trace logger * Fix Trace arguments in modules/auth/auth.go * Properly handle XORMLogger * Improve admin/config page * fix fmt * Add auto-compression of old logs * Update error log levels * Remove the unnecessary skip argument from Error, Fatal and Critical * Add stacktrace support * Fix tests * Remove x/sync from vendors? * Add stderr option to console logger * Use filepath.ToSlash to protect against Windows in tests * Remove prefixed underscores from names in colors.go * Remove not implemented database logger This was removed from Gogs on 4 Mar 2016 but left in the configuration since then. * Ensure that log paths are relative to ROOT_PATH * use path.Join * rename jsonConfig to logConfig * Rename "config" to "jsonConfig" to make it clearer * Requested changes * Requested changes: XormLogger * Try to color the windows terminal If successful default to colorizing the console logs * fixup * Colorize initially too * update vendor * Colorize logs on default and remove if this is not a colorizing logger * Fix documentation * fix test * Use go-isatty to detect if on windows we are on msys or cygwin * Fix spelling mistake * Add missing vendors * More changes * Rationalise the ANSI writer protection * Adjust colors on advice from @0x5c * Make Flags a comma separated list * Move to use the windows constant for ENABLE_VIRTUAL_TERMINAL_PROCESSING * Ensure matching is done on the non-colored message - to simpify EXPRESSION
This commit is contained in:
parent
ef2a343e27
commit
704da08fdc
@ -204,14 +204,14 @@ func runHookPostReceive(c *cli.Context) error {
|
||||
RepoUserName: repoUser,
|
||||
RepoName: repoName,
|
||||
}); err != nil {
|
||||
log.GitLogger.Error(2, "Update: %v", err)
|
||||
log.GitLogger.Error("Update: %v", err)
|
||||
}
|
||||
|
||||
if newCommitID != git.EmptySHA && strings.HasPrefix(refFullName, git.BranchPrefix) {
|
||||
branch := strings.TrimPrefix(refFullName, git.BranchPrefix)
|
||||
repo, pullRequestAllowed, err := private.GetRepository(repoID)
|
||||
if err != nil {
|
||||
log.GitLogger.Error(2, "get repo: %v", err)
|
||||
log.GitLogger.Error("get repo: %v", err)
|
||||
break
|
||||
}
|
||||
if !pullRequestAllowed {
|
||||
@ -229,7 +229,7 @@ func runHookPostReceive(c *cli.Context) error {
|
||||
|
||||
pr, err := private.ActivePullRequest(baseRepo.ID, repo.ID, baseRepo.DefaultBranch, branch)
|
||||
if err != nil {
|
||||
log.GitLogger.Error(2, "get active pr: %v", err)
|
||||
log.GitLogger.Error("get active pr: %v", err)
|
||||
break
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ func runMigrate(ctx *cli.Context) error {
|
||||
models.LoadConfigs()
|
||||
|
||||
if err := models.NewEngine(migrations.Migrate); err != nil {
|
||||
log.Fatal(4, "Failed to initialize ORM engine: %v", err)
|
||||
log.Fatal("Failed to initialize ORM engine: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,7 @@ func fail(userMessage, logMessage string, args ...interface{}) {
|
||||
if !setting.ProdMode {
|
||||
fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
|
||||
}
|
||||
log.GitLogger.Fatal(3, logMessage, args...)
|
||||
log.GitLogger.Fatal(logMessage, args...)
|
||||
return
|
||||
}
|
||||
|
||||
|
14
cmd/web.go
14
cmd/web.go
@ -69,7 +69,7 @@ func runHTTPRedirector() {
|
||||
var err = runHTTP(source, context2.ClearHandler(handler))
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to start port redirection: %v", err)
|
||||
log.Fatal("Failed to start port redirection: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler)
|
||||
log.Info("Running Let's Encrypt handler on %s", setting.HTTPAddr+":"+setting.PortToRedirect)
|
||||
var err = http.ListenAndServe(setting.HTTPAddr+":"+setting.PortToRedirect, certManager.HTTPHandler(http.HandlerFunc(runLetsEncryptFallbackHandler))) // all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validation happens here)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to start the Let's Encrypt handler on port %s: %v", setting.PortToRedirect, err)
|
||||
log.Fatal("Failed to start the Let's Encrypt handler on port %s: %v", setting.PortToRedirect, err)
|
||||
}
|
||||
}()
|
||||
server := &http.Server{
|
||||
@ -192,13 +192,13 @@ func runWeb(ctx *cli.Context) error {
|
||||
case setting.FCGI:
|
||||
listener, err := net.Listen("tcp", listenAddr)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to bind %s", listenAddr, err)
|
||||
log.Fatal("Failed to bind %s: %v", listenAddr, err)
|
||||
}
|
||||
defer listener.Close()
|
||||
err = fcgi.Serve(listener, context2.ClearHandler(m))
|
||||
case setting.UnixSocket:
|
||||
if err := os.Remove(listenAddr); err != nil && !os.IsNotExist(err) {
|
||||
log.Fatal(4, "Failed to remove unix socket directory %s: %v", listenAddr, err)
|
||||
log.Fatal("Failed to remove unix socket directory %s: %v", listenAddr, err)
|
||||
}
|
||||
var listener *net.UnixListener
|
||||
listener, err = net.ListenUnix("unix", &net.UnixAddr{Name: listenAddr, Net: "unix"})
|
||||
@ -209,15 +209,15 @@ func runWeb(ctx *cli.Context) error {
|
||||
// FIXME: add proper implementation of signal capture on all protocols
|
||||
// execute this on SIGTERM or SIGINT: listener.Close()
|
||||
if err = os.Chmod(listenAddr, os.FileMode(setting.UnixSocketPermission)); err != nil {
|
||||
log.Fatal(4, "Failed to set permission of unix socket: %v", err)
|
||||
log.Fatal("Failed to set permission of unix socket: %v", err)
|
||||
}
|
||||
err = http.Serve(listener, context2.ClearHandler(m))
|
||||
default:
|
||||
log.Fatal(4, "Invalid protocol: %s", setting.Protocol)
|
||||
log.Fatal("Invalid protocol: %s", setting.Protocol)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to start server: %v", err)
|
||||
log.Fatal("Failed to start server: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -34,7 +34,7 @@ func runHTTPS(listenAddr, certFile, keyFile string, m http.Handler) error {
|
||||
var err error
|
||||
config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to load https cert file %s: %v", listenAddr, err)
|
||||
log.Fatal("Failed to load https cert file %s: %v", listenAddr, err)
|
||||
}
|
||||
|
||||
return gracehttp.Serve(&http.Server{
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
; This file lists the default values used by Gitea
|
||||
; Copy required sections to your own app.ini (default is custom/conf/app.ini)
|
||||
; and modify as needed.
|
||||
@ -33,7 +34,7 @@ PREFERRED_LICENSES = Apache License 2.0,MIT License
|
||||
DISABLE_HTTP_GIT = false
|
||||
; Value for Access-Control-Allow-Origin header, default is not to present
|
||||
; WARNING: This maybe harmful to you website if you do not give it a right value.
|
||||
ACCESS_CONTROL_ALLOW_ORIGIN =
|
||||
ACCESS_CONTROL_ALLOW_ORIGIN =
|
||||
; Force ssh:// clone url instead of scp-style uri when default SSH port is used
|
||||
USE_COMPAT_SSH_URI = false
|
||||
; Close issues as long as a commit on any branch marks it as fixed
|
||||
@ -260,7 +261,7 @@ ISSUE_INDEXER_TYPE = bleve
|
||||
ISSUE_INDEXER_PATH = indexers/issues.bleve
|
||||
; Issue indexer queue, currently support: channel or levelqueue, default is levelqueue
|
||||
ISSUE_INDEXER_QUEUE_TYPE = levelqueue
|
||||
; When ISSUE_INDEXER_QUEUE_TYPE is levelqueue, this will be the queue will be saved path,
|
||||
; When ISSUE_INDEXER_QUEUE_TYPE is levelqueue, this will be the queue will be saved path,
|
||||
; default is indexers/issues.queue
|
||||
ISSUE_INDEXER_QUEUE_DIR = indexers/issues.queue
|
||||
; Batch queue number, default is 20
|
||||
@ -390,8 +391,8 @@ NO_REPLY_ADDRESS = noreply.example.org
|
||||
; Show Registration button
|
||||
SHOW_REGISTRATION_BUTTON = true
|
||||
; Default value for AutoWatchNewRepos
|
||||
; When adding a repo to a team or creating a new repo all team members will watch the
|
||||
; repo automatically if enabled
|
||||
; When adding a repo to a team or creating a new repo all team members will watch the
|
||||
; repo automatically if enabled
|
||||
AUTO_WATCH_NEW_REPOS = true
|
||||
|
||||
[webhook]
|
||||
@ -516,17 +517,37 @@ ROOT_PATH =
|
||||
MODE = console
|
||||
; Buffer length of the channel, keep it as it is if you don't know what it is.
|
||||
BUFFER_LEN = 10000
|
||||
; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"
|
||||
LEVEL = Trace
|
||||
REDIRECT_MACARON_LOG = false
|
||||
MACARON = file
|
||||
; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Info"
|
||||
ROUTER_LOG_LEVEL = Info
|
||||
ROUTER = console
|
||||
ENABLE_ACCESS_LOG = false
|
||||
ACCESS_LOG_TEMPLATE = {{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}"
|
||||
ACCESS = file
|
||||
; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"
|
||||
LEVEL = Info
|
||||
; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "None"
|
||||
STACKTRACE_LEVEL = None
|
||||
|
||||
; Generic log modes
|
||||
[log.x]
|
||||
FLAGS = stdflags
|
||||
EXPRESSION =
|
||||
PREFIX =
|
||||
COLORIZE = false
|
||||
|
||||
; For "console" mode only
|
||||
[log.console]
|
||||
LEVEL =
|
||||
STDERR = false
|
||||
|
||||
; For "file" mode only
|
||||
[log.file]
|
||||
LEVEL =
|
||||
; Set the file_name for the logger. If this is a relative path this
|
||||
; will be relative to ROOT_PATH
|
||||
FILE_NAME =
|
||||
; This enables automated log rotate(switch of following options), default is true
|
||||
LOG_ROTATE = true
|
||||
; Max number of lines in a single file, default is 1000000
|
||||
@ -537,6 +558,10 @@ MAX_SIZE_SHIFT = 28
|
||||
DAILY_ROTATE = true
|
||||
; delete the log file after n days, default is 7
|
||||
MAX_DAYS = 7
|
||||
; compress logs with gzip
|
||||
COMPRESS = true
|
||||
; compression level see godoc for compress/gzip
|
||||
COMPRESSION_LEVEL = -1
|
||||
|
||||
; For "conn" mode only
|
||||
[log.conn]
|
||||
@ -564,14 +589,6 @@ PASSWD =
|
||||
; Receivers, can be one or more, e.g. 1@example.com,2@example.com
|
||||
RECEIVERS =
|
||||
|
||||
; For "database" mode only
|
||||
[log.database]
|
||||
LEVEL =
|
||||
; Either "mysql" or "postgres"
|
||||
DRIVER =
|
||||
; Based on xorm, e.g.: root:root@localhost/gitea?charset=utf8
|
||||
CONN =
|
||||
|
||||
[cron]
|
||||
; Enable running cron tasks periodically.
|
||||
ENABLED = true
|
||||
|
@ -68,10 +68,12 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
|
||||
- `DEFAULT_CLOSE_ISSUES_VIA_COMMITS_IN_ANY_BRANCH`: **false**: Close an issue if a commit on a non default branch marks it as closed.
|
||||
|
||||
### Repository - Pull Request (`repository.pull-request`)
|
||||
|
||||
- `WORK_IN_PROGRESS_PREFIXES`: **WIP:,\[WIP\]**: List of prefixes used in Pull Request
|
||||
title to mark them as Work In Progress
|
||||
|
||||
### Repository - Issue (`repository.issue`)
|
||||
|
||||
- `LOCK_REASONS`: **Too heated,Off-topic,Resolved,Spam**: A list of reasons why a Pull Request or Issue can be locked
|
||||
|
||||
## UI (`ui`)
|
||||
@ -287,9 +289,65 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
|
||||
## Log (`log`)
|
||||
|
||||
- `ROOT_PATH`: **\<empty\>**: Root path for log files.
|
||||
- `MODE`: **console**: Logging mode. For multiple modes, use a comma to separate values.
|
||||
- `LEVEL`: **Trace**: General log level. \[Trace, Debug, Info, Warn, Error, Critical\]
|
||||
- `REDIRECT_MACARON_LOG`: **false**: Redirects the Macaron log to the Gitea logger.
|
||||
- `MODE`: **console**: Logging mode. For multiple modes, use a comma to separate values. You can configure each mode in per mode log subsections `\[log.modename\]`. By default the file mode will log to `$ROOT_PATH/gitea.log`.
|
||||
- `LEVEL`: **Info**: General log level. \[Trace, Debug, Info, Warn, Error, Critical, Fatal, None\]
|
||||
- `STACKTRACE_LEVEL`: **None**: Default log level at which to log create stack traces. \[Trace, Debug, Info, Warn, Error, Critical, Fatal, None\]
|
||||
- `REDIRECT_MACARON_LOG`: **false**: Redirects the Macaron log to its own logger or the default logger.
|
||||
- `MACARON`: **file**: Logging mode for the macaron logger, use a comma to separate values. Configure each mode in per mode log subsections `\[log.modename.macaron\]`. By default the file mode will log to `$ROOT_PATH/macaron.log`. (If you set this to `,` it will log to default gitea logger.)
|
||||
- `ROUTER_LOG_LEVEL`: **Info**: The log level that the router should log at. (If you are setting the access log, its recommended to place this at Debug.)
|
||||
- `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 `REDIRECT_MACARON_LOG` and 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
|
||||
- `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.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:
|
||||
- `Ctx`: the `macaron.Context` of the request.
|
||||
- `Identity`: the SignedUserName or `"-"` if not logged in.
|
||||
- `Start`: the start time of the request.
|
||||
- `ResponseWriter`: the responseWriter from the request.
|
||||
- You must be very careful to ensure that this template does not throw errors or panics as this template runs outside of the panic/recovery script.
|
||||
- `ENABLE_XORM_LOG`: **true**: Set whether to perform XORM logging. Please note SQL statement logging can be disabled by setting `LOG_SQL` to false in the `[database]` section.
|
||||
|
||||
### Log subsections (`log.name`, `log.name.*`)
|
||||
|
||||
- `LEVEL`: **log.LEVEL**: Sets the log-level of this sublogger. Defaults to the `LEVEL` set in the global `[log]` section.
|
||||
- `STACKTRACE_LEVEL`: **log.STACKTRACE_LEVEL**: Sets the log level at which to log stack traces.
|
||||
- `MODE`: **name**: Sets the mode of this sublogger - Defaults to the provided subsection name. This allows you to have two different file loggers at different levels.
|
||||
- `EXPRESSION`: **""**: A regular expression to match either the function name, file or message. Defaults to empty. Only log messages that match the expression will be saved in the logger.
|
||||
- `FLAGS`: **stdflags**: A comma separated string representing the log flags. Defaults to `stdflags` which represents the prefix: `2009/01/23 01:23:23 ...a/b/c/d.go:23:runtime.Caller() [I]: message`. `none` means don't prefix log lines. See `modules/log/base.go` for more information.
|
||||
- `PREFIX`: **""**: An additional prefix for every log line in this logger. Defaults to empty.
|
||||
- `COLORIZE`: **false**: Colorize the log lines by default
|
||||
|
||||
### Console log mode (`log.console`, `log.console.*`, or `MODE=console`)
|
||||
|
||||
- For the console logger `COLORIZE` will default to `true` if not on windows.
|
||||
- `STDERR`: **false**: Use Stderr instead of Stdout.
|
||||
|
||||
### File log mode (`log.file`, `log.file.*` or `MODE=file`)
|
||||
|
||||
- `FILE_NAME`: Set the file name for this logger. Defaults as described above. If relative will be relative to the `ROOT_PATH`
|
||||
- `LOG_ROTATE`: **true**: Rotate the log files.
|
||||
- `MAX_SIZE_SHIFT`: **28**: Maximum size shift of a single file, 28 represents 256Mb.
|
||||
- `DAILY_ROTATE`: **true**: Rotate logs daily.
|
||||
- `MAX_DAYS`: **7**: Delete the log file after n days
|
||||
- NB: `COLORIZE`: will default to `true` if not on windows.
|
||||
- `COMPRESS`: **true**: Compress old log files by default with gzip
|
||||
- `COMPRESSION_LEVEL`: **-1**: Compression level
|
||||
|
||||
### Conn log mode (`log.conn`, `log.conn.*` or `MODE=conn`)
|
||||
|
||||
- `RECONNECT_ON_MSG`: **false**: Reconnect host for every single message.
|
||||
- `RECONNECT`: **false**: Try to reconnect when connection is lost.
|
||||
- `PROTOCOL`: **tcp**: Set the protocol, either "tcp", "unix" or "udp".
|
||||
- `ADDR`: **:7020**: Sets the address to connect to.
|
||||
|
||||
### SMTP log mode (`log.smtp`, `log.smtp.*` or `MODE=smtp`)
|
||||
|
||||
- `USER`: User email address to send from.
|
||||
- `PASSWD`: Password for the smtp server.
|
||||
- `HOST`: **127.0.0.1:25**: The SMTP host to connect to.
|
||||
- `RECEIVERS`: Email addresses to send to.
|
||||
- `SUBJECT`: **Diagnostic message from Gitea**
|
||||
|
||||
## Cron (`cron`)
|
||||
|
||||
|
4
go.mod
4
go.mod
@ -79,6 +79,7 @@ require (
|
||||
github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de // indirect
|
||||
github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af // indirect
|
||||
github.com/markbates/goth v1.49.0
|
||||
github.com/mattn/go-isatty v0.0.7
|
||||
github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d // indirect
|
||||
github.com/mattn/go-sqlite3 v1.10.0
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
@ -114,8 +115,7 @@ require (
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519
|
||||
golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759 // indirect
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f
|
||||
golang.org/x/sys v0.0.0-20181026144532-2772b66316d2
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223
|
||||
golang.org/x/text v0.3.0
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect
|
||||
|
6
go.sum
6
go.sum
@ -207,6 +207,8 @@ github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VOb
|
||||
github.com/markbates/going v1.0.0/go.mod h1:I6mnB4BPnEeqo85ynXIx1ZFLLbtiLHNXVgWeFO9OGOA=
|
||||
github.com/markbates/goth v1.49.0 h1:qQ4Ti4WaqAxNAggOC+4s5M85sMVfMJwQn/Xkp73wfgI=
|
||||
github.com/markbates/goth v1.49.0/go.mod h1:zZmAw0Es0Dpm7TT/4AdN14QrkiWLMrrU9Xei1o+/mdA=
|
||||
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d h1:m+dSK37rFf2fqppZhg15yI2IwC9BtucBiRwSDm9VL8g=
|
||||
github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d/go.mod h1:/M9VLO+lUPmxvoOK2PfWRZ8mTtB4q1Hy9lEGijv9Nr8=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
@ -311,8 +313,8 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6Zh
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026144532-2772b66316d2 h1:W7CqTdBJ1CmxLKe7LptKDnBYV6PHrVLiGnoyBjaG/JQ=
|
||||
golang.org/x/sys v0.0.0-20181026144532-2772b66316d2/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
2
main.go
2
main.go
@ -56,7 +56,7 @@ arguments - which can alternatively be run by running the subcommand web.`
|
||||
app.Action = cmd.CmdWeb.Action
|
||||
err := app.Run(os.Args)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to run app with %s: %v", os.Args, err)
|
||||
log.Fatal("Failed to run app with %s: %v", os.Args, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ func (a *Action) loadActUser() {
|
||||
} else if IsErrUserNotExist(err) {
|
||||
a.ActUser = NewGhostUser()
|
||||
} else {
|
||||
log.Error(4, "GetUserByID(%d): %v", a.ActUserID, err)
|
||||
log.Error("GetUserByID(%d): %v", a.ActUserID, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@ func (a *Action) loadRepo() {
|
||||
var err error
|
||||
a.Repo, err = GetRepositoryByID(a.RepoID)
|
||||
if err != nil {
|
||||
log.Error(4, "GetRepositoryByID(%d): %v", a.RepoID, err)
|
||||
log.Error("GetRepositoryByID(%d): %v", a.RepoID, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -256,7 +256,7 @@ func (a *Action) GetIssueTitle() string {
|
||||
index := com.StrTo(a.GetIssueInfos()[0]).MustInt64()
|
||||
issue, err := GetIssueByIndex(a.RepoID, index)
|
||||
if err != nil {
|
||||
log.Error(4, "GetIssueByIndex: %v", err)
|
||||
log.Error("GetIssueByIndex: %v", err)
|
||||
return "500 when get issue"
|
||||
}
|
||||
return issue.Title
|
||||
@ -268,7 +268,7 @@ func (a *Action) GetIssueContent() string {
|
||||
index := com.StrTo(a.GetIssueInfos()[0]).MustInt64()
|
||||
issue, err := GetIssueByIndex(a.RepoID, index)
|
||||
if err != nil {
|
||||
log.Error(4, "GetIssueByIndex: %v", err)
|
||||
log.Error("GetIssueByIndex: %v", err)
|
||||
return "500 when get issue"
|
||||
}
|
||||
return issue.Content
|
||||
@ -419,7 +419,7 @@ func (pc *PushCommits) AvatarLink(email string) string {
|
||||
if err != nil {
|
||||
pc.avatars[email] = base.AvatarLink(email)
|
||||
if !IsErrUserNotExist(err) {
|
||||
log.Error(4, "GetUserByEmail: %v", err)
|
||||
log.Error("GetUserByEmail: %v", err)
|
||||
return ""
|
||||
}
|
||||
} else {
|
||||
@ -619,7 +619,7 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
|
||||
}
|
||||
|
||||
if err = UpdateIssuesCommit(pusher, repo, opts.Commits.Commits, refName); err != nil {
|
||||
log.Error(4, "updateIssuesCommit: %v", err)
|
||||
log.Error("updateIssuesCommit: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -661,12 +661,12 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
|
||||
if isNewBranch {
|
||||
gitRepo, err := git.OpenRepository(repo.RepoPath())
|
||||
if err != nil {
|
||||
log.Error(4, "OpenRepository[%s]: %v", repo.RepoPath(), err)
|
||||
log.Error("OpenRepository[%s]: %v", repo.RepoPath(), err)
|
||||
}
|
||||
|
||||
shaSum, err = gitRepo.GetBranchCommitID(refName)
|
||||
if err != nil {
|
||||
log.Error(4, "GetBranchCommitID[%s]: %v", opts.RefFullName, err)
|
||||
log.Error("GetBranchCommitID[%s]: %v", opts.RefFullName, err)
|
||||
}
|
||||
if err = PrepareWebhooks(repo, HookEventCreate, &api.CreatePayload{
|
||||
Ref: refName,
|
||||
@ -697,11 +697,11 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
|
||||
|
||||
gitRepo, err := git.OpenRepository(repo.RepoPath())
|
||||
if err != nil {
|
||||
log.Error(4, "OpenRepository[%s]: %v", repo.RepoPath(), err)
|
||||
log.Error("OpenRepository[%s]: %v", repo.RepoPath(), err)
|
||||
}
|
||||
shaSum, err = gitRepo.GetTagCommitID(refName)
|
||||
if err != nil {
|
||||
log.Error(4, "GetTagCommitID[%s]: %v", opts.RefFullName, err)
|
||||
log.Error("GetTagCommitID[%s]: %v", opts.RefFullName, err)
|
||||
}
|
||||
if err = PrepareWebhooks(repo, HookEventCreate, &api.CreatePayload{
|
||||
Ref: refName,
|
||||
|
@ -65,7 +65,7 @@ func removeAllWithNotice(e Engine, title, path string) {
|
||||
desc := fmt.Sprintf("%s [%s]: %v", title, path, err)
|
||||
log.Warn(desc)
|
||||
if err = createNotice(e, NoticeRepository, desc); err != nil {
|
||||
log.Error(4, "CreateRepositoryNotice: %v", err)
|
||||
log.Error("CreateRepositoryNotice: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ func (protectBranch *ProtectedBranch) CanUserPush(userID int64) bool {
|
||||
|
||||
in, err := IsUserInTeams(userID, protectBranch.WhitelistTeamIDs)
|
||||
if err != nil {
|
||||
log.Error(1, "IsUserInTeams:", err)
|
||||
log.Error("IsUserInTeams: %v", err)
|
||||
return false
|
||||
}
|
||||
return in
|
||||
@ -83,7 +83,7 @@ func (protectBranch *ProtectedBranch) CanUserMerge(userID int64) bool {
|
||||
|
||||
in, err := IsUserInTeams(userID, protectBranch.MergeWhitelistTeamIDs)
|
||||
if err != nil {
|
||||
log.Error(1, "IsUserInTeams:", err)
|
||||
log.Error("IsUserInTeams: %v", err)
|
||||
return false
|
||||
}
|
||||
return in
|
||||
@ -101,7 +101,7 @@ func (protectBranch *ProtectedBranch) HasEnoughApprovals(pr *PullRequest) bool {
|
||||
func (protectBranch *ProtectedBranch) GetGrantedApprovalsCount(pr *PullRequest) int64 {
|
||||
reviews, err := GetReviewersByPullID(pr.Issue.ID)
|
||||
if err != nil {
|
||||
log.Error(1, "GetReviewersByPullID:", err)
|
||||
log.Error("GetReviewersByPullID: %v", err)
|
||||
return 0
|
||||
}
|
||||
|
||||
@ -119,7 +119,7 @@ func (protectBranch *ProtectedBranch) GetGrantedApprovalsCount(pr *PullRequest)
|
||||
}
|
||||
approvalTeamCount, err := UsersInTeamsCount(userIDs, protectBranch.ApprovalsWhitelistTeamIDs)
|
||||
if err != nil {
|
||||
log.Error(1, "UsersInTeamsCount:", err)
|
||||
log.Error("UsersInTeamsCount: %v", err)
|
||||
return 0
|
||||
}
|
||||
return approvalTeamCount + approvals
|
||||
@ -466,6 +466,6 @@ func RemoveOldDeletedBranches() {
|
||||
deleteBefore := time.Now().Add(-setting.Cron.DeletedBranchesCleanup.OlderThan)
|
||||
_, err := x.Where("deleted_unix < ?", deleteBefore.Unix()).Delete(new(DeletedBranch))
|
||||
if err != nil {
|
||||
log.Error(4, "DeletedBranchesCleanup: %v", err)
|
||||
log.Error("DeletedBranchesCleanup: %v", err)
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ func (key *GPGKey) BeforeInsert() {
|
||||
func (key *GPGKey) AfterLoad(session *xorm.Session) {
|
||||
err := session.Where("primary_key_id=?", key.KeyID).Find(&key.SubsKey)
|
||||
if err != nil {
|
||||
log.Error(3, "Find Sub GPGkeys[%d]: %v", key.KeyID, err)
|
||||
log.Error("Find Sub GPGkeys[%s]: %v", key.KeyID, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,7 +364,7 @@ func ParseCommitWithSignature(c *git.Commit) *CommitVerification {
|
||||
//Parsing signature
|
||||
sig, err := extractSignature(c.Signature.Signature)
|
||||
if err != nil { //Skipping failed to extract sign
|
||||
log.Error(3, "SignatureRead err: %v", err)
|
||||
log.Error("SignatureRead err: %v", err)
|
||||
return &CommitVerification{
|
||||
Verified: false,
|
||||
Reason: "gpg.error.extract_sign",
|
||||
@ -377,7 +377,7 @@ func ParseCommitWithSignature(c *git.Commit) *CommitVerification {
|
||||
// We can expect this to often be an ErrUserNotExist. in the case
|
||||
// it is not, however, it is important to log it.
|
||||
if !IsErrUserNotExist(err) {
|
||||
log.Error(3, "GetUserByEmail: %v", err)
|
||||
log.Error("GetUserByEmail: %v", err)
|
||||
}
|
||||
return &CommitVerification{
|
||||
Verified: false,
|
||||
@ -387,7 +387,7 @@ func ParseCommitWithSignature(c *git.Commit) *CommitVerification {
|
||||
|
||||
keys, err := ListGPGKeys(committer.ID)
|
||||
if err != nil { //Skipping failed to get gpg keys of user
|
||||
log.Error(3, "ListGPGKeys: %v", err)
|
||||
log.Error("ListGPGKeys: %v", err)
|
||||
return &CommitVerification{
|
||||
Verified: false,
|
||||
Reason: "gpg.error.failed_retrieval_gpg_keys",
|
||||
@ -411,7 +411,7 @@ func ParseCommitWithSignature(c *git.Commit) *CommitVerification {
|
||||
//Generating hash of commit
|
||||
hash, err := populateHash(sig.Hash, []byte(c.Signature.Payload))
|
||||
if err != nil { //Skipping ailed to generate hash
|
||||
log.Error(3, "PopulateHash: %v", err)
|
||||
log.Error("PopulateHash: %v", err)
|
||||
return &CommitVerification{
|
||||
Verified: false,
|
||||
Reason: "gpg.error.generate_hash",
|
||||
@ -432,7 +432,7 @@ func ParseCommitWithSignature(c *git.Commit) *CommitVerification {
|
||||
//Generating hash of commit
|
||||
hash, err := populateHash(sig.Hash, []byte(c.Signature.Payload))
|
||||
if err != nil { //Skipping ailed to generate hash
|
||||
log.Error(3, "PopulateHash: %v", err)
|
||||
log.Error("PopulateHash: %v", err)
|
||||
return &CommitVerification{
|
||||
Verified: false,
|
||||
Reason: "gpg.error.generate_hash",
|
||||
|
@ -112,7 +112,7 @@ func (issue *Issue) IsTimetrackerEnabled() bool {
|
||||
|
||||
func (issue *Issue) isTimetrackerEnabled(e Engine) bool {
|
||||
if err := issue.loadRepo(e); err != nil {
|
||||
log.Error(4, fmt.Sprintf("loadRepo: %v", err))
|
||||
log.Error(fmt.Sprintf("loadRepo: %v", err))
|
||||
return false
|
||||
}
|
||||
return issue.Repo.IsTimetrackerEnabled()
|
||||
@ -423,23 +423,23 @@ func (issue *Issue) sendLabelUpdatedWebhook(doer *User) {
|
||||
var err error
|
||||
|
||||
if err = issue.loadRepo(x); err != nil {
|
||||
log.Error(4, "loadRepo: %v", err)
|
||||
log.Error("loadRepo: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = issue.loadPoster(x); err != nil {
|
||||
log.Error(4, "loadPoster: %v", err)
|
||||
log.Error("loadPoster: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
mode, _ := AccessLevel(issue.Poster, issue.Repo)
|
||||
if issue.IsPull {
|
||||
if err = issue.loadPullRequest(x); err != nil {
|
||||
log.Error(4, "loadPullRequest: %v", err)
|
||||
log.Error("loadPullRequest: %v", err)
|
||||
return
|
||||
}
|
||||
if err = issue.PullRequest.LoadIssue(); err != nil {
|
||||
log.Error(4, "LoadIssue: %v", err)
|
||||
log.Error("LoadIssue: %v", err)
|
||||
return
|
||||
}
|
||||
err = PrepareWebhooks(issue.Repo, HookEventPullRequest, &api.PullRequestPayload{
|
||||
@ -459,7 +459,7 @@ func (issue *Issue) sendLabelUpdatedWebhook(doer *User) {
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
log.Error(4, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
|
||||
log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
|
||||
} else {
|
||||
go HookQueue.Add(issue.RepoID)
|
||||
}
|
||||
@ -584,7 +584,7 @@ func (issue *Issue) ClearLabels(doer *User) (err error) {
|
||||
if issue.IsPull {
|
||||
err = issue.PullRequest.LoadIssue()
|
||||
if err != nil {
|
||||
log.Error(4, "LoadIssue: %v", err)
|
||||
log.Error("LoadIssue: %v", err)
|
||||
return
|
||||
}
|
||||
err = PrepareWebhooks(issue.Repo, HookEventPullRequest, &api.PullRequestPayload{
|
||||
@ -604,7 +604,7 @@ func (issue *Issue) ClearLabels(doer *User) (err error) {
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
log.Error(4, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
|
||||
log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
|
||||
} else {
|
||||
go HookQueue.Add(issue.RepoID)
|
||||
}
|
||||
@ -819,7 +819,7 @@ func (issue *Issue) ChangeStatus(doer *User, isClosed bool) (err error) {
|
||||
err = PrepareWebhooks(issue.Repo, HookEventIssues, apiIssue)
|
||||
}
|
||||
if err != nil {
|
||||
log.Error(4, "PrepareWebhooks [is_pull: %v, is_closed: %v]: %v", issue.IsPull, isClosed, err)
|
||||
log.Error("PrepareWebhooks [is_pull: %v, is_closed: %v]: %v", issue.IsPull, isClosed, err)
|
||||
} else {
|
||||
go HookQueue.Add(issue.Repo.ID)
|
||||
}
|
||||
@ -888,7 +888,7 @@ func (issue *Issue) ChangeTitle(doer *User, title string) (err error) {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Error(4, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
|
||||
log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
|
||||
} else {
|
||||
go HookQueue.Add(issue.RepoID)
|
||||
}
|
||||
@ -953,7 +953,7 @@ func (issue *Issue) ChangeContent(doer *User, content string) (err error) {
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
log.Error(4, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
|
||||
log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
|
||||
} else {
|
||||
go HookQueue.Add(issue.RepoID)
|
||||
}
|
||||
@ -1169,7 +1169,7 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, assigneeIDs []in
|
||||
Repo: repo,
|
||||
IsPrivate: repo.IsPrivate,
|
||||
}); err != nil {
|
||||
log.Error(4, "NotifyWatchers: %v", err)
|
||||
log.Error("NotifyWatchers: %v", err)
|
||||
}
|
||||
|
||||
mode, _ := AccessLevel(issue.Poster, issue.Repo)
|
||||
@ -1180,7 +1180,7 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, assigneeIDs []in
|
||||
Repository: repo.APIFormat(mode),
|
||||
Sender: issue.Poster.APIFormat(),
|
||||
}); err != nil {
|
||||
log.Error(4, "PrepareWebhooks: %v", err)
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
} else {
|
||||
go HookQueue.Add(issue.RepoID)
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID in
|
||||
apiPullRequest.Action = api.HookIssueAssigned
|
||||
}
|
||||
if err := prepareWebhooks(sess, issue.Repo, HookEventPullRequest, apiPullRequest); err != nil {
|
||||
log.Error(4, "PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
|
||||
log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
@ -205,7 +205,7 @@ func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID in
|
||||
apiIssue.Action = api.HookIssueAssigned
|
||||
}
|
||||
if err := prepareWebhooks(sess, issue.Repo, HookEventIssues, apiIssue); err != nil {
|
||||
log.Error(4, "PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
|
||||
log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -171,12 +171,12 @@ func (c *Comment) AfterDelete() {
|
||||
func (c *Comment) HTMLURL() string {
|
||||
err := c.LoadIssue()
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error(4, "LoadIssue(%d): %v", c.IssueID, err)
|
||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||
return ""
|
||||
}
|
||||
err = c.Issue.loadRepo(x)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error(4, "loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||
return ""
|
||||
}
|
||||
if c.Type == CommentTypeCode {
|
||||
@ -200,7 +200,7 @@ func (c *Comment) HTMLURL() string {
|
||||
func (c *Comment) IssueURL() string {
|
||||
err := c.LoadIssue()
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error(4, "LoadIssue(%d): %v", c.IssueID, err)
|
||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -210,7 +210,7 @@ func (c *Comment) IssueURL() string {
|
||||
|
||||
err = c.Issue.loadRepo(x)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error(4, "loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||
return ""
|
||||
}
|
||||
return c.Issue.HTMLURL()
|
||||
@ -220,13 +220,13 @@ func (c *Comment) IssueURL() string {
|
||||
func (c *Comment) PRURL() string {
|
||||
err := c.LoadIssue()
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error(4, "LoadIssue(%d): %v", c.IssueID, err)
|
||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||
return ""
|
||||
}
|
||||
|
||||
err = c.Issue.loadRepo(x)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error(4, "loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -318,7 +318,7 @@ func (c *Comment) LoadPoster() error {
|
||||
c.PosterID = -1
|
||||
c.Poster = NewGhostUser()
|
||||
} else {
|
||||
log.Error(3, "getUserByID[%d]: %v", c.ID, err)
|
||||
log.Error("getUserByID[%d]: %v", c.ID, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -333,7 +333,7 @@ func (c *Comment) LoadAttachments() error {
|
||||
var err error
|
||||
c.Attachments, err = getAttachmentsByCommentID(x, c.ID)
|
||||
if err != nil {
|
||||
log.Error(3, "getAttachmentsByCommentID[%d]: %v", c.ID, err)
|
||||
log.Error("getAttachmentsByCommentID[%d]: %v", c.ID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -384,7 +384,7 @@ func (c *Comment) mailParticipants(e Engine, opType ActionType, issue *Issue) (e
|
||||
content = fmt.Sprintf("Reopened #%d", issue.Index)
|
||||
}
|
||||
if err = mailIssueCommentToParticipants(e, issue, c.Poster, content, c, mentions); err != nil {
|
||||
log.Error(4, "mailIssueCommentToParticipants: %v", err)
|
||||
log.Error("mailIssueCommentToParticipants: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -492,12 +492,12 @@ func (c *Comment) MustAsDiff() *Diff {
|
||||
func (c *Comment) CodeCommentURL() string {
|
||||
err := c.LoadIssue()
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error(4, "LoadIssue(%d): %v", c.IssueID, err)
|
||||
log.Error("LoadIssue(%d): %v", c.IssueID, err)
|
||||
return ""
|
||||
}
|
||||
err = c.Issue.loadRepo(x)
|
||||
if err != nil { // Silently dropping errors :unamused:
|
||||
log.Error(4, "loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
|
||||
@ -638,7 +638,7 @@ func sendCreateCommentAction(e *xorm.Session, opts *CreateCommentOptions, commen
|
||||
// Notify watchers for whatever action comes in, ignore if no action type.
|
||||
if act.OpType > 0 {
|
||||
if err = notifyWatchers(e, act); err != nil {
|
||||
log.Error(4, "notifyWatchers: %v", err)
|
||||
log.Error("notifyWatchers: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -850,7 +850,7 @@ func CreateIssueComment(doer *User, repo *Repository, issue *Issue, content stri
|
||||
Repository: repo.APIFormat(mode),
|
||||
Sender: doer.APIFormat(),
|
||||
}); err != nil {
|
||||
log.Error(2, "PrepareWebhooks [comment_id: %d]: %v", comment.ID, err)
|
||||
log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err)
|
||||
} else {
|
||||
go HookQueue.Add(repo.ID)
|
||||
}
|
||||
@ -1053,7 +1053,7 @@ func UpdateComment(doer *User, c *Comment, oldContent string) error {
|
||||
Repository: c.Issue.Repo.APIFormat(mode),
|
||||
Sender: doer.APIFormat(),
|
||||
}); err != nil {
|
||||
log.Error(2, "PrepareWebhooks [comment_id: %d]: %v", c.ID, err)
|
||||
log.Error("PrepareWebhooks [comment_id: %d]: %v", c.ID, err)
|
||||
} else {
|
||||
go HookQueue.Add(c.Issue.Repo.ID)
|
||||
}
|
||||
@ -1108,7 +1108,7 @@ func DeleteComment(doer *User, comment *Comment) error {
|
||||
Repository: comment.Issue.Repo.APIFormat(mode),
|
||||
Sender: doer.APIFormat(),
|
||||
}); err != nil {
|
||||
log.Error(2, "PrepareWebhooks [comment_id: %d]: %v", comment.ID, err)
|
||||
log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err)
|
||||
} else {
|
||||
go HookQueue.Add(comment.Issue.Repo.ID)
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ func (issue *Issue) mailParticipants(e Engine) (err error) {
|
||||
}
|
||||
|
||||
if err = mailIssueCommentToParticipants(e, issue, issue.Poster, issue.Content, nil, mentions); err != nil {
|
||||
log.Error(4, "mailIssueCommentToParticipants: %v", err)
|
||||
log.Error("mailIssueCommentToParticipants: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -393,7 +393,7 @@ func ChangeMilestoneAssign(issue *Issue, doer *User, oldMilestoneID int64) (err
|
||||
if issue.IsPull {
|
||||
err = issue.PullRequest.LoadIssue()
|
||||
if err != nil {
|
||||
log.Error(2, "LoadIssue: %v", err)
|
||||
log.Error("LoadIssue: %v", err)
|
||||
return
|
||||
}
|
||||
err = PrepareWebhooks(issue.Repo, HookEventPullRequest, &api.PullRequestPayload{
|
||||
@ -413,7 +413,7 @@ func ChangeMilestoneAssign(issue *Issue, doer *User, oldMilestoneID int64) (err
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
log.Error(2, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
|
||||
log.Error("PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
|
||||
} else {
|
||||
go HookQueue.Add(issue.RepoID)
|
||||
}
|
||||
|
@ -39,11 +39,11 @@ func (l *LFSLock) AfterLoad(session *xorm.Session) {
|
||||
var err error
|
||||
l.Owner, err = getUserByID(session, l.OwnerID)
|
||||
if err != nil {
|
||||
log.Error(2, "LFS lock AfterLoad failed OwnerId[%d] not found: %v", l.OwnerID, err)
|
||||
log.Error("LFS lock AfterLoad failed OwnerId[%d] not found: %v", l.OwnerID, err)
|
||||
}
|
||||
l.Repo, err = getRepositoryByID(session, l.RepoID)
|
||||
if err != nil {
|
||||
log.Error(2, "LFS lock AfterLoad failed RepoId[%d] not found: %v", l.RepoID, err)
|
||||
log.Error("LFS lock AfterLoad failed RepoId[%d] not found: %v", l.RepoID, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ func SendUserMail(c *macaron.Context, u *User, tpl base.TplName, code, subject,
|
||||
var content bytes.Buffer
|
||||
|
||||
if err := templates.ExecuteTemplate(&content, string(tpl), data); err != nil {
|
||||
log.Error(3, "Template: %v", err)
|
||||
log.Error("Template: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@ func SendActivateEmailMail(c *macaron.Context, u *User, email *EmailAddress) {
|
||||
var content bytes.Buffer
|
||||
|
||||
if err := templates.ExecuteTemplate(&content, string(mailAuthActivateEmail), data); err != nil {
|
||||
log.Error(3, "Template: %v", err)
|
||||
log.Error("Template: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ func SendRegisterNotifyMail(c *macaron.Context, u *User) {
|
||||
var content bytes.Buffer
|
||||
|
||||
if err := templates.ExecuteTemplate(&content, string(mailAuthRegisterNotify), data); err != nil {
|
||||
log.Error(3, "Template: %v", err)
|
||||
log.Error("Template: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -131,7 +131,7 @@ func SendCollaboratorMail(u, doer *User, repo *Repository) {
|
||||
var content bytes.Buffer
|
||||
|
||||
if err := templates.ExecuteTemplate(&content, string(mailNotifyCollaborator), data); err != nil {
|
||||
log.Error(3, "Template: %v", err)
|
||||
log.Error("Template: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -165,7 +165,7 @@ func composeIssueCommentMessage(issue *Issue, doer *User, content string, commen
|
||||
var mailBody bytes.Buffer
|
||||
|
||||
if err := templates.ExecuteTemplate(&mailBody, string(tplName), data); err != nil {
|
||||
log.Error(3, "Template: %v", err)
|
||||
log.Error("Template: %v", err)
|
||||
}
|
||||
|
||||
msg := mailer.NewMessageFrom(tos, doer.DisplayName(), setting.MailService.FromEmail, subject, mailBody.String())
|
||||
|
@ -244,7 +244,7 @@ func Migrate(x *xorm.Engine) error {
|
||||
|
||||
v := currentVersion.Version
|
||||
if minDBVersion > v {
|
||||
log.Fatal(4, `Gitea no longer supports auto-migration from your previously installed version.
|
||||
log.Fatal(`Gitea no longer supports auto-migration from your previously installed version.
|
||||
Please try to upgrade to a lower version (>= v0.6.0) first, then upgrade to current version.`)
|
||||
return nil
|
||||
}
|
||||
@ -315,7 +315,7 @@ func dropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin
|
||||
|
||||
return sess.Commit()
|
||||
default:
|
||||
log.Fatal(4, "Unrecognized DB")
|
||||
log.Fatal("Unrecognized DB")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -26,7 +26,7 @@ func removeActionColumns(x *xorm.Engine) error {
|
||||
return fmt.Errorf("DROP COLUMN repo_name: %v", err)
|
||||
}
|
||||
default:
|
||||
log.Fatal(4, "Unrecognized DB")
|
||||
log.Fatal("Unrecognized DB")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ func removeIndexColumnFromRepoUnitTable(x *xorm.Engine) (err error) {
|
||||
log.Warn("DROP COLUMN index: %v", err)
|
||||
}
|
||||
default:
|
||||
log.Fatal(4, "Unrecognized DB")
|
||||
log.Fatal("Unrecognized DB")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -48,7 +48,7 @@ func migrateProtectedBranchStruct(x *xorm.Engine) error {
|
||||
log.Warn("DROP COLUMN can_push (skipping): %v", err)
|
||||
}
|
||||
default:
|
||||
log.Fatal(4, "Unrecognized DB")
|
||||
log.Fatal("Unrecognized DB")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -33,7 +33,7 @@ func addSizeToAttachment(x *xorm.Engine) error {
|
||||
localPath := path.Join(setting.AttachmentPath, attach.UUID[0:1], attach.UUID[1:2], attach.UUID)
|
||||
fi, err := os.Stat(localPath)
|
||||
if err != nil {
|
||||
log.Error(4, "calculate file size of attachment[UUID: %s]: %v", attach.UUID, err)
|
||||
log.Error("calculate file size of attachment[UUID: %s]: %v", attach.UUID, err)
|
||||
continue
|
||||
}
|
||||
attach.Size = fi.Size()
|
||||
|
@ -303,7 +303,7 @@ func isOrganizationOwner(e Engine, orgID, uid int64) (bool, error) {
|
||||
if has, err := e.Get(ownerTeam); err != nil {
|
||||
return false, err
|
||||
} else if !has {
|
||||
log.Error(4, "Organization does not have owner team: %d", orgID)
|
||||
log.Error("Organization does not have owner team: %d", orgID)
|
||||
return false, nil
|
||||
}
|
||||
return isTeamMember(e, orgID, ownerTeam.ID, uid)
|
||||
|
@ -69,7 +69,7 @@ func (t *Team) IsOwnerTeam() bool {
|
||||
func (t *Team) IsMember(userID int64) bool {
|
||||
isMember, err := IsTeamMember(t.OrgID, t.ID, userID)
|
||||
if err != nil {
|
||||
log.Error(4, "IsMember: %v", err)
|
||||
log.Error("IsMember: %v", err)
|
||||
return false
|
||||
}
|
||||
return isMember
|
||||
|
@ -135,7 +135,7 @@ func (pr *PullRequest) GetDefaultMergeMessage() string {
|
||||
var err error
|
||||
pr.HeadRepo, err = GetRepositoryByID(pr.HeadRepoID)
|
||||
if err != nil {
|
||||
log.Error(4, "GetRepositoryById[%d]: %v", pr.HeadRepoID, err)
|
||||
log.Error("GetRepositoryById[%d]: %v", pr.HeadRepoID, err)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
@ -145,7 +145,7 @@ func (pr *PullRequest) GetDefaultMergeMessage() string {
|
||||
// GetDefaultSquashMessage returns default message used when squash and merging pull request
|
||||
func (pr *PullRequest) GetDefaultSquashMessage() string {
|
||||
if err := pr.LoadIssue(); err != nil {
|
||||
log.Error(4, "LoadIssue: %v", err)
|
||||
log.Error("LoadIssue: %v", err)
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%s (#%d)", pr.Issue.Title, pr.Issue.Index)
|
||||
@ -172,21 +172,21 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
|
||||
err error
|
||||
)
|
||||
if err = pr.Issue.loadRepo(e); err != nil {
|
||||
log.Error(log.ERROR, "loadRepo[%d]: %v", pr.ID, err)
|
||||
log.Error("loadRepo[%d]: %v", pr.ID, err)
|
||||
return nil
|
||||
}
|
||||
apiIssue := pr.Issue.apiFormat(e)
|
||||
if pr.BaseRepo == nil {
|
||||
pr.BaseRepo, err = getRepositoryByID(e, pr.BaseRepoID)
|
||||
if err != nil {
|
||||
log.Error(log.ERROR, "GetRepositoryById[%d]: %v", pr.ID, err)
|
||||
log.Error("GetRepositoryById[%d]: %v", pr.ID, err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if pr.HeadRepo == nil {
|
||||
pr.HeadRepo, err = getRepositoryByID(e, pr.HeadRepoID)
|
||||
if err != nil {
|
||||
log.Error(log.ERROR, "GetRepositoryById[%d]: %v", pr.ID, err)
|
||||
log.Error("GetRepositoryById[%d]: %v", pr.ID, err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -581,11 +581,11 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
|
||||
pr.MergerID = doer.ID
|
||||
|
||||
if err = pr.setMerged(); err != nil {
|
||||
log.Error(4, "setMerged [%d]: %v", pr.ID, err)
|
||||
log.Error("setMerged [%d]: %v", pr.ID, err)
|
||||
}
|
||||
|
||||
if err = MergePullRequestAction(doer, pr.Issue.Repo, pr.Issue); err != nil {
|
||||
log.Error(4, "MergePullRequestAction [%d]: %v", pr.ID, err)
|
||||
log.Error("MergePullRequestAction [%d]: %v", pr.ID, err)
|
||||
}
|
||||
|
||||
// Reset cached commit count
|
||||
@ -593,7 +593,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
|
||||
|
||||
// Reload pull request information.
|
||||
if err = pr.LoadAttributes(); err != nil {
|
||||
log.Error(4, "LoadAttributes: %v", err)
|
||||
log.Error("LoadAttributes: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -605,14 +605,14 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
|
||||
Repository: pr.Issue.Repo.APIFormat(mode),
|
||||
Sender: doer.APIFormat(),
|
||||
}); err != nil {
|
||||
log.Error(4, "PrepareWebhooks: %v", err)
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
} else {
|
||||
go HookQueue.Add(pr.Issue.Repo.ID)
|
||||
}
|
||||
|
||||
l, err := baseGitRepo.CommitsBetweenIDs(pr.MergedCommitID, pr.MergeBase)
|
||||
if err != nil {
|
||||
log.Error(4, "CommitsBetweenIDs: %v", err)
|
||||
log.Error("CommitsBetweenIDs: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -621,7 +621,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
|
||||
// to avoid strange diff commits produced.
|
||||
mergeCommit, err := baseGitRepo.GetBranchCommit(pr.BaseBranch)
|
||||
if err != nil {
|
||||
log.Error(4, "GetBranchCommit: %v", err)
|
||||
log.Error("GetBranchCommit: %v", err)
|
||||
return nil
|
||||
}
|
||||
if mergeStyle == MergeStyleMerge {
|
||||
@ -639,7 +639,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
|
||||
Sender: doer.APIFormat(),
|
||||
}
|
||||
if err = PrepareWebhooks(pr.BaseRepo, HookEventPush, p); err != nil {
|
||||
log.Error(4, "PrepareWebhooks: %v", err)
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
} else {
|
||||
go HookQueue.Add(pr.BaseRepo.ID)
|
||||
}
|
||||
@ -692,7 +692,7 @@ func (pr *PullRequest) setMerged() (err error) {
|
||||
func (pr *PullRequest) manuallyMerged() bool {
|
||||
commit, err := pr.getMergeCommit()
|
||||
if err != nil {
|
||||
log.Error(4, "PullRequest[%d].getMergeCommit: %v", pr.ID, err)
|
||||
log.Error("PullRequest[%d].getMergeCommit: %v", pr.ID, err)
|
||||
return false
|
||||
}
|
||||
if commit != nil {
|
||||
@ -705,7 +705,7 @@ func (pr *PullRequest) manuallyMerged() bool {
|
||||
if merger == nil {
|
||||
if pr.BaseRepo.Owner == nil {
|
||||
if err = pr.BaseRepo.getOwner(x); err != nil {
|
||||
log.Error(4, "BaseRepo.getOwner[%d]: %v", pr.ID, err)
|
||||
log.Error("BaseRepo.getOwner[%d]: %v", pr.ID, err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -715,7 +715,7 @@ func (pr *PullRequest) manuallyMerged() bool {
|
||||
pr.MergerID = merger.ID
|
||||
|
||||
if err = pr.setMerged(); err != nil {
|
||||
log.Error(4, "PullRequest[%d].setMerged : %v", pr.ID, err)
|
||||
log.Error("PullRequest[%d].setMerged : %v", pr.ID, err)
|
||||
return false
|
||||
}
|
||||
log.Info("manuallyMerged[%d]: Marked as manually merged into %s/%s by commit id: %s", pr.ID, pr.BaseRepo.Name, pr.BaseBranch, commit.ID.String())
|
||||
@ -936,7 +936,7 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
|
||||
Repo: repo,
|
||||
IsPrivate: repo.IsPrivate,
|
||||
}); err != nil {
|
||||
log.Error(4, "NotifyWatchers: %v", err)
|
||||
log.Error("NotifyWatchers: %v", err)
|
||||
}
|
||||
|
||||
pr.Issue = pull
|
||||
@ -949,7 +949,7 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
|
||||
Repository: repo.APIFormat(mode),
|
||||
Sender: pull.Poster.APIFormat(),
|
||||
}); err != nil {
|
||||
log.Error(4, "PrepareWebhooks: %v", err)
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
} else {
|
||||
go HookQueue.Add(repo.ID)
|
||||
}
|
||||
@ -997,12 +997,12 @@ func PullRequests(baseRepoID int64, opts *PullRequestsOptions) ([]*PullRequest,
|
||||
|
||||
countSession, err := listPullRequestStatement(baseRepoID, opts)
|
||||
if err != nil {
|
||||
log.Error(4, "listPullRequestStatement", err)
|
||||
log.Error("listPullRequestStatement: %v", err)
|
||||
return nil, 0, err
|
||||
}
|
||||
maxResults, err := countSession.Count(new(PullRequest))
|
||||
if err != nil {
|
||||
log.Error(4, "Count PRs", err)
|
||||
log.Error("Count PRs: %v", err)
|
||||
return nil, maxResults, err
|
||||
}
|
||||
|
||||
@ -1010,7 +1010,7 @@ func PullRequests(baseRepoID int64, opts *PullRequestsOptions) ([]*PullRequest,
|
||||
findSession, err := listPullRequestStatement(baseRepoID, opts)
|
||||
sortIssuesSession(findSession, opts.SortType)
|
||||
if err != nil {
|
||||
log.Error(4, "listPullRequestStatement", err)
|
||||
log.Error("listPullRequestStatement: %v", err)
|
||||
return nil, maxResults, err
|
||||
}
|
||||
findSession.Limit(ItemsPerPage, (opts.Page-1)*ItemsPerPage)
|
||||
@ -1215,7 +1215,7 @@ func (pr *PullRequest) AddToTaskQueue() {
|
||||
go pullRequestQueue.AddFunc(pr.ID, func() {
|
||||
pr.Status = PullRequestStatusChecking
|
||||
if err := pr.UpdateCols("status"); err != nil {
|
||||
log.Error(5, "AddToTaskQueue.UpdateCols[%d].(add to queue): %v", pr.ID, err)
|
||||
log.Error("AddToTaskQueue.UpdateCols[%d].(add to queue): %v", pr.ID, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -1290,10 +1290,10 @@ func addHeadRepoTasks(prs []*PullRequest) {
|
||||
for _, pr := range prs {
|
||||
log.Trace("addHeadRepoTasks[%d]: composing new test task", pr.ID)
|
||||
if err := pr.UpdatePatch(); err != nil {
|
||||
log.Error(4, "UpdatePatch: %v", err)
|
||||
log.Error("UpdatePatch: %v", err)
|
||||
continue
|
||||
} else if err := pr.PushToBaseRepo(); err != nil {
|
||||
log.Error(4, "PushToBaseRepo: %v", err)
|
||||
log.Error("PushToBaseRepo: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -1307,23 +1307,23 @@ func AddTestPullRequestTask(doer *User, repoID int64, branch string, isSync bool
|
||||
log.Trace("AddTestPullRequestTask [head_repo_id: %d, head_branch: %s]: finding pull requests", repoID, branch)
|
||||
prs, err := GetUnmergedPullRequestsByHeadInfo(repoID, branch)
|
||||
if err != nil {
|
||||
log.Error(4, "Find pull requests [head_repo_id: %d, head_branch: %s]: %v", repoID, branch, err)
|
||||
log.Error("Find pull requests [head_repo_id: %d, head_branch: %s]: %v", repoID, branch, err)
|
||||
return
|
||||
}
|
||||
|
||||
if isSync {
|
||||
requests := PullRequestList(prs)
|
||||
if err = requests.LoadAttributes(); err != nil {
|
||||
log.Error(4, "PullRequestList.LoadAttributes: %v", err)
|
||||
log.Error("PullRequestList.LoadAttributes: %v", err)
|
||||
}
|
||||
if invalidationErr := checkForInvalidation(requests, repoID, doer, branch); invalidationErr != nil {
|
||||
log.Error(4, "checkForInvalidation: %v", invalidationErr)
|
||||
log.Error("checkForInvalidation: %v", invalidationErr)
|
||||
}
|
||||
if err == nil {
|
||||
for _, pr := range prs {
|
||||
pr.Issue.PullRequest = pr
|
||||
if err = pr.Issue.LoadAttributes(); err != nil {
|
||||
log.Error(4, "LoadAttributes: %v", err)
|
||||
log.Error("LoadAttributes: %v", err)
|
||||
continue
|
||||
}
|
||||
if err = PrepareWebhooks(pr.Issue.Repo, HookEventPullRequest, &api.PullRequestPayload{
|
||||
@ -1333,7 +1333,7 @@ func AddTestPullRequestTask(doer *User, repoID int64, branch string, isSync bool
|
||||
Repository: pr.Issue.Repo.APIFormat(AccessModeNone),
|
||||
Sender: doer.APIFormat(),
|
||||
}); err != nil {
|
||||
log.Error(4, "PrepareWebhooks [pull_id: %v]: %v", pr.ID, err)
|
||||
log.Error("PrepareWebhooks [pull_id: %v]: %v", pr.ID, err)
|
||||
continue
|
||||
}
|
||||
go HookQueue.Add(pr.Issue.Repo.ID)
|
||||
@ -1347,7 +1347,7 @@ func AddTestPullRequestTask(doer *User, repoID int64, branch string, isSync bool
|
||||
log.Trace("AddTestPullRequestTask [base_repo_id: %d, base_branch: %s]: finding pull requests", repoID, branch)
|
||||
prs, err = GetUnmergedPullRequestsByBaseInfo(repoID, branch)
|
||||
if err != nil {
|
||||
log.Error(4, "Find pull requests [base_repo_id: %d, base_branch: %s]: %v", repoID, branch, err)
|
||||
log.Error("Find pull requests [base_repo_id: %d, base_branch: %s]: %v", repoID, branch, err)
|
||||
return
|
||||
}
|
||||
for _, pr := range prs {
|
||||
@ -1367,7 +1367,7 @@ func checkForInvalidation(requests PullRequestList, repoID int64, doer *User, br
|
||||
go func() {
|
||||
err := requests.InvalidateCodeComments(doer, gitRepo, branch)
|
||||
if err != nil {
|
||||
log.Error(4, "PullRequestList.InvalidateCodeComments: %v", err)
|
||||
log.Error("PullRequestList.InvalidateCodeComments: %v", err)
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
@ -1396,7 +1396,7 @@ func (pr *PullRequest) checkAndUpdateStatus() {
|
||||
// Make sure there is no waiting test to process before leaving the checking status.
|
||||
if !pullRequestQueue.Exist(pr.ID) {
|
||||
if err := pr.UpdateCols("status, conflicted_files"); err != nil {
|
||||
log.Error(4, "Update[%d]: %v", pr.ID, err)
|
||||
log.Error("Update[%d]: %v", pr.ID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1404,7 +1404,7 @@ func (pr *PullRequest) checkAndUpdateStatus() {
|
||||
// IsWorkInProgress determine if the Pull Request is a Work In Progress by its title
|
||||
func (pr *PullRequest) IsWorkInProgress() bool {
|
||||
if err := pr.LoadIssue(); err != nil {
|
||||
log.Error(4, "LoadIssue: %v", err)
|
||||
log.Error("LoadIssue: %v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
@ -1425,7 +1425,7 @@ func (pr *PullRequest) IsFilesConflicted() bool {
|
||||
// It returns an empty string when none were found
|
||||
func (pr *PullRequest) GetWorkInProgressPrefix() string {
|
||||
if err := pr.LoadIssue(); err != nil {
|
||||
log.Error(4, "LoadIssue: %v", err)
|
||||
log.Error("LoadIssue: %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -1444,7 +1444,7 @@ func TestPullRequests() {
|
||||
|
||||
err := x.Where("status = ?", PullRequestStatusChecking).Find(&prs)
|
||||
if err != nil {
|
||||
log.Error(3, "Find Checking PRs", err)
|
||||
log.Error("Find Checking PRs: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -1454,14 +1454,14 @@ func TestPullRequests() {
|
||||
for _, pr := range prs {
|
||||
checkedPRs[pr.ID] = struct{}{}
|
||||
if err := pr.GetBaseRepo(); err != nil {
|
||||
log.Error(3, "GetBaseRepo: %v", err)
|
||||
log.Error("GetBaseRepo: %v", err)
|
||||
continue
|
||||
}
|
||||
if pr.manuallyMerged() {
|
||||
continue
|
||||
}
|
||||
if err := pr.testPatch(x); err != nil {
|
||||
log.Error(3, "testPatch: %v", err)
|
||||
log.Error("testPatch: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -1480,12 +1480,12 @@ func TestPullRequests() {
|
||||
|
||||
pr, err := GetPullRequestByID(id)
|
||||
if err != nil {
|
||||
log.Error(4, "GetPullRequestByID[%s]: %v", prID, err)
|
||||
log.Error("GetPullRequestByID[%s]: %v", prID, err)
|
||||
continue
|
||||
} else if pr.manuallyMerged() {
|
||||
continue
|
||||
} else if err = pr.testPatch(x); err != nil {
|
||||
log.Error(4, "testPatch[%d]: %v", pr.ID, err)
|
||||
log.Error("testPatch[%d]: %v", pr.ID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -199,7 +199,7 @@ func CreateRelease(gitRepo *git.Repository, rel *Release, attachmentUUIDs []stri
|
||||
|
||||
if !rel.IsDraft {
|
||||
if err := rel.LoadAttributes(); err != nil {
|
||||
log.Error(2, "LoadAttributes: %v", err)
|
||||
log.Error("LoadAttributes: %v", err)
|
||||
} else {
|
||||
mode, _ := AccessLevel(rel.Publisher, rel.Repo)
|
||||
if err := PrepareWebhooks(rel.Repo, HookEventRelease, &api.ReleasePayload{
|
||||
@ -208,7 +208,7 @@ func CreateRelease(gitRepo *git.Repository, rel *Release, attachmentUUIDs []stri
|
||||
Repository: rel.Repo.APIFormat(mode),
|
||||
Sender: rel.Publisher.APIFormat(),
|
||||
}); err != nil {
|
||||
log.Error(2, "PrepareWebhooks: %v", err)
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
} else {
|
||||
go HookQueue.Add(rel.Repo.ID)
|
||||
}
|
||||
@ -409,7 +409,7 @@ func UpdateRelease(doer *User, gitRepo *git.Repository, rel *Release, attachment
|
||||
Repository: rel.Repo.APIFormat(mode),
|
||||
Sender: rel.Publisher.APIFormat(),
|
||||
}); err1 != nil {
|
||||
log.Error(2, "PrepareWebhooks: %v", err)
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
} else {
|
||||
go HookQueue.Add(rel.Repo.ID)
|
||||
}
|
||||
@ -464,7 +464,7 @@ func DeleteReleaseByID(id int64, u *User, delTag bool) error {
|
||||
Repository: rel.Repo.APIFormat(mode),
|
||||
Sender: rel.Publisher.APIFormat(),
|
||||
}); err != nil {
|
||||
log.Error(2, "PrepareWebhooks: %v", err)
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
} else {
|
||||
go HookQueue.Add(rel.Repo.ID)
|
||||
}
|
||||
|
@ -74,13 +74,13 @@ func LoadRepoConfig() {
|
||||
for i, t := range types {
|
||||
files, err := options.Dir(t)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to get %s files: %v", t, err)
|
||||
log.Fatal("Failed to get %s files: %v", t, err)
|
||||
}
|
||||
customPath := path.Join(setting.CustomPath, "options", t)
|
||||
if com.IsDir(customPath) {
|
||||
customFiles, err := com.StatDir(customPath)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to get custom %s files: %v", t, err)
|
||||
log.Fatal("Failed to get custom %s files: %v", t, err)
|
||||
}
|
||||
|
||||
for _, f := range customFiles {
|
||||
@ -122,19 +122,19 @@ func NewRepoContext() {
|
||||
|
||||
// Check Git installation.
|
||||
if _, err := exec.LookPath("git"); err != nil {
|
||||
log.Fatal(4, "Failed to test 'git' command: %v (forgotten install?)", err)
|
||||
log.Fatal("Failed to test 'git' command: %v (forgotten install?)", err)
|
||||
}
|
||||
|
||||
// Check Git version.
|
||||
var err error
|
||||
setting.Git.Version, err = git.BinVersion()
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to get Git version: %v", err)
|
||||
log.Fatal("Failed to get Git version: %v", err)
|
||||
}
|
||||
|
||||
log.Info("Git Version: %s", setting.Git.Version)
|
||||
if version.Compare("1.7.1", setting.Git.Version, ">") {
|
||||
log.Fatal(4, "Gitea requires Git version greater or equal to 1.7.1")
|
||||
log.Fatal("Gitea requires Git version greater or equal to 1.7.1")
|
||||
}
|
||||
|
||||
// Git requires setting user.name and user.email in order to commit changes.
|
||||
@ -143,11 +143,11 @@ func NewRepoContext() {
|
||||
// ExitError indicates this config is not set
|
||||
if _, ok := err.(*exec.ExitError); ok || strings.TrimSpace(stdout) == "" {
|
||||
if _, stderr, gerr := process.GetManager().Exec("NewRepoContext(set "+configKey+")", "git", "config", "--global", configKey, defaultValue); gerr != nil {
|
||||
log.Fatal(4, "Failed to set git %s(%s): %s", configKey, gerr, stderr)
|
||||
log.Fatal("Failed to set git %s(%s): %s", configKey, gerr, stderr)
|
||||
}
|
||||
log.Info("Git config %s set to %s", configKey, defaultValue)
|
||||
} else {
|
||||
log.Fatal(4, "Failed to get git %s(%s): %s", configKey, err, stderr)
|
||||
log.Fatal("Failed to get git %s(%s): %s", configKey, err, stderr)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -155,7 +155,7 @@ func NewRepoContext() {
|
||||
// Set git some configurations.
|
||||
if _, stderr, err := process.GetManager().Exec("NewRepoContext(git config --global core.quotepath false)",
|
||||
"git", "config", "--global", "core.quotepath", "false"); err != nil {
|
||||
log.Fatal(4, "Failed to execute 'git config --global core.quotepath false': %s", stderr)
|
||||
log.Fatal("Failed to execute 'git config --global core.quotepath false': %s", stderr)
|
||||
}
|
||||
|
||||
RemoveAllWithNotice("Clean up repository temporary data", filepath.Join(setting.AppDataPath, "tmp"))
|
||||
@ -281,7 +281,7 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool)
|
||||
if !isParent {
|
||||
err := repo.getBaseRepo(e)
|
||||
if err != nil {
|
||||
log.Error(4, "APIFormat: %v", err)
|
||||
log.Error("APIFormat: %v", err)
|
||||
}
|
||||
if repo.BaseRepo != nil {
|
||||
parent = repo.BaseRepo.innerAPIFormat(e, mode, true)
|
||||
@ -462,7 +462,7 @@ func (repo *Repository) GetOwnerName() error {
|
||||
|
||||
func (repo *Repository) mustOwnerName(e Engine) string {
|
||||
if err := repo.getOwnerName(e); err != nil {
|
||||
log.Error(4, "Error loading repository owner name: %v", err)
|
||||
log.Error("Error loading repository owner name: %v", err)
|
||||
return "error"
|
||||
}
|
||||
|
||||
@ -724,7 +724,7 @@ var (
|
||||
func (repo *Repository) DescriptionHTML() template.HTML {
|
||||
desc, err := markup.RenderDescriptionHTML([]byte(repo.Description), repo.HTMLURL(), repo.ComposeMetas())
|
||||
if err != nil {
|
||||
log.Error(4, "Failed to render description for %s (ID: %d): %v", repo.Name, repo.ID, err)
|
||||
log.Error("Failed to render description for %s (ID: %d): %v", repo.Name, repo.ID, err)
|
||||
return template.HTML(markup.Sanitize(repo.Description))
|
||||
}
|
||||
return template.HTML(markup.Sanitize(string(desc)))
|
||||
@ -981,12 +981,12 @@ func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, err
|
||||
}
|
||||
|
||||
if err = SyncReleasesWithTags(repo, gitRepo); err != nil {
|
||||
log.Error(4, "Failed to synchronize tags to releases for repository: %v", err)
|
||||
log.Error("Failed to synchronize tags to releases for repository: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = repo.UpdateSize(); err != nil {
|
||||
log.Error(4, "Failed to update size for repository: %v", err)
|
||||
log.Error("Failed to update size for repository: %v", err)
|
||||
}
|
||||
|
||||
if opts.IsMirror {
|
||||
@ -1405,7 +1405,7 @@ func CreateRepository(doer, u *User, opts CreateRepoOptions) (_ *Repository, err
|
||||
repoPath := RepoPath(u.Name, repo.Name)
|
||||
if err = initRepository(sess, repoPath, u, repo, opts); err != nil {
|
||||
if err2 := os.RemoveAll(repoPath); err2 != nil {
|
||||
log.Error(4, "initRepository: %v", err)
|
||||
log.Error("initRepository: %v", err)
|
||||
return nil, fmt.Errorf(
|
||||
"delete repo directory %s/%s failed(2): %v", u.Name, repo.Name, err2)
|
||||
}
|
||||
@ -1435,7 +1435,7 @@ func countRepositories(userID int64, private bool) int64 {
|
||||
|
||||
count, err := sess.Count(new(Repository))
|
||||
if err != nil {
|
||||
log.Error(4, "countRepositories: %v", err)
|
||||
log.Error("countRepositories: %v", err)
|
||||
}
|
||||
return count
|
||||
}
|
||||
@ -1690,11 +1690,11 @@ func updateRepository(e Engine, repo *Repository, visibilityChanged bool) (err e
|
||||
daemonExportFile := path.Join(repo.repoPath(e), `git-daemon-export-ok`)
|
||||
if repo.IsPrivate && com.IsExist(daemonExportFile) {
|
||||
if err = os.Remove(daemonExportFile); err != nil {
|
||||
log.Error(4, "Failed to remove %s: %v", daemonExportFile, err)
|
||||
log.Error("Failed to remove %s: %v", daemonExportFile, err)
|
||||
}
|
||||
} else if !repo.IsPrivate && !com.IsExist(daemonExportFile) {
|
||||
if f, err := os.Create(daemonExportFile); err != nil {
|
||||
log.Error(4, "Failed to create %s: %v", daemonExportFile, err)
|
||||
log.Error("Failed to create %s: %v", daemonExportFile, err)
|
||||
} else {
|
||||
f.Close()
|
||||
}
|
||||
@ -1712,7 +1712,7 @@ func updateRepository(e Engine, repo *Repository, visibilityChanged bool) (err e
|
||||
}
|
||||
|
||||
if err = repo.updateSize(e); err != nil {
|
||||
log.Error(4, "Failed to update size for repository: %v", err)
|
||||
log.Error("Failed to update size for repository: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1928,7 +1928,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
|
||||
|
||||
if repo.NumForks > 0 {
|
||||
if _, err = sess.Exec("UPDATE `repository` SET fork_id=0,is_fork=? WHERE fork_id=?", false, repo.ID); err != nil {
|
||||
log.Error(4, "reset 'fork_id' and 'is_fork': %v", err)
|
||||
log.Error("reset 'fork_id' and 'is_fork': %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2090,7 +2090,7 @@ func DeleteOldRepositoryArchives() {
|
||||
log.Trace("Doing: ArchiveCleanup")
|
||||
|
||||
if err := x.Where("id > 0").Iterate(new(Repository), deleteOldRepositoryArchives); err != nil {
|
||||
log.Error(4, "ArchiveClean: %v", err)
|
||||
log.Error("ArchiveClean: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2243,12 +2243,12 @@ func GitFsck() {
|
||||
desc := fmt.Sprintf("Failed to health check repository (%s): %v", repoPath, err)
|
||||
log.Warn(desc)
|
||||
if err = CreateRepositoryNotice(desc); err != nil {
|
||||
log.Error(4, "CreateRepositoryNotice: %v", err)
|
||||
log.Error("CreateRepositoryNotice: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Error(4, "GitFsck: %v", err)
|
||||
log.Error("GitFsck: %v", err)
|
||||
}
|
||||
log.Trace("Finished: GitFsck")
|
||||
}
|
||||
@ -2283,7 +2283,7 @@ type repoChecker struct {
|
||||
func repoStatsCheck(checker *repoChecker) {
|
||||
results, err := x.Query(checker.querySQL)
|
||||
if err != nil {
|
||||
log.Error(4, "Select %s: %v", checker.desc, err)
|
||||
log.Error("Select %s: %v", checker.desc, err)
|
||||
return
|
||||
}
|
||||
for _, result := range results {
|
||||
@ -2291,7 +2291,7 @@ func repoStatsCheck(checker *repoChecker) {
|
||||
log.Trace("Updating %s: %d", checker.desc, id)
|
||||
_, err = x.Exec(checker.correctSQL, id, id)
|
||||
if err != nil {
|
||||
log.Error(4, "Update %s[%d]: %v", checker.desc, id, err)
|
||||
log.Error("Update %s[%d]: %v", checker.desc, id, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2345,14 +2345,14 @@ func CheckRepoStats() {
|
||||
desc := "repository count 'num_closed_issues'"
|
||||
results, err := x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_closed_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", true, false)
|
||||
if err != nil {
|
||||
log.Error(4, "Select %s: %v", desc, err)
|
||||
log.Error("Select %s: %v", desc, err)
|
||||
} else {
|
||||
for _, result := range results {
|
||||
id := com.StrTo(result["id"]).MustInt64()
|
||||
log.Trace("Updating %s: %d", desc, id)
|
||||
_, err = x.Exec("UPDATE `repository` SET num_closed_issues=(SELECT COUNT(*) FROM `issue` WHERE repo_id=? AND is_closed=? AND is_pull=?) WHERE id=?", id, true, false, id)
|
||||
if err != nil {
|
||||
log.Error(4, "Update %s[%d]: %v", desc, id, err)
|
||||
log.Error("Update %s[%d]: %v", desc, id, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2362,7 +2362,7 @@ func CheckRepoStats() {
|
||||
// ***** START: Repository.NumForks *****
|
||||
results, err = x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_forks!=(SELECT COUNT(*) FROM `repository` WHERE fork_id=repo.id)")
|
||||
if err != nil {
|
||||
log.Error(4, "Select repository count 'num_forks': %v", err)
|
||||
log.Error("Select repository count 'num_forks': %v", err)
|
||||
} else {
|
||||
for _, result := range results {
|
||||
id := com.StrTo(result["id"]).MustInt64()
|
||||
@ -2370,19 +2370,19 @@ func CheckRepoStats() {
|
||||
|
||||
repo, err := GetRepositoryByID(id)
|
||||
if err != nil {
|
||||
log.Error(4, "GetRepositoryByID[%d]: %v", id, err)
|
||||
log.Error("GetRepositoryByID[%d]: %v", id, err)
|
||||
continue
|
||||
}
|
||||
|
||||
rawResult, err := x.Query("SELECT COUNT(*) FROM `repository` WHERE fork_id=?", repo.ID)
|
||||
if err != nil {
|
||||
log.Error(4, "Select count of forks[%d]: %v", repo.ID, err)
|
||||
log.Error("Select count of forks[%d]: %v", repo.ID, err)
|
||||
continue
|
||||
}
|
||||
repo.NumForks = int(parseCountResult(rawResult))
|
||||
|
||||
if err = UpdateRepository(repo, false); err != nil {
|
||||
log.Error(4, "UpdateRepository[%d]: %v", id, err)
|
||||
log.Error("UpdateRepository[%d]: %v", id, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
@ -2485,13 +2485,13 @@ func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *R
|
||||
Repo: repo.APIFormat(mode),
|
||||
Sender: doer.APIFormat(),
|
||||
}); err != nil {
|
||||
log.Error(2, "PrepareWebhooks [repo_id: %d]: %v", oldRepo.ID, err)
|
||||
log.Error("PrepareWebhooks [repo_id: %d]: %v", oldRepo.ID, err)
|
||||
} else {
|
||||
go HookQueue.Add(oldRepo.ID)
|
||||
}
|
||||
|
||||
if err = repo.UpdateSize(); err != nil {
|
||||
log.Error(4, "Failed to update size for repository: %v", err)
|
||||
log.Error("Failed to update size for repository: %v", err)
|
||||
}
|
||||
|
||||
// Copy LFS meta objects in new session
|
||||
|
@ -113,7 +113,7 @@ func populateRepoIndexer(maxRepoID int64) {
|
||||
Limit(RepositoryListDefaultPageSize).
|
||||
Find(&repos)
|
||||
if err != nil {
|
||||
log.Error(4, "populateRepoIndexer: %v", err)
|
||||
log.Error("populateRepoIndexer: %v", err)
|
||||
return
|
||||
} else if len(repos) == 0 {
|
||||
break
|
||||
@ -314,11 +314,11 @@ func processRepoIndexerOperationQueue() {
|
||||
op := <-repoIndexerOperationQueue
|
||||
if op.deleted {
|
||||
if err := indexer.DeleteRepoFromIndexer(op.repo.ID); err != nil {
|
||||
log.Error(4, "DeleteRepoFromIndexer: %v", err)
|
||||
log.Error("DeleteRepoFromIndexer: %v", err)
|
||||
}
|
||||
} else {
|
||||
if err := updateRepoIndexer(op.repo); err != nil {
|
||||
log.Error(4, "updateRepoIndexer: %v", err)
|
||||
log.Error("updateRepoIndexer: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ func (m *Mirror) AfterLoad(session *xorm.Session) {
|
||||
var err error
|
||||
m.Repo, err = getRepositoryByID(session, m.RepoID)
|
||||
if err != nil {
|
||||
log.Error(3, "getRepositoryByID[%d]: %v", m.ID, err)
|
||||
log.Error("getRepositoryByID[%d]: %v", m.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,7 +85,7 @@ func (m *Mirror) readAddress() {
|
||||
var err error
|
||||
m.address, err = remoteAddress(m.Repo.RepoPath())
|
||||
if err != nil {
|
||||
log.Error(4, "remoteAddress: %v", err)
|
||||
log.Error("remoteAddress: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,12 +164,12 @@ func parseRemoteUpdateOutput(output string) []*mirrorSyncResult {
|
||||
case strings.HasPrefix(lines[i], " "): // New commits of a reference
|
||||
delimIdx := strings.Index(lines[i][3:], " ")
|
||||
if delimIdx == -1 {
|
||||
log.Error(2, "SHA delimiter not found: %q", lines[i])
|
||||
log.Error("SHA delimiter not found: %q", lines[i])
|
||||
continue
|
||||
}
|
||||
shas := strings.Split(lines[i][3:delimIdx+3], "..")
|
||||
if len(shas) != 2 {
|
||||
log.Error(2, "Expect two SHAs but not what found: %q", lines[i])
|
||||
log.Error("Expect two SHAs but not what found: %q", lines[i])
|
||||
continue
|
||||
}
|
||||
results = append(results, &mirrorSyncResult{
|
||||
@ -204,13 +204,13 @@ func (m *Mirror) runSync() ([]*mirrorSyncResult, bool) {
|
||||
// contain a password
|
||||
message, err := sanitizeOutput(stderr, repoPath)
|
||||
if err != nil {
|
||||
log.Error(4, "sanitizeOutput: %v", err)
|
||||
log.Error("sanitizeOutput: %v", err)
|
||||
return nil, false
|
||||
}
|
||||
desc := fmt.Sprintf("Failed to update mirror repository '%s': %s", repoPath, message)
|
||||
log.Error(4, desc)
|
||||
log.Error(desc)
|
||||
if err = CreateRepositoryNotice(desc); err != nil {
|
||||
log.Error(4, "CreateRepositoryNotice: %v", err)
|
||||
log.Error("CreateRepositoryNotice: %v", err)
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
@ -218,15 +218,15 @@ func (m *Mirror) runSync() ([]*mirrorSyncResult, bool) {
|
||||
|
||||
gitRepo, err := git.OpenRepository(repoPath)
|
||||
if err != nil {
|
||||
log.Error(4, "OpenRepository: %v", err)
|
||||
log.Error("OpenRepository: %v", err)
|
||||
return nil, false
|
||||
}
|
||||
if err = SyncReleasesWithTags(m.Repo, gitRepo); err != nil {
|
||||
log.Error(4, "Failed to synchronize tags to releases for repository: %v", err)
|
||||
log.Error("Failed to synchronize tags to releases for repository: %v", err)
|
||||
}
|
||||
|
||||
if err := m.Repo.UpdateSize(); err != nil {
|
||||
log.Error(4, "Failed to update size for mirror repository: %v", err)
|
||||
log.Error("Failed to update size for mirror repository: %v", err)
|
||||
}
|
||||
|
||||
if m.Repo.HasWiki() {
|
||||
@ -237,13 +237,13 @@ func (m *Mirror) runSync() ([]*mirrorSyncResult, bool) {
|
||||
// contain a password
|
||||
message, err := sanitizeOutput(stderr, wikiPath)
|
||||
if err != nil {
|
||||
log.Error(4, "sanitizeOutput: %v", err)
|
||||
log.Error("sanitizeOutput: %v", err)
|
||||
return nil, false
|
||||
}
|
||||
desc := fmt.Sprintf("Failed to update mirror wiki repository '%s': %s", wikiPath, message)
|
||||
log.Error(4, desc)
|
||||
log.Error(desc)
|
||||
if err = CreateRepositoryNotice(desc); err != nil {
|
||||
log.Error(4, "CreateRepositoryNotice: %v", err)
|
||||
log.Error("CreateRepositoryNotice: %v", err)
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
@ -251,7 +251,7 @@ func (m *Mirror) runSync() ([]*mirrorSyncResult, bool) {
|
||||
|
||||
branches, err := m.Repo.GetBranches()
|
||||
if err != nil {
|
||||
log.Error(4, "GetBranches: %v", err)
|
||||
log.Error("GetBranches: %v", err)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
@ -310,14 +310,14 @@ func MirrorUpdate() {
|
||||
Iterate(new(Mirror), func(idx int, bean interface{}) error {
|
||||
m := bean.(*Mirror)
|
||||
if m.Repo == nil {
|
||||
log.Error(4, "Disconnected mirror repository found: %d", m.ID)
|
||||
log.Error("Disconnected mirror repository found: %d", m.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
MirrorQueue.Add(m.RepoID)
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Error(4, "MirrorUpdate: %v", err)
|
||||
log.Error("MirrorUpdate: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -333,7 +333,7 @@ func SyncMirrors() {
|
||||
|
||||
m, err := GetMirrorByRepoID(com.StrTo(repoID).MustInt64())
|
||||
if err != nil {
|
||||
log.Error(4, "GetMirrorByRepoID [%s]: %v", repoID, err)
|
||||
log.Error("GetMirrorByRepoID [%s]: %v", repoID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -344,7 +344,7 @@ func SyncMirrors() {
|
||||
|
||||
m.ScheduleNextUpdate()
|
||||
if err = updateMirror(sess, m); err != nil {
|
||||
log.Error(4, "UpdateMirror [%s]: %v", repoID, err)
|
||||
log.Error("UpdateMirror [%s]: %v", repoID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -354,7 +354,7 @@ func SyncMirrors() {
|
||||
} else {
|
||||
gitRepo, err = git.OpenRepository(m.Repo.RepoPath())
|
||||
if err != nil {
|
||||
log.Error(2, "OpenRepository [%d]: %v", m.RepoID, err)
|
||||
log.Error("OpenRepository [%d]: %v", m.RepoID, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
@ -368,7 +368,7 @@ func SyncMirrors() {
|
||||
// Create reference
|
||||
if result.oldCommitID == gitShortEmptySha {
|
||||
if err = MirrorSyncCreateAction(m.Repo, result.refName); err != nil {
|
||||
log.Error(2, "MirrorSyncCreateAction [repo_id: %d]: %v", m.RepoID, err)
|
||||
log.Error("MirrorSyncCreateAction [repo_id: %d]: %v", m.RepoID, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
@ -376,7 +376,7 @@ func SyncMirrors() {
|
||||
// Delete reference
|
||||
if result.newCommitID == gitShortEmptySha {
|
||||
if err = MirrorSyncDeleteAction(m.Repo, result.refName); err != nil {
|
||||
log.Error(2, "MirrorSyncDeleteAction [repo_id: %d]: %v", m.RepoID, err)
|
||||
log.Error("MirrorSyncDeleteAction [repo_id: %d]: %v", m.RepoID, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
@ -384,17 +384,17 @@ func SyncMirrors() {
|
||||
// Push commits
|
||||
oldCommitID, err := git.GetFullCommitID(gitRepo.Path, result.oldCommitID)
|
||||
if err != nil {
|
||||
log.Error(2, "GetFullCommitID [%d]: %v", m.RepoID, err)
|
||||
log.Error("GetFullCommitID [%d]: %v", m.RepoID, err)
|
||||
continue
|
||||
}
|
||||
newCommitID, err := git.GetFullCommitID(gitRepo.Path, result.newCommitID)
|
||||
if err != nil {
|
||||
log.Error(2, "GetFullCommitID [%d]: %v", m.RepoID, err)
|
||||
log.Error("GetFullCommitID [%d]: %v", m.RepoID, err)
|
||||
continue
|
||||
}
|
||||
commits, err := gitRepo.CommitsBetweenIDs(newCommitID, oldCommitID)
|
||||
if err != nil {
|
||||
log.Error(2, "CommitsBetweenIDs [repo_id: %d, new_commit_id: %s, old_commit_id: %s]: %v", m.RepoID, newCommitID, oldCommitID, err)
|
||||
log.Error("CommitsBetweenIDs [repo_id: %d, new_commit_id: %s, old_commit_id: %s]: %v", m.RepoID, newCommitID, oldCommitID, err)
|
||||
continue
|
||||
}
|
||||
if err = MirrorSyncPushAction(m.Repo, MirrorSyncPushActionOptions{
|
||||
@ -403,7 +403,7 @@ func SyncMirrors() {
|
||||
NewCommitID: newCommitID,
|
||||
Commits: ListToPushCommits(commits),
|
||||
}); err != nil {
|
||||
log.Error(2, "MirrorSyncPushAction [repo_id: %d]: %v", m.RepoID, err)
|
||||
log.Error("MirrorSyncPushAction [repo_id: %d]: %v", m.RepoID, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
@ -411,12 +411,12 @@ func SyncMirrors() {
|
||||
// Get latest commit date and update to current repository updated time
|
||||
commitDate, err := git.GetLatestCommitTime(m.Repo.RepoPath())
|
||||
if err != nil {
|
||||
log.Error(2, "GetLatestCommitDate [%s]: %v", m.RepoID, err)
|
||||
log.Error("GetLatestCommitDate [%d]: %v", m.RepoID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if _, err = sess.Exec("UPDATE repository SET updated_unix = ? WHERE id = ?", commitDate.Unix(), m.RepoID); err != nil {
|
||||
log.Error(2, "Update repository 'updated_unix' [%s]: %v", m.RepoID, err)
|
||||
log.Error("Update repository 'updated_unix' [%d]: %v", m.RepoID, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
@ -330,7 +330,7 @@ func appendAuthorizedKeysToFile(keys ...*PublicKey) error {
|
||||
|
||||
// .ssh directory should have mode 700, and authorized_keys file should have mode 600.
|
||||
if fi.Mode().Perm() > 0600 {
|
||||
log.Error(4, "authorized_keys file has unusual permission flags: %s - setting to -rw-------", fi.Mode().Perm().String())
|
||||
log.Error("authorized_keys file has unusual permission flags: %s - setting to -rw-------", fi.Mode().Perm().String())
|
||||
if err = f.Chmod(0600); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ func ParseCommitsWithStatus(oldCommits *list.List, repo *Repository) *list.List
|
||||
}
|
||||
statuses, err := GetLatestCommitStatus(repo, commit.ID.String(), 0)
|
||||
if err != nil {
|
||||
log.Error(3, "GetLatestCommitStatus: %v", err)
|
||||
log.Error("GetLatestCommitStatus: %v", err)
|
||||
} else {
|
||||
commit.Status = CalcCommitStatus(statuses)
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ func (list U2FRegistrationList) ToRegistrations() []u2f.Registration {
|
||||
for _, reg := range list {
|
||||
r, err := reg.Parse()
|
||||
if err != nil {
|
||||
log.Fatal(4, "parsing u2f registration: %v", err)
|
||||
log.Fatal("parsing u2f registration: %v", err)
|
||||
continue
|
||||
}
|
||||
regs = append(regs, *r)
|
||||
|
@ -215,7 +215,7 @@ func pushUpdate(opts PushUpdateOptions) (repo *Repository, err error) {
|
||||
}
|
||||
|
||||
if err = repo.UpdateSize(); err != nil {
|
||||
log.Error(4, "Failed to update size for repository: %v", err)
|
||||
log.Error("Failed to update size for repository: %v", err)
|
||||
}
|
||||
|
||||
var commits = &PushCommits{}
|
||||
|
@ -367,7 +367,7 @@ func (u *User) SizedRelAvatarLink(size int) string {
|
||||
case setting.DisableGravatar, setting.OfflineMode:
|
||||
if !com.IsFile(u.CustomAvatarPath()) {
|
||||
if err := u.GenerateRandomAvatar(); err != nil {
|
||||
log.Error(3, "GenerateRandomAvatar: %v", err)
|
||||
log.Error("GenerateRandomAvatar: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -523,7 +523,7 @@ func (u *User) IsOrganization() bool {
|
||||
func (u *User) IsUserOrgOwner(orgID int64) bool {
|
||||
isOwner, err := IsOrganizationOwner(orgID, u.ID)
|
||||
if err != nil {
|
||||
log.Error(4, "IsOrganizationOwner: %v", err)
|
||||
log.Error("IsOrganizationOwner: %v", err)
|
||||
return false
|
||||
}
|
||||
return isOwner
|
||||
@ -533,7 +533,7 @@ func (u *User) IsUserOrgOwner(orgID int64) bool {
|
||||
func (u *User) IsUserPartOfOrg(userID int64) bool {
|
||||
isMember, err := IsOrganizationMember(u.ID, userID)
|
||||
if err != nil {
|
||||
log.Error(4, "IsOrganizationMember: %v", err)
|
||||
log.Error("IsOrganizationMember: %v", err)
|
||||
return false
|
||||
}
|
||||
return isMember
|
||||
@ -543,7 +543,7 @@ func (u *User) IsUserPartOfOrg(userID int64) bool {
|
||||
func (u *User) IsPublicMember(orgID int64) bool {
|
||||
isMember, err := IsPublicMembership(orgID, u.ID)
|
||||
if err != nil {
|
||||
log.Error(4, "IsPublicMembership: %v", err)
|
||||
log.Error("IsPublicMembership: %v", err)
|
||||
return false
|
||||
}
|
||||
return isMember
|
||||
@ -864,7 +864,7 @@ func getVerifyUser(code string) (user *User) {
|
||||
if user, err = GetUserByName(string(b)); user != nil {
|
||||
return user
|
||||
}
|
||||
log.Error(4, "user.getVerifyUser: %v", err)
|
||||
log.Error("user.getVerifyUser: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -1490,11 +1490,11 @@ func deleteKeysMarkedForDeletion(keys []string) (bool, error) {
|
||||
for _, KeyToDelete := range keys {
|
||||
key, err := searchPublicKeyByContentWithEngine(sess, KeyToDelete)
|
||||
if err != nil {
|
||||
log.Error(4, "SearchPublicKeyByContent: %v", err)
|
||||
log.Error("SearchPublicKeyByContent: %v", err)
|
||||
continue
|
||||
}
|
||||
if err = deletePublicKeys(sess, key.ID); err != nil {
|
||||
log.Error(4, "deletePublicKeys: %v", err)
|
||||
log.Error("deletePublicKeys: %v", err)
|
||||
continue
|
||||
}
|
||||
sshKeysNeedUpdate = true
|
||||
@ -1515,7 +1515,7 @@ func addLdapSSHPublicKeys(usr *User, s *LoginSource, SSHPublicKeys []string) boo
|
||||
if err == nil {
|
||||
sshKeyName := fmt.Sprintf("%s-%s", s.Name, sshKey[0:40])
|
||||
if _, err := AddPublicKey(usr.ID, sshKeyName, sshKey, s.ID); err != nil {
|
||||
log.Error(4, "addLdapSSHPublicKeys[%s]: Error adding LDAP Public SSH Key for user %s: %v", s.Name, usr.Name, err)
|
||||
log.Error("addLdapSSHPublicKeys[%s]: Error adding LDAP Public SSH Key for user %s: %v", s.Name, usr.Name, err)
|
||||
} else {
|
||||
log.Trace("addLdapSSHPublicKeys[%s]: Added LDAP Public SSH Key for user %s", s.Name, usr.Name)
|
||||
sshKeysNeedUpdate = true
|
||||
@ -1537,7 +1537,7 @@ func synchronizeLdapSSHPublicKeys(usr *User, s *LoginSource, SSHPublicKeys []str
|
||||
var giteaKeys []string
|
||||
keys, err := ListPublicLdapSSHKeys(usr.ID, s.ID)
|
||||
if err != nil {
|
||||
log.Error(4, "synchronizeLdapSSHPublicKeys[%s]: Error listing LDAP Public SSH Keys for user %s: %v", s.Name, usr.Name, err)
|
||||
log.Error("synchronizeLdapSSHPublicKeys[%s]: Error listing LDAP Public SSH Keys for user %s: %v", s.Name, usr.Name, err)
|
||||
}
|
||||
|
||||
for _, v := range keys {
|
||||
@ -1586,7 +1586,7 @@ func synchronizeLdapSSHPublicKeys(usr *User, s *LoginSource, SSHPublicKeys []str
|
||||
// Delete LDAP keys from DB that doesn't exist in LDAP
|
||||
needUpd, err := deleteKeysMarkedForDeletion(giteaKeysToDelete)
|
||||
if err != nil {
|
||||
log.Error(4, "synchronizeLdapSSHPublicKeys[%s]: Error deleting LDAP Public SSH Keys marked for deletion for user %s: %v", s.Name, usr.Name, err)
|
||||
log.Error("synchronizeLdapSSHPublicKeys[%s]: Error deleting LDAP Public SSH Keys marked for deletion for user %s: %v", s.Name, usr.Name, err)
|
||||
}
|
||||
if needUpd {
|
||||
sshKeysNeedUpdate = true
|
||||
@ -1606,7 +1606,7 @@ func SyncExternalUsers() {
|
||||
|
||||
ls, err := LoginSources()
|
||||
if err != nil {
|
||||
log.Error(4, "SyncExternalUsers: %v", err)
|
||||
log.Error("SyncExternalUsers: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -1669,7 +1669,7 @@ func SyncExternalUsers() {
|
||||
err = CreateUser(usr)
|
||||
|
||||
if err != nil {
|
||||
log.Error(4, "SyncExternalUsers[%s]: Error creating user %s: %v", s.Name, su.Username, err)
|
||||
log.Error("SyncExternalUsers[%s]: Error creating user %s: %v", s.Name, su.Username, err)
|
||||
} else if isAttributeSSHPublicKeySet {
|
||||
log.Trace("SyncExternalUsers[%s]: Adding LDAP Public SSH Keys for user %s", s.Name, usr.Name)
|
||||
if addLdapSSHPublicKeys(usr, s, su.SSHPublicKey) {
|
||||
@ -1702,7 +1702,7 @@ func SyncExternalUsers() {
|
||||
|
||||
err = UpdateUserCols(usr, "full_name", "email", "is_admin", "is_active")
|
||||
if err != nil {
|
||||
log.Error(4, "SyncExternalUsers[%s]: Error updating user %s: %v", s.Name, usr.Name, err)
|
||||
log.Error("SyncExternalUsers[%s]: Error updating user %s: %v", s.Name, usr.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1729,7 +1729,7 @@ func SyncExternalUsers() {
|
||||
usr.IsActive = false
|
||||
err = UpdateUserCols(&usr, "is_active")
|
||||
if err != nil {
|
||||
log.Error(4, "SyncExternalUsers[%s]: Error deactivating user %s: %v", s.Name, usr.Name, err)
|
||||
log.Error("SyncExternalUsers[%s]: Error deactivating user %s: %v", s.Name, usr.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ type Webhook struct {
|
||||
func (w *Webhook) AfterLoad() {
|
||||
w.HookEvent = &HookEvent{}
|
||||
if err := json.Unmarshal([]byte(w.Events), w.HookEvent); err != nil {
|
||||
log.Error(3, "Unmarshal[%d]: %v", w.ID, err)
|
||||
log.Error("Unmarshal[%d]: %v", w.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,7 +131,7 @@ func (w *Webhook) AfterLoad() {
|
||||
func (w *Webhook) GetSlackHook() *SlackMeta {
|
||||
s := &SlackMeta{}
|
||||
if err := json.Unmarshal([]byte(w.Meta), s); err != nil {
|
||||
log.Error(4, "webhook.GetSlackHook(%d): %v", w.ID, err)
|
||||
log.Error("webhook.GetSlackHook(%d): %v", w.ID, err)
|
||||
}
|
||||
return s
|
||||
}
|
||||
@ -140,7 +140,7 @@ func (w *Webhook) GetSlackHook() *SlackMeta {
|
||||
func (w *Webhook) GetDiscordHook() *DiscordMeta {
|
||||
s := &DiscordMeta{}
|
||||
if err := json.Unmarshal([]byte(w.Meta), s); err != nil {
|
||||
log.Error(4, "webhook.GetDiscordHook(%d): %v", w.ID, err)
|
||||
log.Error("webhook.GetDiscordHook(%d): %v", w.ID, err)
|
||||
}
|
||||
return s
|
||||
}
|
||||
@ -572,13 +572,13 @@ func (t *HookTask) AfterLoad() {
|
||||
|
||||
t.RequestInfo = &HookRequest{}
|
||||
if err := json.Unmarshal([]byte(t.RequestContent), t.RequestInfo); err != nil {
|
||||
log.Error(3, "Unmarshal RequestContent[%d]: %v", t.ID, err)
|
||||
log.Error("Unmarshal RequestContent[%d]: %v", t.ID, err)
|
||||
}
|
||||
|
||||
if len(t.ResponseContent) > 0 {
|
||||
t.ResponseInfo = &HookResponse{}
|
||||
if err := json.Unmarshal([]byte(t.ResponseContent), t.ResponseInfo); err != nil {
|
||||
log.Error(3, "Unmarshal ResponseContent[%d]: %v", t.ID, err)
|
||||
log.Error("Unmarshal ResponseContent[%d]: %v", t.ID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -586,7 +586,7 @@ func (t *HookTask) AfterLoad() {
|
||||
func (t *HookTask) simpleMarshalJSON(v interface{}) string {
|
||||
p, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
log.Error(3, "Marshal [%d]: %v", t.ID, err)
|
||||
log.Error("Marshal [%d]: %v", t.ID, err)
|
||||
}
|
||||
return string(p)
|
||||
}
|
||||
@ -666,7 +666,7 @@ func prepareWebhook(e Engine, w *Webhook, repo *Repository, event HookEventType,
|
||||
if len(w.Secret) > 0 {
|
||||
data, err := payloader.JSONPayload()
|
||||
if err != nil {
|
||||
log.Error(2, "prepareWebhooks.JSONPayload: %v", err)
|
||||
log.Error("prepareWebhooks.JSONPayload: %v", err)
|
||||
}
|
||||
sig := hmac.New(sha256.New, []byte(w.Secret))
|
||||
sig.Write(data)
|
||||
@ -765,13 +765,13 @@ func (t *HookTask) deliver() {
|
||||
}
|
||||
|
||||
if err := UpdateHookTask(t); err != nil {
|
||||
log.Error(4, "UpdateHookTask [%d]: %v", t.ID, err)
|
||||
log.Error("UpdateHookTask [%d]: %v", t.ID, err)
|
||||
}
|
||||
|
||||
// Update webhook last delivery status.
|
||||
w, err := GetWebhookByID(t.HookID)
|
||||
if err != nil {
|
||||
log.Error(5, "GetWebhookByID: %v", err)
|
||||
log.Error("GetWebhookByID: %v", err)
|
||||
return
|
||||
}
|
||||
if t.IsSucceed {
|
||||
@ -780,7 +780,7 @@ func (t *HookTask) deliver() {
|
||||
w.LastStatus = HookStatusFail
|
||||
}
|
||||
if err = UpdateWebhookLastStatus(w); err != nil {
|
||||
log.Error(5, "UpdateWebhookLastStatus: %v", err)
|
||||
log.Error("UpdateWebhookLastStatus: %v", err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
@ -813,7 +813,7 @@ func DeliverHooks() {
|
||||
tasks := make([]*HookTask, 0, 10)
|
||||
err := x.Where("is_delivered=?", false).Find(&tasks)
|
||||
if err != nil {
|
||||
log.Error(4, "DeliverHooks: %v", err)
|
||||
log.Error("DeliverHooks: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -829,13 +829,13 @@ func DeliverHooks() {
|
||||
|
||||
repoID, err := com.StrTo(repoIDStr).Int64()
|
||||
if err != nil {
|
||||
log.Error(4, "Invalid repo ID: %s", repoIDStr)
|
||||
log.Error("Invalid repo ID: %s", repoIDStr)
|
||||
continue
|
||||
}
|
||||
|
||||
tasks = make([]*HookTask, 0, 5)
|
||||
if err := x.Where("repo_id=? AND is_delivered=?", repoID, false).Find(&tasks); err != nil {
|
||||
log.Error(4, "Get repository [%s] hook tasks: %v", repoID, err)
|
||||
log.Error("Get repository [%d] hook tasks: %v", repoID, err)
|
||||
continue
|
||||
}
|
||||
for _, t := range tasks {
|
||||
|
@ -63,13 +63,13 @@ func SignedInID(ctx *macaron.Context, sess session.Store) int64 {
|
||||
t, err := models.GetAccessTokenBySHA(tokenSHA)
|
||||
if err != nil {
|
||||
if models.IsErrAccessTokenNotExist(err) || models.IsErrAccessTokenEmpty(err) {
|
||||
log.Error(4, "GetAccessTokenBySHA: %v", err)
|
||||
log.Error("GetAccessTokenBySHA: %v", err)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
t.UpdatedUnix = util.TimeStampNow()
|
||||
if err = models.UpdateAccessToken(t); err != nil {
|
||||
log.Error(4, "UpdateAccessToken: %v", err)
|
||||
log.Error("UpdateAccessToken: %v", err)
|
||||
}
|
||||
ctx.Data["IsApiToken"] = true
|
||||
return t.UID
|
||||
@ -92,7 +92,7 @@ func checkOAuthAccessToken(accessToken string) int64 {
|
||||
}
|
||||
token, err := models.ParseOAuth2Token(accessToken)
|
||||
if err != nil {
|
||||
log.Trace("ParseOAuth2Token", err)
|
||||
log.Trace("ParseOAuth2Token: %v", err)
|
||||
return 0
|
||||
}
|
||||
var grant *models.OAuth2Grant
|
||||
@ -120,7 +120,7 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
|
||||
if err == nil {
|
||||
return user, false
|
||||
} else if !models.IsErrUserNotExist(err) {
|
||||
log.Error(4, "GetUserById: %v", err)
|
||||
log.Error("GetUserById: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,7 +130,7 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
|
||||
u, err := models.GetUserByName(webAuthUser)
|
||||
if err != nil {
|
||||
if !models.IsErrUserNotExist(err) {
|
||||
log.Error(4, "GetUserByName: %v", err)
|
||||
log.Error("GetUserByName: %v", err)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
@ -151,7 +151,7 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
|
||||
}
|
||||
if err = models.CreateUser(u); err != nil {
|
||||
// FIXME: should I create a system notice?
|
||||
log.Error(4, "CreateUser: %v", err)
|
||||
log.Error("CreateUser: %v", err)
|
||||
return nil, false
|
||||
}
|
||||
return u, false
|
||||
@ -183,13 +183,13 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
|
||||
if isUsernameToken {
|
||||
u, err = models.GetUserByID(token.UID)
|
||||
if err != nil {
|
||||
log.Error(4, "GetUserByID: %v", err)
|
||||
log.Error("GetUserByID: %v", err)
|
||||
return nil, false
|
||||
}
|
||||
} else {
|
||||
u, err = models.GetUserByName(uname)
|
||||
if err != nil {
|
||||
log.Error(4, "GetUserByID: %v", err)
|
||||
log.Error("GetUserByID: %v", err)
|
||||
return nil, false
|
||||
}
|
||||
if u.ID != token.UID {
|
||||
@ -198,11 +198,11 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
|
||||
}
|
||||
token.UpdatedUnix = util.TimeStampNow()
|
||||
if err = models.UpdateAccessToken(token); err != nil {
|
||||
log.Error(4, "UpdateAccessToken: %v", err)
|
||||
log.Error("UpdateAccessToken: %v", err)
|
||||
}
|
||||
} else {
|
||||
if !models.IsErrAccessTokenNotExist(err) && !models.IsErrAccessTokenEmpty(err) {
|
||||
log.Error(4, "GetAccessTokenBySha: %v", err)
|
||||
log.Error("GetAccessTokenBySha: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,7 +210,7 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
|
||||
u, err = models.UserSignIn(uname, passwd)
|
||||
if err != nil {
|
||||
if !models.IsErrUserNotExist(err) {
|
||||
log.Error(4, "UserSignIn: %v", err)
|
||||
log.Error("UserSignIn: %v", err)
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ func (ls *Source) findUserDN(l *ldap.Conn, name string) (string, bool) {
|
||||
|
||||
userDN := sr.Entries[0].DN
|
||||
if userDN == "" {
|
||||
log.Error(4, "LDAP search was successful, but found no DN!")
|
||||
log.Error("LDAP search was successful, but found no DN!")
|
||||
return "", false
|
||||
}
|
||||
|
||||
@ -162,7 +162,7 @@ func checkAdmin(l *ldap.Conn, ls *Source, userDN string) bool {
|
||||
sr, err := l.Search(search)
|
||||
|
||||
if err != nil {
|
||||
log.Error(4, "LDAP Admin Search failed unexpectedly! (%v)", err)
|
||||
log.Error("LDAP Admin Search failed unexpectedly! (%v)", err)
|
||||
} else if len(sr.Entries) < 1 {
|
||||
log.Trace("LDAP Admin Search found no matching entries.")
|
||||
} else {
|
||||
@ -176,12 +176,12 @@ func checkAdmin(l *ldap.Conn, ls *Source, userDN string) bool {
|
||||
func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResult {
|
||||
// See https://tools.ietf.org/search/rfc4513#section-5.1.2
|
||||
if len(passwd) == 0 {
|
||||
log.Debug("Auth. failed for %s, password cannot be empty")
|
||||
log.Debug("Auth. failed for %s, password cannot be empty", name)
|
||||
return nil
|
||||
}
|
||||
l, err := dial(ls)
|
||||
if err != nil {
|
||||
log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err)
|
||||
log.Error("LDAP Connect error, %s:%v", ls.Host, err)
|
||||
ls.Enabled = false
|
||||
return nil
|
||||
}
|
||||
@ -261,7 +261,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul
|
||||
|
||||
sr, err := l.Search(search)
|
||||
if err != nil {
|
||||
log.Error(4, "LDAP Search failed unexpectedly! (%v)", err)
|
||||
log.Error("LDAP Search failed unexpectedly! (%v)", err)
|
||||
return nil
|
||||
} else if len(sr.Entries) < 1 {
|
||||
if directBind {
|
||||
@ -311,7 +311,7 @@ func (ls *Source) UsePagedSearch() bool {
|
||||
func (ls *Source) SearchEntries() []*SearchResult {
|
||||
l, err := dial(ls)
|
||||
if err != nil {
|
||||
log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err)
|
||||
log.Error("LDAP Connect error, %s:%v", ls.Host, err)
|
||||
ls.Enabled = false
|
||||
return nil
|
||||
}
|
||||
@ -349,7 +349,7 @@ func (ls *Source) SearchEntries() []*SearchResult {
|
||||
sr, err = l.Search(search)
|
||||
}
|
||||
if err != nil {
|
||||
log.Error(4, "LDAP Search failed unexpectedly! (%v)", err)
|
||||
log.Error("LDAP Search failed unexpectedly! (%v)", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ func GetRandomBytesAsBase64(n int) string {
|
||||
_, err := io.ReadFull(rand.Reader, bytes)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(4, "Error reading random bytes: %v", err)
|
||||
log.Fatal("Error reading random bytes: %v", err)
|
||||
}
|
||||
|
||||
return base64.RawURLEncoding.EncodeToString(bytes)
|
||||
@ -197,12 +197,12 @@ const DefaultAvatarSize = -1
|
||||
func libravatarURL(email string) (*url.URL, error) {
|
||||
urlStr, err := setting.LibravatarService.FromEmail(email)
|
||||
if err != nil {
|
||||
log.Error(4, "LibravatarService.FromEmail(email=%s): error %v", email, err)
|
||||
log.Error("LibravatarService.FromEmail(email=%s): error %v", email, err)
|
||||
return nil, err
|
||||
}
|
||||
u, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
log.Error(4, "Failed to parse libravatar url(%s): error %v", urlStr, err)
|
||||
log.Error("Failed to parse libravatar url(%s): error %v", urlStr, err)
|
||||
return nil, err
|
||||
}
|
||||
return u, nil
|
||||
|
@ -72,7 +72,7 @@ func (ctx *APIContext) Error(status int, title string, obj interface{}) {
|
||||
}
|
||||
|
||||
if status == 500 {
|
||||
log.Error(4, "%s: %s", title, message)
|
||||
log.Error("%s: %s", title, message)
|
||||
}
|
||||
|
||||
ctx.JSON(status, APIError{
|
||||
|
@ -116,7 +116,7 @@ func (ctx *Context) RenderWithErr(msg string, tpl base.TplName, form interface{}
|
||||
// NotFound displays a 404 (Not Found) page and prints the given error, if any.
|
||||
func (ctx *Context) NotFound(title string, err error) {
|
||||
if err != nil {
|
||||
log.Error(4, "%s: %v", title, err)
|
||||
log.Error("%s: %v", title, err)
|
||||
if macaron.Env != macaron.PROD {
|
||||
ctx.Data["ErrorMsg"] = err
|
||||
}
|
||||
@ -131,7 +131,7 @@ func (ctx *Context) NotFound(title string, err error) {
|
||||
// error, if any.
|
||||
func (ctx *Context) ServerError(title string, err error) {
|
||||
if err != nil {
|
||||
log.Error(4, "%s: %v", title, err)
|
||||
log.Error("%s: %v", title, err)
|
||||
if macaron.Env != macaron.PROD {
|
||||
ctx.Data["ErrorMsg"] = err
|
||||
}
|
||||
@ -156,7 +156,7 @@ func (ctx *Context) NotFoundOrServerError(title string, errck func(error) bool,
|
||||
// HandleText handles HTTP status code
|
||||
func (ctx *Context) HandleText(status int, title string) {
|
||||
if (status/100 == 4) || (status/100 == 5) {
|
||||
log.Error(4, "%s", title)
|
||||
log.Error("%s", title)
|
||||
}
|
||||
ctx.PlainText(status, []byte(title))
|
||||
}
|
||||
|
@ -17,11 +17,9 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"runtime"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
macaron "gopkg.in/macaron.v1"
|
||||
)
|
||||
|
||||
@ -32,7 +30,7 @@ func Recovery() macaron.Handler {
|
||||
return func(ctx *Context) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
combinedErr := fmt.Errorf("%s\n%s", err, string(stack(3)))
|
||||
combinedErr := fmt.Errorf("%s\n%s", err, string(log.Stack(2)))
|
||||
ctx.ServerError("PANIC:", combinedErr)
|
||||
}
|
||||
}()
|
||||
@ -40,73 +38,3 @@ func Recovery() macaron.Handler {
|
||||
ctx.Next()
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
unknown = []byte("???")
|
||||
)
|
||||
|
||||
// Although we could just use debug.Stack(), this routine will return the source code
|
||||
// skip the provided number of frames - i.e. allowing us to ignore this function call
|
||||
// and the preceding function call.
|
||||
// If the problem is a lack of memory of course all this is not going to work...
|
||||
func stack(skip int) []byte {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
// Store the last file we opened as its probable that the preceding stack frame
|
||||
// will be in the same file
|
||||
var lines [][]byte
|
||||
var lastFilename string
|
||||
for i := skip; ; i++ { // Skip over frames
|
||||
programCounter, filename, lineNumber, ok := runtime.Caller(i)
|
||||
// If we can't retrieve the information break - basically we're into go internals at this point.
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
// Print equivalent of debug.Stack()
|
||||
fmt.Fprintf(buf, "%s:%d (0x%x)\n", filename, lineNumber, programCounter)
|
||||
// Now try to print the offending line
|
||||
if filename != lastFilename {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
// can't read this sourcefile
|
||||
// likely we don't have the sourcecode available
|
||||
continue
|
||||
}
|
||||
lines = bytes.Split(data, []byte{'\n'})
|
||||
lastFilename = filename
|
||||
}
|
||||
fmt.Fprintf(buf, "\t%s: %s\n", functionName(programCounter), source(lines, lineNumber))
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// functionName converts the provided programCounter into a function name
|
||||
func functionName(programCounter uintptr) []byte {
|
||||
function := runtime.FuncForPC(programCounter)
|
||||
if function == nil {
|
||||
return unknown
|
||||
}
|
||||
name := []byte(function.Name())
|
||||
|
||||
// Because we provide the filename we can drop the preceding package name.
|
||||
if lastslash := bytes.LastIndex(name, []byte("/")); lastslash >= 0 {
|
||||
name = name[lastslash+1:]
|
||||
}
|
||||
// And the current package name.
|
||||
if period := bytes.Index(name, []byte(".")); period >= 0 {
|
||||
name = name[period+1:]
|
||||
}
|
||||
// And we should just replace the interpunct with a dot
|
||||
name = bytes.Replace(name, []byte("·"), []byte("."), -1)
|
||||
return name
|
||||
}
|
||||
|
||||
// source returns a space-trimmed slice of the n'th line.
|
||||
func source(lines [][]byte, n int) []byte {
|
||||
n-- // in stack trace, lines are 1-indexed but our array is 0-indexed
|
||||
if n < 0 || n >= len(lines) {
|
||||
return unknown
|
||||
}
|
||||
return bytes.TrimSpace(lines[n])
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ func (r *Repository) BranchNameSubURL() string {
|
||||
case r.IsViewCommit:
|
||||
return "commit/" + r.BranchName
|
||||
}
|
||||
log.Error(4, "Unknown view type for repo: %v", r)
|
||||
log.Error("Unknown view type for repo: %v", r)
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -536,7 +536,7 @@ func getRefName(ctx *Context, pathType RepoRefType) string {
|
||||
}
|
||||
return path
|
||||
default:
|
||||
log.Error(4, "Unrecognized path type: %v", path)
|
||||
log.Error("Unrecognized path type: %v", path)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ func NewContext() {
|
||||
if setting.Cron.UpdateMirror.Enabled {
|
||||
entry, err = c.AddFunc("Update mirrors", setting.Cron.UpdateMirror.Schedule, models.MirrorUpdate)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Cron[Update mirrors]: %v", err)
|
||||
log.Fatal("Cron[Update mirrors]: %v", err)
|
||||
}
|
||||
if setting.Cron.UpdateMirror.RunAtStart {
|
||||
entry.Prev = time.Now()
|
||||
@ -36,7 +36,7 @@ func NewContext() {
|
||||
if setting.Cron.RepoHealthCheck.Enabled {
|
||||
entry, err = c.AddFunc("Repository health check", setting.Cron.RepoHealthCheck.Schedule, models.GitFsck)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Cron[Repository health check]: %v", err)
|
||||
log.Fatal("Cron[Repository health check]: %v", err)
|
||||
}
|
||||
if setting.Cron.RepoHealthCheck.RunAtStart {
|
||||
entry.Prev = time.Now()
|
||||
@ -47,7 +47,7 @@ func NewContext() {
|
||||
if setting.Cron.CheckRepoStats.Enabled {
|
||||
entry, err = c.AddFunc("Check repository statistics", setting.Cron.CheckRepoStats.Schedule, models.CheckRepoStats)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Cron[Check repository statistics]: %v", err)
|
||||
log.Fatal("Cron[Check repository statistics]: %v", err)
|
||||
}
|
||||
if setting.Cron.CheckRepoStats.RunAtStart {
|
||||
entry.Prev = time.Now()
|
||||
@ -58,7 +58,7 @@ func NewContext() {
|
||||
if setting.Cron.ArchiveCleanup.Enabled {
|
||||
entry, err = c.AddFunc("Clean up old repository archives", setting.Cron.ArchiveCleanup.Schedule, models.DeleteOldRepositoryArchives)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Cron[Clean up old repository archives]: %v", err)
|
||||
log.Fatal("Cron[Clean up old repository archives]: %v", err)
|
||||
}
|
||||
if setting.Cron.ArchiveCleanup.RunAtStart {
|
||||
entry.Prev = time.Now()
|
||||
@ -69,7 +69,7 @@ func NewContext() {
|
||||
if setting.Cron.SyncExternalUsers.Enabled {
|
||||
entry, err = c.AddFunc("Synchronize external users", setting.Cron.SyncExternalUsers.Schedule, models.SyncExternalUsers)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Cron[Synchronize external users]: %v", err)
|
||||
log.Fatal("Cron[Synchronize external users]: %v", err)
|
||||
}
|
||||
if setting.Cron.SyncExternalUsers.RunAtStart {
|
||||
entry.Prev = time.Now()
|
||||
@ -80,7 +80,7 @@ func NewContext() {
|
||||
if setting.Cron.DeletedBranchesCleanup.Enabled {
|
||||
entry, err = c.AddFunc("Remove old deleted branches", setting.Cron.DeletedBranchesCleanup.Schedule, models.RemoveOldDeletedBranches)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Cron[Remove old deleted branches]: %v", err)
|
||||
log.Fatal("Cron[Remove old deleted branches]: %v", err)
|
||||
}
|
||||
if setting.Cron.DeletedBranchesCleanup.RunAtStart {
|
||||
entry.Prev = time.Now()
|
||||
|
@ -116,7 +116,7 @@ func populateIssueIndexer() {
|
||||
Collaborate: util.OptionalBoolFalse,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error(4, "SearchRepositoryByName: %v", err)
|
||||
log.Error("SearchRepositoryByName: %v", err)
|
||||
continue
|
||||
}
|
||||
if len(repos) == 0 {
|
||||
@ -130,11 +130,11 @@ func populateIssueIndexer() {
|
||||
IsPull: util.OptionalBoolNone,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error(4, "Issues: %v", err)
|
||||
log.Error("Issues: %v", err)
|
||||
continue
|
||||
}
|
||||
if err = models.IssueList(is).LoadDiscussComments(); err != nil {
|
||||
log.Error(4, "LoadComments: %v", err)
|
||||
log.Error("LoadComments: %v", err)
|
||||
continue
|
||||
}
|
||||
for _, issue := range is {
|
||||
@ -166,7 +166,7 @@ func DeleteRepoIssueIndexer(repo *models.Repository) {
|
||||
var ids []int64
|
||||
ids, err := models.GetIssueIDsByRepoID(repo.ID)
|
||||
if err != nil {
|
||||
log.Error(4, "getIssueIDsByRepoID failed: %v", err)
|
||||
log.Error("getIssueIDsByRepoID failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ func (l *LevelQueue) Run() error {
|
||||
bs, err := l.queue.RPop()
|
||||
if err != nil {
|
||||
if err != levelqueue.ErrNotFound {
|
||||
log.Error(4, "RPop: %v", err)
|
||||
log.Error("RPop: %v", err)
|
||||
}
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
continue
|
||||
@ -67,7 +67,7 @@ func (l *LevelQueue) Run() error {
|
||||
var data IndexerData
|
||||
err = json.Unmarshal(bs, &data)
|
||||
if err != nil {
|
||||
log.Error(4, "Unmarshal: %v", err)
|
||||
log.Error("Unmarshal: %v", err)
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
continue
|
||||
}
|
||||
@ -77,11 +77,11 @@ func (l *LevelQueue) Run() error {
|
||||
if data.IsDelete {
|
||||
if data.ID > 0 {
|
||||
if err = l.indexer.Delete(data.ID); err != nil {
|
||||
log.Error(4, "indexer.Delete: %v", err)
|
||||
log.Error("indexer.Delete: %v", err)
|
||||
}
|
||||
} else if len(data.IDs) > 0 {
|
||||
if err = l.indexer.Delete(data.IDs...); err != nil {
|
||||
log.Error(4, "indexer.Delete: %v", err)
|
||||
log.Error("indexer.Delete: %v", err)
|
||||
}
|
||||
}
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
|
@ -68,7 +68,7 @@ func (update RepoIndexerUpdate) AddToFlushingBatch(batch rupture.FlushingBatch)
|
||||
case RepoIndexerOpDelete:
|
||||
return batch.Delete(id)
|
||||
default:
|
||||
log.Error(4, "Unrecognized repo indexer op: %d", update.Op)
|
||||
log.Error("Unrecognized repo indexer op: %d", update.Op)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -78,17 +78,17 @@ func InitRepoIndexer(populateIndexer func() error) {
|
||||
var err error
|
||||
repoIndexer, err = openIndexer(setting.Indexer.RepoPath, repoIndexerLatestVersion)
|
||||
if err != nil {
|
||||
log.Fatal(4, "InitRepoIndexer: %v", err)
|
||||
log.Fatal("InitRepoIndexer: %v", err)
|
||||
}
|
||||
if repoIndexer != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = createRepoIndexer(setting.Indexer.RepoPath, repoIndexerLatestVersion); err != nil {
|
||||
log.Fatal(4, "CreateRepoIndexer: %v", err)
|
||||
log.Fatal("CreateRepoIndexer: %v", err)
|
||||
}
|
||||
if err = populateIndexer(); err != nil {
|
||||
log.Fatal(4, "PopulateRepoIndex: %v", err)
|
||||
log.Fatal("PopulateRepoIndex: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,7 +135,7 @@ func filenameIndexerID(repoID int64, filename string) string {
|
||||
func filenameOfIndexerID(indexerID string) string {
|
||||
index := strings.IndexByte(indexerID, '_')
|
||||
if index == -1 {
|
||||
log.Error(4, "Unexpected ID in repo indexer: %s", indexerID)
|
||||
log.Error("Unexpected ID in repo indexer: %s", indexerID)
|
||||
}
|
||||
return indexerID[index+1:]
|
||||
}
|
||||
|
@ -333,7 +333,7 @@ func PutHandler(ctx *context.Context) {
|
||||
ctx.Resp.WriteHeader(500)
|
||||
fmt.Fprintf(ctx.Resp, `{"message":"%s"}`, err)
|
||||
if err = repository.RemoveLFSMetaObjectByOid(rv.Oid); err != nil {
|
||||
log.Error(4, "RemoveLFSMetaObjectByOid: %v", err)
|
||||
log.Error("RemoveLFSMetaObjectByOid: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
328
modules/log/base.go
Normal file
328
modules/log/base.go
Normal file
@ -0,0 +1,328 @@
|
||||
// Copyright 2019 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 log
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// These flags define which text to prefix to each log entry generated
|
||||
// by the Logger. Bits are or'ed together to control what's printed.
|
||||
// There is no control over the order they appear (the order listed
|
||||
// here) or the format they present (as described in the comments).
|
||||
// The prefix is followed by a colon only if more than time is stated
|
||||
// is specified. For example, flags Ldate | Ltime
|
||||
// produce, 2009/01/23 01:23:23 message.
|
||||
// The standard is:
|
||||
// 2009/01/23 01:23:23 ...a/b/c/d.go:23:runtime.Caller() [I]: message
|
||||
const (
|
||||
Ldate = 1 << iota // the date in the local time zone: 2009/01/23
|
||||
Ltime // the time in the local time zone: 01:23:23
|
||||
Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime.
|
||||
Llongfile // full file name and line number: /a/b/c/d.go:23
|
||||
Lshortfile // final file name element and line number: d.go:23. overrides Llongfile
|
||||
Lfuncname // function name of the caller: runtime.Caller()
|
||||
Lshortfuncname // last part of the function name
|
||||
LUTC // if Ldate or Ltime is set, use UTC rather than the local time zone
|
||||
Llevelinitial // Initial character of the provided level in brackets eg. [I] for info
|
||||
Llevel // Provided level in brackets [INFO]
|
||||
|
||||
// Last 20 characters of the filename
|
||||
Lmedfile = Lshortfile | Llongfile
|
||||
|
||||
// LstdFlags is the initial value for the standard logger
|
||||
LstdFlags = Ldate | Ltime | Lmedfile | Lshortfuncname | Llevelinitial
|
||||
)
|
||||
|
||||
var flagFromString = map[string]int{
|
||||
"none": 0,
|
||||
"date": Ldate,
|
||||
"time": Ltime,
|
||||
"microseconds": Lmicroseconds,
|
||||
"longfile": Llongfile,
|
||||
"shortfile": Lshortfile,
|
||||
"funcname": Lfuncname,
|
||||
"shortfuncname": Lshortfuncname,
|
||||
"utc": LUTC,
|
||||
"levelinitial": Llevelinitial,
|
||||
"level": Llevel,
|
||||
"medfile": Lmedfile,
|
||||
"stdflags": LstdFlags,
|
||||
}
|
||||
|
||||
// FlagsFromString takes a comma separated list of flags and returns
|
||||
// the flags for this string
|
||||
func FlagsFromString(from string) int {
|
||||
flags := 0
|
||||
for _, flag := range strings.Split(strings.ToLower(from), ",") {
|
||||
f, ok := flagFromString[strings.TrimSpace(flag)]
|
||||
if ok {
|
||||
flags = flags | f
|
||||
}
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
||||
type byteArrayWriter []byte
|
||||
|
||||
func (b *byteArrayWriter) Write(p []byte) (int, error) {
|
||||
*b = append(*b, p...)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// BaseLogger represent a basic logger for Gitea
|
||||
type BaseLogger struct {
|
||||
out io.WriteCloser
|
||||
mu sync.Mutex
|
||||
|
||||
Level Level `json:"level"`
|
||||
StacktraceLevel Level `json:"stacktraceLevel"`
|
||||
Flags int `json:"flags"`
|
||||
Prefix string `json:"prefix"`
|
||||
Colorize bool `json:"colorize"`
|
||||
Expression string `json:"expression"`
|
||||
regexp *regexp.Regexp
|
||||
}
|
||||
|
||||
func (b *BaseLogger) createLogger(out io.WriteCloser, level ...Level) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
b.out = out
|
||||
switch b.Flags {
|
||||
case 0:
|
||||
b.Flags = LstdFlags
|
||||
case -1:
|
||||
b.Flags = 0
|
||||
}
|
||||
if len(level) > 0 {
|
||||
b.Level = level[0]
|
||||
}
|
||||
b.createExpression()
|
||||
}
|
||||
|
||||
func (b *BaseLogger) createExpression() {
|
||||
if len(b.Expression) > 0 {
|
||||
var err error
|
||||
b.regexp, err = regexp.Compile(b.Expression)
|
||||
if err != nil {
|
||||
b.regexp = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetLevel returns the logging level for this logger
|
||||
func (b *BaseLogger) GetLevel() Level {
|
||||
return b.Level
|
||||
}
|
||||
|
||||
// GetStacktraceLevel returns the stacktrace logging level for this logger
|
||||
func (b *BaseLogger) GetStacktraceLevel() Level {
|
||||
return b.StacktraceLevel
|
||||
}
|
||||
|
||||
// Copy of cheap integer to fixed-width decimal to ascii from logger.
|
||||
func itoa(buf *[]byte, i int, wid int) {
|
||||
var b [20]byte
|
||||
bp := len(b) - 1
|
||||
for i >= 10 || wid > 1 {
|
||||
wid--
|
||||
q := i / 10
|
||||
b[bp] = byte('0' + i - q*10)
|
||||
bp--
|
||||
i = q
|
||||
}
|
||||
// i < 10
|
||||
b[bp] = byte('0' + i)
|
||||
*buf = append(*buf, b[bp:]...)
|
||||
}
|
||||
|
||||
func (b *BaseLogger) createMsg(buf *[]byte, event *Event) {
|
||||
*buf = append(*buf, b.Prefix...)
|
||||
t := event.time
|
||||
if b.Flags&(Ldate|Ltime|Lmicroseconds) != 0 {
|
||||
if b.Colorize {
|
||||
*buf = append(*buf, fgCyanBytes...)
|
||||
}
|
||||
if b.Flags&LUTC != 0 {
|
||||
t = t.UTC()
|
||||
}
|
||||
if b.Flags&Ldate != 0 {
|
||||
year, month, day := t.Date()
|
||||
itoa(buf, year, 4)
|
||||
*buf = append(*buf, '/')
|
||||
itoa(buf, int(month), 2)
|
||||
*buf = append(*buf, '/')
|
||||
itoa(buf, day, 2)
|
||||
*buf = append(*buf, ' ')
|
||||
}
|
||||
if b.Flags&(Ltime|Lmicroseconds) != 0 {
|
||||
hour, min, sec := t.Clock()
|
||||
itoa(buf, hour, 2)
|
||||
*buf = append(*buf, ':')
|
||||
itoa(buf, min, 2)
|
||||
*buf = append(*buf, ':')
|
||||
itoa(buf, sec, 2)
|
||||
if b.Flags&Lmicroseconds != 0 {
|
||||
*buf = append(*buf, '.')
|
||||
itoa(buf, t.Nanosecond()/1e3, 6)
|
||||
}
|
||||
*buf = append(*buf, ' ')
|
||||
}
|
||||
if b.Colorize {
|
||||
*buf = append(*buf, resetBytes...)
|
||||
}
|
||||
|
||||
}
|
||||
if b.Flags&(Lshortfile|Llongfile) != 0 {
|
||||
if b.Colorize {
|
||||
*buf = append(*buf, fgGreenBytes...)
|
||||
}
|
||||
file := event.filename
|
||||
if b.Flags&Lmedfile == Lmedfile {
|
||||
startIndex := len(file) - 20
|
||||
if startIndex > 0 {
|
||||
file = "..." + file[startIndex:]
|
||||
}
|
||||
} else if b.Flags&Lshortfile != 0 {
|
||||
startIndex := strings.LastIndexByte(file, '/')
|
||||
if startIndex > 0 && startIndex < len(file) {
|
||||
file = file[startIndex+1:]
|
||||
}
|
||||
}
|
||||
*buf = append(*buf, file...)
|
||||
*buf = append(*buf, ':')
|
||||
itoa(buf, event.line, -1)
|
||||
if b.Flags&(Lfuncname|Lshortfuncname) != 0 {
|
||||
*buf = append(*buf, ':')
|
||||
} else {
|
||||
if b.Colorize {
|
||||
*buf = append(*buf, resetBytes...)
|
||||
}
|
||||
*buf = append(*buf, ' ')
|
||||
}
|
||||
}
|
||||
if b.Flags&(Lfuncname|Lshortfuncname) != 0 {
|
||||
if b.Colorize {
|
||||
*buf = append(*buf, fgGreenBytes...)
|
||||
}
|
||||
funcname := event.caller
|
||||
if b.Flags&Lshortfuncname != 0 {
|
||||
lastIndex := strings.LastIndexByte(funcname, '.')
|
||||
if lastIndex > 0 && len(funcname) > lastIndex+1 {
|
||||
funcname = funcname[lastIndex+1:]
|
||||
}
|
||||
}
|
||||
*buf = append(*buf, funcname...)
|
||||
if b.Colorize {
|
||||
*buf = append(*buf, resetBytes...)
|
||||
}
|
||||
*buf = append(*buf, ' ')
|
||||
|
||||
}
|
||||
if b.Flags&(Llevel|Llevelinitial) != 0 {
|
||||
level := strings.ToUpper(event.level.String())
|
||||
if b.Colorize {
|
||||
*buf = append(*buf, levelToColor[event.level]...)
|
||||
}
|
||||
*buf = append(*buf, '[')
|
||||
if b.Flags&Llevelinitial != 0 {
|
||||
*buf = append(*buf, level[0])
|
||||
} else {
|
||||
*buf = append(*buf, level...)
|
||||
}
|
||||
*buf = append(*buf, ']')
|
||||
if b.Colorize {
|
||||
*buf = append(*buf, resetBytes...)
|
||||
}
|
||||
*buf = append(*buf, ' ')
|
||||
}
|
||||
|
||||
var msg = []byte(event.msg)
|
||||
if len(msg) > 0 && msg[len(msg)-1] == '\n' {
|
||||
msg = msg[:len(msg)-1]
|
||||
}
|
||||
|
||||
pawMode := allowColor
|
||||
if !b.Colorize {
|
||||
pawMode = removeColor
|
||||
}
|
||||
|
||||
baw := byteArrayWriter(*buf)
|
||||
(&protectedANSIWriter{
|
||||
w: &baw,
|
||||
mode: pawMode,
|
||||
}).Write([]byte(msg))
|
||||
*buf = baw
|
||||
|
||||
if event.stacktrace != "" && b.StacktraceLevel <= event.level {
|
||||
lines := bytes.Split([]byte(event.stacktrace), []byte("\n"))
|
||||
if len(lines) > 1 {
|
||||
for _, line := range lines {
|
||||
*buf = append(*buf, "\n\t"...)
|
||||
*buf = append(*buf, line...)
|
||||
}
|
||||
}
|
||||
*buf = append(*buf, '\n')
|
||||
}
|
||||
*buf = append(*buf, '\n')
|
||||
}
|
||||
|
||||
// LogEvent logs the event to the internal writer
|
||||
func (b *BaseLogger) LogEvent(event *Event) error {
|
||||
if b.Level > event.level {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
if !b.Match(event) {
|
||||
return nil
|
||||
}
|
||||
var buf []byte
|
||||
b.createMsg(&buf, event)
|
||||
_, err := b.out.Write(buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// Match checks if the given event matches the logger's regexp expression
|
||||
func (b *BaseLogger) Match(event *Event) bool {
|
||||
if b.regexp == nil {
|
||||
return true
|
||||
}
|
||||
if b.regexp.Match([]byte(fmt.Sprintf("%s:%d:%s", event.filename, event.line, event.caller))) {
|
||||
return true
|
||||
}
|
||||
// Match on the non-colored msg - therefore strip out colors
|
||||
var msg []byte
|
||||
baw := byteArrayWriter(msg)
|
||||
(&protectedANSIWriter{
|
||||
w: &baw,
|
||||
mode: removeColor,
|
||||
}).Write([]byte(event.msg))
|
||||
msg = baw
|
||||
if b.regexp.Match(msg) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Close the base logger
|
||||
func (b *BaseLogger) Close() {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
if b.out != nil {
|
||||
b.out.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// GetName returns empty for these provider loggers
|
||||
func (b *BaseLogger) GetName() string {
|
||||
return ""
|
||||
}
|
277
modules/log/base_test.go
Normal file
277
modules/log/base_test.go
Normal file
@ -0,0 +1,277 @@
|
||||
// Copyright 2019 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 log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type CallbackWriteCloser struct {
|
||||
callback func([]byte, bool)
|
||||
}
|
||||
|
||||
func (c CallbackWriteCloser) Write(p []byte) (int, error) {
|
||||
c.callback(p, false)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (c CallbackWriteCloser) Close() error {
|
||||
c.callback(nil, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestBaseLogger(t *testing.T) {
|
||||
var written []byte
|
||||
var closed bool
|
||||
|
||||
c := CallbackWriteCloser{
|
||||
callback: func(p []byte, close bool) {
|
||||
written = p
|
||||
closed = close
|
||||
},
|
||||
}
|
||||
prefix := "TestPrefix "
|
||||
b := BaseLogger{
|
||||
out: c,
|
||||
Level: INFO,
|
||||
Flags: LstdFlags | LUTC,
|
||||
Prefix: prefix,
|
||||
}
|
||||
location, _ := time.LoadLocation("EST")
|
||||
|
||||
date := time.Date(2019, time.January, 13, 22, 3, 30, 15, location)
|
||||
|
||||
dateString := date.UTC().Format("2006/01/02 15:04:05")
|
||||
|
||||
event := Event{
|
||||
level: INFO,
|
||||
msg: "TEST MSG",
|
||||
caller: "CALLER",
|
||||
filename: "FULL/FILENAME",
|
||||
line: 1,
|
||||
time: date,
|
||||
}
|
||||
|
||||
assert.Equal(t, INFO, b.GetLevel())
|
||||
|
||||
expected := fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
b.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
written = written[:0]
|
||||
|
||||
event.level = DEBUG
|
||||
expected = ""
|
||||
b.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
|
||||
event.level = TRACE
|
||||
expected = ""
|
||||
b.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
|
||||
event.level = WARN
|
||||
expected = fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
b.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
written = written[:0]
|
||||
|
||||
event.level = ERROR
|
||||
expected = fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
b.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
written = written[:0]
|
||||
|
||||
event.level = CRITICAL
|
||||
expected = fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
b.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
written = written[:0]
|
||||
|
||||
b.Close()
|
||||
assert.Equal(t, true, closed)
|
||||
}
|
||||
|
||||
func TestBaseLoggerDated(t *testing.T) {
|
||||
var written []byte
|
||||
var closed bool
|
||||
|
||||
c := CallbackWriteCloser{
|
||||
callback: func(p []byte, close bool) {
|
||||
written = p
|
||||
closed = close
|
||||
},
|
||||
}
|
||||
prefix := ""
|
||||
b := BaseLogger{
|
||||
out: c,
|
||||
Level: WARN,
|
||||
Flags: Ldate | Ltime | Lmicroseconds | Lshortfile | Llevel,
|
||||
Prefix: prefix,
|
||||
}
|
||||
|
||||
location, _ := time.LoadLocation("EST")
|
||||
|
||||
date := time.Date(2019, time.January, 13, 22, 3, 30, 115, location)
|
||||
|
||||
dateString := date.Format("2006/01/02 15:04:05.000000")
|
||||
|
||||
event := Event{
|
||||
level: WARN,
|
||||
msg: "TEST MESSAGE TEST\n",
|
||||
caller: "CALLER",
|
||||
filename: "FULL/FILENAME",
|
||||
line: 1,
|
||||
time: date,
|
||||
}
|
||||
|
||||
assert.Equal(t, WARN, b.GetLevel())
|
||||
|
||||
expected := fmt.Sprintf("%s%s %s:%d [%s] %s", prefix, dateString, "FILENAME", event.line, strings.ToUpper(event.level.String()), event.msg)
|
||||
b.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
written = written[:0]
|
||||
|
||||
event.level = INFO
|
||||
expected = ""
|
||||
b.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
written = written[:0]
|
||||
|
||||
event.level = ERROR
|
||||
expected = fmt.Sprintf("%s%s %s:%d [%s] %s", prefix, dateString, "FILENAME", event.line, strings.ToUpper(event.level.String()), event.msg)
|
||||
b.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
written = written[:0]
|
||||
|
||||
event.level = DEBUG
|
||||
expected = ""
|
||||
b.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
written = written[:0]
|
||||
|
||||
event.level = CRITICAL
|
||||
expected = fmt.Sprintf("%s%s %s:%d [%s] %s", prefix, dateString, "FILENAME", event.line, strings.ToUpper(event.level.String()), event.msg)
|
||||
b.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
written = written[:0]
|
||||
|
||||
event.level = TRACE
|
||||
expected = ""
|
||||
b.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
written = written[:0]
|
||||
|
||||
b.Close()
|
||||
assert.Equal(t, true, closed)
|
||||
}
|
||||
|
||||
func TestBaseLoggerMultiLineNoFlagsRegexp(t *testing.T) {
|
||||
var written []byte
|
||||
var closed bool
|
||||
|
||||
c := CallbackWriteCloser{
|
||||
callback: func(p []byte, close bool) {
|
||||
written = p
|
||||
closed = close
|
||||
},
|
||||
}
|
||||
prefix := ""
|
||||
b := BaseLogger{
|
||||
Level: DEBUG,
|
||||
StacktraceLevel: ERROR,
|
||||
Flags: -1,
|
||||
Prefix: prefix,
|
||||
Expression: "FILENAME",
|
||||
}
|
||||
b.createLogger(c)
|
||||
|
||||
location, _ := time.LoadLocation("EST")
|
||||
|
||||
date := time.Date(2019, time.January, 13, 22, 3, 30, 115, location)
|
||||
|
||||
event := Event{
|
||||
level: DEBUG,
|
||||
msg: "TEST\nMESSAGE\nTEST",
|
||||
caller: "CALLER",
|
||||
filename: "FULL/FILENAME",
|
||||
line: 1,
|
||||
time: date,
|
||||
}
|
||||
|
||||
assert.Equal(t, DEBUG, b.GetLevel())
|
||||
|
||||
expected := "TEST\n\tMESSAGE\n\tTEST\n"
|
||||
b.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
written = written[:0]
|
||||
|
||||
event.filename = "ELSEWHERE"
|
||||
|
||||
b.LogEvent(&event)
|
||||
assert.Equal(t, "", string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
written = written[:0]
|
||||
|
||||
event.caller = "FILENAME"
|
||||
b.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
written = written[:0]
|
||||
|
||||
event = Event{
|
||||
level: DEBUG,
|
||||
msg: "TEST\nFILENAME\nTEST",
|
||||
caller: "CALLER",
|
||||
filename: "FULL/ELSEWHERE",
|
||||
line: 1,
|
||||
time: date,
|
||||
}
|
||||
expected = "TEST\n\tFILENAME\n\tTEST\n"
|
||||
b.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
written = written[:0]
|
||||
|
||||
}
|
||||
|
||||
func TestBrokenRegexp(t *testing.T) {
|
||||
var closed bool
|
||||
|
||||
c := CallbackWriteCloser{
|
||||
callback: func(p []byte, close bool) {
|
||||
closed = close
|
||||
},
|
||||
}
|
||||
|
||||
b := BaseLogger{
|
||||
Level: DEBUG,
|
||||
StacktraceLevel: ERROR,
|
||||
Flags: -1,
|
||||
Prefix: prefix,
|
||||
Expression: "\\",
|
||||
}
|
||||
b.createLogger(c)
|
||||
assert.Empty(t, b.regexp)
|
||||
b.Close()
|
||||
assert.Equal(t, true, closed)
|
||||
}
|
348
modules/log/colors.go
Normal file
348
modules/log/colors.go
Normal file
@ -0,0 +1,348 @@
|
||||
// Copyright 2019 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 log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const escape = "\033"
|
||||
|
||||
// ColorAttribute defines a single SGR Code
|
||||
type ColorAttribute int
|
||||
|
||||
// Base ColorAttributes
|
||||
const (
|
||||
Reset ColorAttribute = iota
|
||||
Bold
|
||||
Faint
|
||||
Italic
|
||||
Underline
|
||||
BlinkSlow
|
||||
BlinkRapid
|
||||
ReverseVideo
|
||||
Concealed
|
||||
CrossedOut
|
||||
)
|
||||
|
||||
// Foreground text colors
|
||||
const (
|
||||
FgBlack ColorAttribute = iota + 30
|
||||
FgRed
|
||||
FgGreen
|
||||
FgYellow
|
||||
FgBlue
|
||||
FgMagenta
|
||||
FgCyan
|
||||
FgWhite
|
||||
)
|
||||
|
||||
// Foreground Hi-Intensity text colors
|
||||
const (
|
||||
FgHiBlack ColorAttribute = iota + 90
|
||||
FgHiRed
|
||||
FgHiGreen
|
||||
FgHiYellow
|
||||
FgHiBlue
|
||||
FgHiMagenta
|
||||
FgHiCyan
|
||||
FgHiWhite
|
||||
)
|
||||
|
||||
// Background text colors
|
||||
const (
|
||||
BgBlack ColorAttribute = iota + 40
|
||||
BgRed
|
||||
BgGreen
|
||||
BgYellow
|
||||
BgBlue
|
||||
BgMagenta
|
||||
BgCyan
|
||||
BgWhite
|
||||
)
|
||||
|
||||
// Background Hi-Intensity text colors
|
||||
const (
|
||||
BgHiBlack ColorAttribute = iota + 100
|
||||
BgHiRed
|
||||
BgHiGreen
|
||||
BgHiYellow
|
||||
BgHiBlue
|
||||
BgHiMagenta
|
||||
BgHiCyan
|
||||
BgHiWhite
|
||||
)
|
||||
|
||||
var colorAttributeToString = map[ColorAttribute]string{
|
||||
Reset: "Reset",
|
||||
Bold: "Bold",
|
||||
Faint: "Faint",
|
||||
Italic: "Italic",
|
||||
Underline: "Underline",
|
||||
BlinkSlow: "BlinkSlow",
|
||||
BlinkRapid: "BlinkRapid",
|
||||
ReverseVideo: "ReverseVideo",
|
||||
Concealed: "Concealed",
|
||||
CrossedOut: "CrossedOut",
|
||||
FgBlack: "FgBlack",
|
||||
FgRed: "FgRed",
|
||||
FgGreen: "FgGreen",
|
||||
FgYellow: "FgYellow",
|
||||
FgBlue: "FgBlue",
|
||||
FgMagenta: "FgMagenta",
|
||||
FgCyan: "FgCyan",
|
||||
FgWhite: "FgWhite",
|
||||
FgHiBlack: "FgHiBlack",
|
||||
FgHiRed: "FgHiRed",
|
||||
FgHiGreen: "FgHiGreen",
|
||||
FgHiYellow: "FgHiYellow",
|
||||
FgHiBlue: "FgHiBlue",
|
||||
FgHiMagenta: "FgHiMagenta",
|
||||
FgHiCyan: "FgHiCyan",
|
||||
FgHiWhite: "FgHiWhite",
|
||||
BgBlack: "BgBlack",
|
||||
BgRed: "BgRed",
|
||||
BgGreen: "BgGreen",
|
||||
BgYellow: "BgYellow",
|
||||
BgBlue: "BgBlue",
|
||||
BgMagenta: "BgMagenta",
|
||||
BgCyan: "BgCyan",
|
||||
BgWhite: "BgWhite",
|
||||
BgHiBlack: "BgHiBlack",
|
||||
BgHiRed: "BgHiRed",
|
||||
BgHiGreen: "BgHiGreen",
|
||||
BgHiYellow: "BgHiYellow",
|
||||
BgHiBlue: "BgHiBlue",
|
||||
BgHiMagenta: "BgHiMagenta",
|
||||
BgHiCyan: "BgHiCyan",
|
||||
BgHiWhite: "BgHiWhite",
|
||||
}
|
||||
|
||||
func (c *ColorAttribute) String() string {
|
||||
return colorAttributeToString[*c]
|
||||
}
|
||||
|
||||
var colorAttributeFromString = map[string]ColorAttribute{}
|
||||
|
||||
// ColorAttributeFromString will return a ColorAttribute given a string
|
||||
func ColorAttributeFromString(from string) ColorAttribute {
|
||||
lowerFrom := strings.TrimSpace(strings.ToLower(from))
|
||||
return colorAttributeFromString[lowerFrom]
|
||||
}
|
||||
|
||||
// ColorString converts a list of ColorAttributes to a color string
|
||||
func ColorString(attrs ...ColorAttribute) string {
|
||||
return string(ColorBytes(attrs...))
|
||||
}
|
||||
|
||||
// ColorBytes converts a list of ColorAttributes to a byte array
|
||||
func ColorBytes(attrs ...ColorAttribute) []byte {
|
||||
bytes := make([]byte, 0, 20)
|
||||
bytes = append(bytes, escape[0], '[')
|
||||
if len(attrs) > 0 {
|
||||
bytes = append(bytes, strconv.Itoa(int(attrs[0]))...)
|
||||
for _, a := range attrs[1:] {
|
||||
bytes = append(bytes, ';')
|
||||
bytes = append(bytes, strconv.Itoa(int(a))...)
|
||||
}
|
||||
} else {
|
||||
bytes = append(bytes, strconv.Itoa(int(Bold))...)
|
||||
}
|
||||
bytes = append(bytes, 'm')
|
||||
return bytes
|
||||
}
|
||||
|
||||
var levelToColor = map[Level]string{
|
||||
TRACE: ColorString(Bold, FgCyan),
|
||||
DEBUG: ColorString(Bold, FgBlue),
|
||||
INFO: ColorString(Bold, FgGreen),
|
||||
WARN: ColorString(Bold, FgYellow),
|
||||
ERROR: ColorString(Bold, FgRed),
|
||||
CRITICAL: ColorString(Bold, BgMagenta),
|
||||
FATAL: ColorString(Bold, BgRed),
|
||||
NONE: ColorString(Reset),
|
||||
}
|
||||
|
||||
var resetBytes = ColorBytes(Reset)
|
||||
var fgCyanBytes = ColorBytes(FgCyan)
|
||||
var fgGreenBytes = ColorBytes(FgGreen)
|
||||
var fgBoldBytes = ColorBytes(Bold)
|
||||
|
||||
type protectedANSIWriterMode int
|
||||
|
||||
const (
|
||||
escapeAll protectedANSIWriterMode = iota
|
||||
allowColor
|
||||
removeColor
|
||||
)
|
||||
|
||||
type protectedANSIWriter struct {
|
||||
w io.Writer
|
||||
mode protectedANSIWriterMode
|
||||
}
|
||||
|
||||
// Write will protect against unusual characters
|
||||
func (c *protectedANSIWriter) Write(bytes []byte) (int, error) {
|
||||
end := len(bytes)
|
||||
totalWritten := 0
|
||||
normalLoop:
|
||||
for i := 0; i < end; {
|
||||
lasti := i
|
||||
|
||||
if c.mode == escapeAll {
|
||||
for i < end && (bytes[i] >= ' ' || bytes[i] == '\n') {
|
||||
i++
|
||||
}
|
||||
} else {
|
||||
for i < end && bytes[i] >= ' ' {
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
if i > lasti {
|
||||
written, err := c.w.Write(bytes[lasti:i])
|
||||
totalWritten = totalWritten + written
|
||||
if err != nil {
|
||||
return totalWritten, err
|
||||
}
|
||||
|
||||
}
|
||||
if i >= end {
|
||||
break
|
||||
}
|
||||
|
||||
// If we're not just escaping all we should prefix all newlines with a \t
|
||||
if c.mode != escapeAll {
|
||||
if bytes[i] == '\n' {
|
||||
written, err := c.w.Write([]byte{'\n', '\t'})
|
||||
if written > 0 {
|
||||
totalWritten++
|
||||
}
|
||||
if err != nil {
|
||||
return totalWritten, err
|
||||
}
|
||||
i++
|
||||
continue normalLoop
|
||||
}
|
||||
|
||||
if bytes[i] == escape[0] && i+1 < end && bytes[i+1] == '[' {
|
||||
for j := i + 2; j < end; j++ {
|
||||
if bytes[j] >= '0' && bytes[j] <= '9' {
|
||||
continue
|
||||
}
|
||||
if bytes[j] == ';' {
|
||||
continue
|
||||
}
|
||||
if bytes[j] == 'm' {
|
||||
if c.mode == allowColor {
|
||||
written, err := c.w.Write(bytes[i : j+1])
|
||||
totalWritten = totalWritten + written
|
||||
if err != nil {
|
||||
return totalWritten, err
|
||||
}
|
||||
} else {
|
||||
totalWritten = j
|
||||
}
|
||||
i = j + 1
|
||||
continue normalLoop
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process naughty character
|
||||
if _, err := fmt.Fprintf(c.w, `\%#o03d`, bytes[i]); err != nil {
|
||||
return totalWritten, err
|
||||
}
|
||||
i++
|
||||
totalWritten++
|
||||
}
|
||||
return totalWritten, nil
|
||||
}
|
||||
|
||||
// ColoredValue will Color the provided value
|
||||
type ColoredValue struct {
|
||||
ColorBytes *[]byte
|
||||
ResetBytes *[]byte
|
||||
Value *interface{}
|
||||
}
|
||||
|
||||
// NewColoredValue is a helper function to create a ColoredValue from a Value
|
||||
// If no color is provided it defaults to Bold with standard Reset
|
||||
// If a ColoredValue is provided it is not changed
|
||||
func NewColoredValue(value interface{}, color ...ColorAttribute) *ColoredValue {
|
||||
return NewColoredValuePointer(&value, color...)
|
||||
}
|
||||
|
||||
// NewColoredValuePointer is a helper function to create a ColoredValue from a Value Pointer
|
||||
// If no color is provided it defaults to Bold with standard Reset
|
||||
// If a ColoredValue is provided it is not changed
|
||||
func NewColoredValuePointer(value *interface{}, color ...ColorAttribute) *ColoredValue {
|
||||
if val, ok := (*value).(*ColoredValue); ok {
|
||||
return val
|
||||
}
|
||||
if len(color) > 0 {
|
||||
bytes := ColorBytes(color...)
|
||||
return &ColoredValue{
|
||||
ColorBytes: &bytes,
|
||||
ResetBytes: &resetBytes,
|
||||
Value: value,
|
||||
}
|
||||
}
|
||||
return &ColoredValue{
|
||||
ColorBytes: &fgBoldBytes,
|
||||
ResetBytes: &resetBytes,
|
||||
Value: value,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// NewColoredValueBytes creates a value from the provided value with color bytes
|
||||
// If a ColoredValue is provided it is not changed
|
||||
func NewColoredValueBytes(value interface{}, colorBytes *[]byte) *ColoredValue {
|
||||
if val, ok := value.(*ColoredValue); ok {
|
||||
return val
|
||||
}
|
||||
return &ColoredValue{
|
||||
ColorBytes: colorBytes,
|
||||
ResetBytes: &resetBytes,
|
||||
Value: &value,
|
||||
}
|
||||
}
|
||||
|
||||
// Format will format the provided value and protect against ANSI spoofing within the value
|
||||
func (cv *ColoredValue) Format(s fmt.State, c rune) {
|
||||
s.Write([]byte(*cv.ColorBytes))
|
||||
fmt.Fprintf(&protectedANSIWriter{w: s}, fmtString(s, c), *(cv.Value))
|
||||
s.Write([]byte(*cv.ResetBytes))
|
||||
}
|
||||
|
||||
func fmtString(s fmt.State, c rune) string {
|
||||
var width, precision string
|
||||
base := make([]byte, 0, 8)
|
||||
base = append(base, '%')
|
||||
for _, c := range []byte(" +-#0") {
|
||||
if s.Flag(int(c)) {
|
||||
base = append(base, c)
|
||||
}
|
||||
}
|
||||
if w, ok := s.Width(); ok {
|
||||
width = strconv.Itoa(w)
|
||||
}
|
||||
if p, ok := s.Precision(); ok {
|
||||
precision = "." + strconv.Itoa(p)
|
||||
}
|
||||
return fmt.Sprintf("%s%s%s%c", base, width, precision, c)
|
||||
}
|
||||
|
||||
func init() {
|
||||
for attr, from := range colorAttributeToString {
|
||||
colorAttributeFromString[strings.ToLower(from)] = attr
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Copyright 2019 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.
|
||||
|
||||
@ -7,73 +8,60 @@ package log
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
)
|
||||
|
||||
// ConnWriter implements LoggerInterface.
|
||||
// it writes messages in keep-live tcp connection.
|
||||
type ConnWriter struct {
|
||||
lg *log.Logger
|
||||
type connWriter struct {
|
||||
innerWriter io.WriteCloser
|
||||
ReconnectOnMsg bool `json:"reconnectOnMsg"`
|
||||
Reconnect bool `json:"reconnect"`
|
||||
Net string `json:"net"`
|
||||
Addr string `json:"addr"`
|
||||
Level int `json:"level"`
|
||||
}
|
||||
|
||||
// NewConn creates new ConnWrite returning as LoggerInterface.
|
||||
func NewConn() LoggerInterface {
|
||||
conn := new(ConnWriter)
|
||||
conn.Level = TRACE
|
||||
return conn
|
||||
}
|
||||
|
||||
// Init inits connection writer with json config.
|
||||
// json config only need key "level".
|
||||
func (cw *ConnWriter) Init(jsonconfig string) error {
|
||||
return json.Unmarshal([]byte(jsonconfig), cw)
|
||||
}
|
||||
|
||||
// WriteMsg writes message in connection.
|
||||
// if connection is down, try to re-connect.
|
||||
func (cw *ConnWriter) WriteMsg(msg string, skip, level int) error {
|
||||
if cw.Level > level {
|
||||
return nil
|
||||
// Close the inner writer
|
||||
func (i *connWriter) Close() error {
|
||||
if i.innerWriter != nil {
|
||||
return i.innerWriter.Close()
|
||||
}
|
||||
if cw.neededConnectOnMsg() {
|
||||
if err := cw.connect(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if cw.ReconnectOnMsg {
|
||||
defer cw.innerWriter.Close()
|
||||
}
|
||||
cw.lg.Println(msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Flush no things for this implementation
|
||||
func (cw *ConnWriter) Flush() {
|
||||
}
|
||||
|
||||
// Destroy destroy connection writer and close tcp listener.
|
||||
func (cw *ConnWriter) Destroy() {
|
||||
if cw.innerWriter == nil {
|
||||
return
|
||||
}
|
||||
cw.innerWriter.Close()
|
||||
}
|
||||
|
||||
func (cw *ConnWriter) connect() error {
|
||||
if cw.innerWriter != nil {
|
||||
cw.innerWriter.Close()
|
||||
cw.innerWriter = nil
|
||||
// Write the data to the connection
|
||||
func (i *connWriter) Write(p []byte) (int, error) {
|
||||
if i.neededConnectOnMsg() {
|
||||
if err := i.connect(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
conn, err := net.Dial(cw.Net, cw.Addr)
|
||||
if i.ReconnectOnMsg {
|
||||
defer i.innerWriter.Close()
|
||||
}
|
||||
|
||||
return i.innerWriter.Write(p)
|
||||
}
|
||||
|
||||
func (i *connWriter) neededConnectOnMsg() bool {
|
||||
if i.Reconnect {
|
||||
i.Reconnect = false
|
||||
return true
|
||||
}
|
||||
|
||||
if i.innerWriter == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return i.ReconnectOnMsg
|
||||
}
|
||||
|
||||
func (i *connWriter) connect() error {
|
||||
if i.innerWriter != nil {
|
||||
i.innerWriter.Close()
|
||||
i.innerWriter = nil
|
||||
}
|
||||
|
||||
conn, err := net.Dial(i.Net, i.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -82,22 +70,50 @@ func (cw *ConnWriter) connect() error {
|
||||
tcpConn.SetKeepAlive(true)
|
||||
}
|
||||
|
||||
cw.innerWriter = conn
|
||||
cw.lg = log.New(conn, "", log.Ldate|log.Ltime)
|
||||
i.innerWriter = conn
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cw *ConnWriter) neededConnectOnMsg() bool {
|
||||
if cw.Reconnect {
|
||||
cw.Reconnect = false
|
||||
return true
|
||||
}
|
||||
// ConnLogger implements LoggerProvider.
|
||||
// it writes messages in keep-live tcp connection.
|
||||
type ConnLogger struct {
|
||||
BaseLogger
|
||||
ReconnectOnMsg bool `json:"reconnectOnMsg"`
|
||||
Reconnect bool `json:"reconnect"`
|
||||
Net string `json:"net"`
|
||||
Addr string `json:"addr"`
|
||||
}
|
||||
|
||||
if cw.innerWriter == nil {
|
||||
return true
|
||||
}
|
||||
// NewConn creates new ConnLogger returning as LoggerProvider.
|
||||
func NewConn() LoggerProvider {
|
||||
conn := new(ConnLogger)
|
||||
conn.Level = TRACE
|
||||
return conn
|
||||
}
|
||||
|
||||
return cw.ReconnectOnMsg
|
||||
// Init inits connection writer with json config.
|
||||
// json config only need key "level".
|
||||
func (log *ConnLogger) Init(jsonconfig string) error {
|
||||
err := json.Unmarshal([]byte(jsonconfig), log)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.createLogger(&connWriter{
|
||||
ReconnectOnMsg: log.ReconnectOnMsg,
|
||||
Reconnect: log.Reconnect,
|
||||
Net: log.Net,
|
||||
Addr: log.Addr,
|
||||
}, log.Level)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Flush does nothing for this implementation
|
||||
func (log *ConnLogger) Flush() {
|
||||
}
|
||||
|
||||
// GetName returns the default name for this implementation
|
||||
func (log *ConnLogger) GetName() string {
|
||||
return "conn"
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
240
modules/log/conn_test.go
Normal file
240
modules/log/conn_test.go
Normal file
@ -0,0 +1,240 @@
|
||||
// Copyright 2019 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 log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func listenReadAndClose(t *testing.T, l net.Listener, expected string) {
|
||||
conn, err := l.Accept()
|
||||
assert.NoError(t, err)
|
||||
defer conn.Close()
|
||||
written, err := ioutil.ReadAll(conn)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, string(written))
|
||||
return
|
||||
}
|
||||
|
||||
func TestConnLogger(t *testing.T) {
|
||||
var written []byte
|
||||
|
||||
protocol := "tcp"
|
||||
address := ":3099"
|
||||
|
||||
l, err := net.Listen(protocol, address)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
prefix := "TestPrefix "
|
||||
level := INFO
|
||||
flags := LstdFlags | LUTC | Lfuncname
|
||||
|
||||
logger := NewConn()
|
||||
connLogger := logger.(*ConnLogger)
|
||||
|
||||
logger.Init(fmt.Sprintf("{\"prefix\":\"%s\",\"level\":\"%s\",\"flags\":%d,\"reconnectOnMsg\":%t,\"reconnect\":%t,\"net\":\"%s\",\"addr\":\"%s\"}", prefix, level.String(), flags, true, true, protocol, address))
|
||||
|
||||
assert.Equal(t, flags, connLogger.Flags)
|
||||
assert.Equal(t, level, connLogger.Level)
|
||||
assert.Equal(t, level, logger.GetLevel())
|
||||
|
||||
location, _ := time.LoadLocation("EST")
|
||||
|
||||
date := time.Date(2019, time.January, 13, 22, 3, 30, 15, location)
|
||||
|
||||
dateString := date.UTC().Format("2006/01/02 15:04:05")
|
||||
|
||||
event := Event{
|
||||
level: INFO,
|
||||
msg: "TEST MSG",
|
||||
caller: "CALLER",
|
||||
filename: "FULL/FILENAME",
|
||||
line: 1,
|
||||
time: date,
|
||||
}
|
||||
expected := fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
listenReadAndClose(t, l, expected)
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
err := logger.LogEvent(&event)
|
||||
assert.NoError(t, err)
|
||||
}()
|
||||
wg.Wait()
|
||||
|
||||
written = written[:0]
|
||||
|
||||
event.level = WARN
|
||||
expected = fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
listenReadAndClose(t, l, expected)
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
err := logger.LogEvent(&event)
|
||||
assert.NoError(t, err)
|
||||
}()
|
||||
wg.Wait()
|
||||
|
||||
logger.Close()
|
||||
}
|
||||
|
||||
func TestConnLoggerBadConfig(t *testing.T) {
|
||||
logger := NewConn()
|
||||
|
||||
err := logger.Init("{")
|
||||
assert.Equal(t, "unexpected end of JSON input", err.Error())
|
||||
logger.Close()
|
||||
}
|
||||
|
||||
func TestConnLoggerCloseBeforeSend(t *testing.T) {
|
||||
protocol := "tcp"
|
||||
address := ":3099"
|
||||
|
||||
prefix := "TestPrefix "
|
||||
level := INFO
|
||||
flags := LstdFlags | LUTC | Lfuncname
|
||||
|
||||
logger := NewConn()
|
||||
|
||||
logger.Init(fmt.Sprintf("{\"prefix\":\"%s\",\"level\":\"%s\",\"flags\":%d,\"reconnectOnMsg\":%t,\"reconnect\":%t,\"net\":\"%s\",\"addr\":\"%s\"}", prefix, level.String(), flags, false, false, protocol, address))
|
||||
logger.Close()
|
||||
}
|
||||
|
||||
func TestConnLoggerFailConnect(t *testing.T) {
|
||||
protocol := "tcp"
|
||||
address := ":3099"
|
||||
|
||||
prefix := "TestPrefix "
|
||||
level := INFO
|
||||
flags := LstdFlags | LUTC | Lfuncname
|
||||
|
||||
logger := NewConn()
|
||||
|
||||
logger.Init(fmt.Sprintf("{\"prefix\":\"%s\",\"level\":\"%s\",\"flags\":%d,\"reconnectOnMsg\":%t,\"reconnect\":%t,\"net\":\"%s\",\"addr\":\"%s\"}", prefix, level.String(), flags, false, false, protocol, address))
|
||||
|
||||
assert.Equal(t, level, logger.GetLevel())
|
||||
|
||||
location, _ := time.LoadLocation("EST")
|
||||
|
||||
date := time.Date(2019, time.January, 13, 22, 3, 30, 15, location)
|
||||
|
||||
//dateString := date.UTC().Format("2006/01/02 15:04:05")
|
||||
|
||||
event := Event{
|
||||
level: INFO,
|
||||
msg: "TEST MSG",
|
||||
caller: "CALLER",
|
||||
filename: "FULL/FILENAME",
|
||||
line: 1,
|
||||
time: date,
|
||||
}
|
||||
|
||||
err := logger.LogEvent(&event)
|
||||
assert.Error(t, err)
|
||||
|
||||
logger.Close()
|
||||
}
|
||||
|
||||
func TestConnLoggerClose(t *testing.T) {
|
||||
var written []byte
|
||||
|
||||
protocol := "tcp"
|
||||
address := ":3099"
|
||||
|
||||
l, err := net.Listen(protocol, address)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
prefix := "TestPrefix "
|
||||
level := INFO
|
||||
flags := LstdFlags | LUTC | Lfuncname
|
||||
|
||||
logger := NewConn()
|
||||
connLogger := logger.(*ConnLogger)
|
||||
|
||||
logger.Init(fmt.Sprintf("{\"prefix\":\"%s\",\"level\":\"%s\",\"flags\":%d,\"reconnectOnMsg\":%t,\"reconnect\":%t,\"net\":\"%s\",\"addr\":\"%s\"}", prefix, level.String(), flags, false, false, protocol, address))
|
||||
|
||||
assert.Equal(t, flags, connLogger.Flags)
|
||||
assert.Equal(t, level, connLogger.Level)
|
||||
assert.Equal(t, level, logger.GetLevel())
|
||||
location, _ := time.LoadLocation("EST")
|
||||
|
||||
date := time.Date(2019, time.January, 13, 22, 3, 30, 15, location)
|
||||
|
||||
dateString := date.UTC().Format("2006/01/02 15:04:05")
|
||||
|
||||
event := Event{
|
||||
level: INFO,
|
||||
msg: "TEST MSG",
|
||||
caller: "CALLER",
|
||||
filename: "FULL/FILENAME",
|
||||
line: 1,
|
||||
time: date,
|
||||
}
|
||||
expected := fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
err := logger.LogEvent(&event)
|
||||
assert.NoError(t, err)
|
||||
logger.Close()
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
listenReadAndClose(t, l, expected)
|
||||
}()
|
||||
wg.Wait()
|
||||
|
||||
logger = NewConn()
|
||||
connLogger = logger.(*ConnLogger)
|
||||
|
||||
logger.Init(fmt.Sprintf("{\"prefix\":\"%s\",\"level\":\"%s\",\"flags\":%d,\"reconnectOnMsg\":%t,\"reconnect\":%t,\"net\":\"%s\",\"addr\":\"%s\"}", prefix, level.String(), flags, false, true, protocol, address))
|
||||
|
||||
assert.Equal(t, flags, connLogger.Flags)
|
||||
assert.Equal(t, level, connLogger.Level)
|
||||
assert.Equal(t, level, logger.GetLevel())
|
||||
|
||||
written = written[:0]
|
||||
|
||||
event.level = WARN
|
||||
expected = fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
listenReadAndClose(t, l, expected)
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
err := logger.LogEvent(&event)
|
||||
assert.NoError(t, err)
|
||||
logger.Close()
|
||||
|
||||
}()
|
||||
wg.Wait()
|
||||
logger.Flush()
|
||||
logger.Close()
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Copyright 2019 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.
|
||||
|
||||
@ -6,75 +7,72 @@ package log
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Brush brush type
|
||||
type Brush func(string) string
|
||||
// CanColorStdout reports if we can color the Stdout
|
||||
// Although we could do terminal sniffing and the like - in reality
|
||||
// most tools on *nix are happy to display ansi colors.
|
||||
// We will terminal sniff on Windows in console_windows.go
|
||||
var CanColorStdout = true
|
||||
|
||||
// NewBrush create a brush according color
|
||||
func NewBrush(color string) Brush {
|
||||
pre := "\033["
|
||||
reset := "\033[0m"
|
||||
return func(text string) string {
|
||||
return pre + color + "m" + text + reset
|
||||
}
|
||||
// CanColorStderr reports if we can color the Stderr
|
||||
var CanColorStderr = true
|
||||
|
||||
type nopWriteCloser struct {
|
||||
w io.WriteCloser
|
||||
}
|
||||
|
||||
var colors = []Brush{
|
||||
NewBrush("1;36"), // Trace cyan
|
||||
NewBrush("1;34"), // Debug blue
|
||||
NewBrush("1;32"), // Info green
|
||||
NewBrush("1;33"), // Warn yellow
|
||||
NewBrush("1;31"), // Error red
|
||||
NewBrush("1;35"), // Critical purple
|
||||
NewBrush("1;31"), // Fatal red
|
||||
func (n *nopWriteCloser) Write(p []byte) (int, error) {
|
||||
return n.w.Write(p)
|
||||
}
|
||||
|
||||
// ConsoleWriter implements LoggerInterface and writes messages to terminal.
|
||||
type ConsoleWriter struct {
|
||||
lg *log.Logger
|
||||
Level int `json:"level"`
|
||||
func (n *nopWriteCloser) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewConsole create ConsoleWriter returning as LoggerInterface.
|
||||
func NewConsole() LoggerInterface {
|
||||
return &ConsoleWriter{
|
||||
lg: log.New(os.Stdout, "", log.Ldate|log.Ltime),
|
||||
Level: TRACE,
|
||||
}
|
||||
// ConsoleLogger implements LoggerProvider and writes messages to terminal.
|
||||
type ConsoleLogger struct {
|
||||
BaseLogger
|
||||
Stderr bool `json:"stderr"`
|
||||
}
|
||||
|
||||
// NewConsoleLogger create ConsoleLogger returning as LoggerProvider.
|
||||
func NewConsoleLogger() LoggerProvider {
|
||||
log := &ConsoleLogger{}
|
||||
log.createLogger(&nopWriteCloser{
|
||||
w: os.Stdout,
|
||||
})
|
||||
return log
|
||||
}
|
||||
|
||||
// Init inits connection writer with json config.
|
||||
// json config only need key "level".
|
||||
func (cw *ConsoleWriter) Init(config string) error {
|
||||
return json.Unmarshal([]byte(config), cw)
|
||||
}
|
||||
|
||||
// WriteMsg writes message in console.
|
||||
// if OS is windows, ignore colors.
|
||||
func (cw *ConsoleWriter) WriteMsg(msg string, skip, level int) error {
|
||||
if cw.Level > level {
|
||||
return nil
|
||||
func (log *ConsoleLogger) Init(config string) error {
|
||||
err := json.Unmarshal([]byte(config), log)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if runtime.GOOS == "windows" {
|
||||
cw.lg.Println(msg)
|
||||
if log.Stderr {
|
||||
log.createLogger(&nopWriteCloser{
|
||||
w: os.Stderr,
|
||||
})
|
||||
} else {
|
||||
cw.lg.Println(colors[level](msg))
|
||||
log.createLogger(log.out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Flush when log should be flushed
|
||||
func (cw *ConsoleWriter) Flush() {
|
||||
func (log *ConsoleLogger) Flush() {
|
||||
}
|
||||
|
||||
// Destroy when writer is destroy
|
||||
func (cw *ConsoleWriter) Destroy() {
|
||||
// GetName returns the default name for this implementation
|
||||
func (log *ConsoleLogger) GetName() string {
|
||||
return "console"
|
||||
}
|
||||
|
||||
func init() {
|
||||
Register("console", NewConsole)
|
||||
Register("console", NewConsoleLogger)
|
||||
}
|
||||
|
137
modules/log/console_test.go
Normal file
137
modules/log/console_test.go
Normal file
@ -0,0 +1,137 @@
|
||||
// Copyright 2019 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 log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestConsoleLoggerBadConfig(t *testing.T) {
|
||||
logger := NewConsoleLogger()
|
||||
|
||||
err := logger.Init("{")
|
||||
assert.Equal(t, "unexpected end of JSON input", err.Error())
|
||||
logger.Close()
|
||||
}
|
||||
|
||||
func TestConsoleLoggerMinimalConfig(t *testing.T) {
|
||||
for _, level := range Levels() {
|
||||
var written []byte
|
||||
var closed bool
|
||||
|
||||
c := CallbackWriteCloser{
|
||||
callback: func(p []byte, close bool) {
|
||||
written = p
|
||||
closed = close
|
||||
},
|
||||
}
|
||||
prefix := ""
|
||||
flags := LstdFlags
|
||||
|
||||
cw := NewConsoleLogger()
|
||||
realCW := cw.(*ConsoleLogger)
|
||||
cw.Init(fmt.Sprintf("{\"level\":\"%s\"}", level))
|
||||
nwc := realCW.out.(*nopWriteCloser)
|
||||
nwc.w = c
|
||||
|
||||
assert.Equal(t, flags, realCW.Flags)
|
||||
assert.Equal(t, FromString(level), realCW.Level)
|
||||
assert.Equal(t, FromString(level), cw.GetLevel())
|
||||
assert.Equal(t, prefix, realCW.Prefix)
|
||||
assert.Equal(t, "", string(written))
|
||||
cw.Close()
|
||||
assert.Equal(t, false, closed)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestConsoleLogger(t *testing.T) {
|
||||
var written []byte
|
||||
var closed bool
|
||||
|
||||
c := CallbackWriteCloser{
|
||||
callback: func(p []byte, close bool) {
|
||||
written = p
|
||||
closed = close
|
||||
},
|
||||
}
|
||||
prefix := "TestPrefix "
|
||||
level := INFO
|
||||
flags := LstdFlags | LUTC | Lfuncname
|
||||
|
||||
cw := NewConsoleLogger()
|
||||
realCW := cw.(*ConsoleLogger)
|
||||
realCW.Colorize = false
|
||||
nwc := realCW.out.(*nopWriteCloser)
|
||||
nwc.w = c
|
||||
|
||||
cw.Init(fmt.Sprintf("{\"expression\":\"FILENAME\",\"prefix\":\"%s\",\"level\":\"%s\",\"flags\":%d}", prefix, level.String(), flags))
|
||||
|
||||
assert.Equal(t, flags, realCW.Flags)
|
||||
assert.Equal(t, level, realCW.Level)
|
||||
assert.Equal(t, level, cw.GetLevel())
|
||||
|
||||
location, _ := time.LoadLocation("EST")
|
||||
|
||||
date := time.Date(2019, time.January, 13, 22, 3, 30, 15, location)
|
||||
|
||||
dateString := date.UTC().Format("2006/01/02 15:04:05")
|
||||
|
||||
event := Event{
|
||||
level: INFO,
|
||||
msg: "TEST MSG",
|
||||
caller: "CALLER",
|
||||
filename: "FULL/FILENAME",
|
||||
line: 1,
|
||||
time: date,
|
||||
}
|
||||
|
||||
expected := fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
cw.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
written = written[:0]
|
||||
|
||||
event.level = DEBUG
|
||||
expected = ""
|
||||
cw.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
|
||||
event.level = TRACE
|
||||
expected = ""
|
||||
cw.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
|
||||
nonMatchEvent := Event{
|
||||
level: INFO,
|
||||
msg: "TEST MSG",
|
||||
caller: "CALLER",
|
||||
filename: "FULL/FI_LENAME",
|
||||
line: 1,
|
||||
time: date,
|
||||
}
|
||||
event.level = INFO
|
||||
expected = ""
|
||||
cw.LogEvent(&nonMatchEvent)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
|
||||
event.level = WARN
|
||||
expected = fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
cw.LogEvent(&event)
|
||||
assert.Equal(t, expected, string(written))
|
||||
assert.Equal(t, false, closed)
|
||||
written = written[:0]
|
||||
|
||||
cw.Close()
|
||||
assert.Equal(t, false, closed)
|
||||
}
|
43
modules/log/console_windows.go
Normal file
43
modules/log/console_windows.go
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2019 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 log
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func enableVTMode(console windows.Handle) bool {
|
||||
mode := uint32(0)
|
||||
err := windows.GetConsoleMode(console, &mode)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// EnableVirtualTerminalProcessing is the console mode to allow ANSI code
|
||||
// interpretation on the console. See:
|
||||
// https://docs.microsoft.com/en-us/windows/console/setconsolemode
|
||||
// It only works on windows 10. Earlier terminals will fail with an err which we will
|
||||
// handle to say don't color
|
||||
mode = mode | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
err = windows.SetConsoleMode(console, mode)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
if isatty.IsTerminal(os.Stdout.Fd()) {
|
||||
CanColorStdout = enableVTMode(windows.Stdout)
|
||||
} else {
|
||||
CanColorStdout = isatty.IsCygwinTerminal(os.Stderr.Fd())
|
||||
}
|
||||
|
||||
if isatty.IsTerminal(os.Stderr.Fd()) {
|
||||
CanColorStderr = enableVTMode(windows.Stderr)
|
||||
} else {
|
||||
CanColorStderr = isatty.IsCygwinTerminal(os.Stderr.Fd())
|
||||
}
|
||||
}
|
62
modules/log/errors.go
Normal file
62
modules/log/errors.go
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright 2019 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 log
|
||||
|
||||
import "fmt"
|
||||
|
||||
// ErrTimeout represents a "Timeout" kind of error.
|
||||
type ErrTimeout struct {
|
||||
Name string
|
||||
Provider string
|
||||
}
|
||||
|
||||
// IsErrTimeout checks if an error is a ErrTimeout.
|
||||
func IsErrTimeout(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := err.(ErrTimeout)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrTimeout) Error() string {
|
||||
return fmt.Sprintf("Log Timeout for %s (%s)", err.Name, err.Provider)
|
||||
}
|
||||
|
||||
// ErrUnknownProvider represents a "Unknown Provider" kind of error.
|
||||
type ErrUnknownProvider struct {
|
||||
Provider string
|
||||
}
|
||||
|
||||
// IsErrUnknownProvider checks if an error is a ErrUnknownProvider.
|
||||
func IsErrUnknownProvider(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := err.(ErrUnknownProvider)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrUnknownProvider) Error() string {
|
||||
return fmt.Sprintf("Unknown Log Provider \"%s\" (Was it registered?)", err.Provider)
|
||||
}
|
||||
|
||||
// ErrDuplicateName represents a Duplicate Name error
|
||||
type ErrDuplicateName struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
// IsErrDuplicateName checks if an error is a ErrDuplicateName.
|
||||
func IsErrDuplicateName(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := err.(ErrDuplicateName)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrDuplicateName) Error() string {
|
||||
return fmt.Sprintf("Duplicate named logger: %s", err.Name)
|
||||
}
|
335
modules/log/event.go
Normal file
335
modules/log/event.go
Normal file
@ -0,0 +1,335 @@
|
||||
// Copyright 2019 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 log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Event represents a logging event
|
||||
type Event struct {
|
||||
level Level
|
||||
msg string
|
||||
caller string
|
||||
filename string
|
||||
line int
|
||||
time time.Time
|
||||
stacktrace string
|
||||
}
|
||||
|
||||
// EventLogger represents the behaviours of a logger
|
||||
type EventLogger interface {
|
||||
LogEvent(event *Event) error
|
||||
Close()
|
||||
Flush()
|
||||
GetLevel() Level
|
||||
GetStacktraceLevel() Level
|
||||
GetName() string
|
||||
}
|
||||
|
||||
// ChannelledLog represents a cached channel to a LoggerProvider
|
||||
type ChannelledLog struct {
|
||||
name string
|
||||
provider string
|
||||
queue chan *Event
|
||||
loggerProvider LoggerProvider
|
||||
flush chan bool
|
||||
close chan bool
|
||||
closed chan bool
|
||||
}
|
||||
|
||||
// NewChannelledLog a new logger instance with given logger provider and config.
|
||||
func NewChannelledLog(name, provider, config string, bufferLength int64) (*ChannelledLog, error) {
|
||||
if log, ok := providers[provider]; ok {
|
||||
l := &ChannelledLog{
|
||||
queue: make(chan *Event, bufferLength),
|
||||
flush: make(chan bool),
|
||||
close: make(chan bool),
|
||||
closed: make(chan bool),
|
||||
}
|
||||
l.loggerProvider = log()
|
||||
if err := l.loggerProvider.Init(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l.name = name
|
||||
l.provider = provider
|
||||
go l.Start()
|
||||
return l, nil
|
||||
}
|
||||
return nil, ErrUnknownProvider{provider}
|
||||
}
|
||||
|
||||
// Start processing the ChannelledLog
|
||||
func (l *ChannelledLog) Start() {
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-l.queue:
|
||||
if !ok {
|
||||
l.closeLogger()
|
||||
return
|
||||
}
|
||||
l.loggerProvider.LogEvent(event)
|
||||
case _, ok := <-l.flush:
|
||||
if !ok {
|
||||
l.closeLogger()
|
||||
return
|
||||
}
|
||||
l.loggerProvider.Flush()
|
||||
case _, _ = <-l.close:
|
||||
l.closeLogger()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LogEvent logs an event to this ChannelledLog
|
||||
func (l *ChannelledLog) LogEvent(event *Event) error {
|
||||
select {
|
||||
case l.queue <- event:
|
||||
return nil
|
||||
case <-time.After(60 * time.Second):
|
||||
// We're blocked!
|
||||
return ErrTimeout{
|
||||
Name: l.name,
|
||||
Provider: l.provider,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ChannelledLog) closeLogger() {
|
||||
l.loggerProvider.Flush()
|
||||
l.loggerProvider.Close()
|
||||
l.closed <- true
|
||||
return
|
||||
}
|
||||
|
||||
// Close this ChannelledLog
|
||||
func (l *ChannelledLog) Close() {
|
||||
l.close <- true
|
||||
<-l.closed
|
||||
}
|
||||
|
||||
// Flush this ChannelledLog
|
||||
func (l *ChannelledLog) Flush() {
|
||||
l.flush <- true
|
||||
}
|
||||
|
||||
// GetLevel gets the level of this ChannelledLog
|
||||
func (l *ChannelledLog) GetLevel() Level {
|
||||
return l.loggerProvider.GetLevel()
|
||||
}
|
||||
|
||||
// GetStacktraceLevel gets the level of this ChannelledLog
|
||||
func (l *ChannelledLog) GetStacktraceLevel() Level {
|
||||
return l.loggerProvider.GetStacktraceLevel()
|
||||
}
|
||||
|
||||
// GetName returns the name of this ChannelledLog
|
||||
func (l *ChannelledLog) GetName() string {
|
||||
return l.name
|
||||
}
|
||||
|
||||
// MultiChannelledLog represents a cached channel to a LoggerProvider
|
||||
type MultiChannelledLog struct {
|
||||
name string
|
||||
bufferLength int64
|
||||
queue chan *Event
|
||||
mutex sync.Mutex
|
||||
loggers map[string]EventLogger
|
||||
flush chan bool
|
||||
close chan bool
|
||||
started bool
|
||||
level Level
|
||||
stacktraceLevel Level
|
||||
closed chan bool
|
||||
}
|
||||
|
||||
// NewMultiChannelledLog a new logger instance with given logger provider and config.
|
||||
func NewMultiChannelledLog(name string, bufferLength int64) *MultiChannelledLog {
|
||||
m := &MultiChannelledLog{
|
||||
name: name,
|
||||
queue: make(chan *Event, bufferLength),
|
||||
flush: make(chan bool),
|
||||
bufferLength: bufferLength,
|
||||
loggers: make(map[string]EventLogger),
|
||||
level: NONE,
|
||||
stacktraceLevel: NONE,
|
||||
close: make(chan bool),
|
||||
closed: make(chan bool),
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// AddLogger adds a logger to this MultiChannelledLog
|
||||
func (m *MultiChannelledLog) AddLogger(logger EventLogger) error {
|
||||
m.mutex.Lock()
|
||||
name := logger.GetName()
|
||||
if _, has := m.loggers[name]; has {
|
||||
m.mutex.Unlock()
|
||||
return ErrDuplicateName{name}
|
||||
}
|
||||
m.loggers[name] = logger
|
||||
if logger.GetLevel() < m.level {
|
||||
m.level = logger.GetLevel()
|
||||
}
|
||||
if logger.GetStacktraceLevel() < m.stacktraceLevel {
|
||||
m.stacktraceLevel = logger.GetStacktraceLevel()
|
||||
}
|
||||
m.mutex.Unlock()
|
||||
go m.Start()
|
||||
return nil
|
||||
}
|
||||
|
||||
// DelLogger removes a sub logger from this MultiChannelledLog
|
||||
// NB: If you delete the last sublogger this logger will simply drop
|
||||
// log events
|
||||
func (m *MultiChannelledLog) DelLogger(name string) bool {
|
||||
m.mutex.Lock()
|
||||
logger, has := m.loggers[name]
|
||||
if !has {
|
||||
m.mutex.Unlock()
|
||||
return false
|
||||
}
|
||||
delete(m.loggers, name)
|
||||
m.internalResetLevel()
|
||||
m.mutex.Unlock()
|
||||
logger.Flush()
|
||||
logger.Close()
|
||||
return true
|
||||
}
|
||||
|
||||
// GetEventLogger returns a sub logger from this MultiChannelledLog
|
||||
func (m *MultiChannelledLog) GetEventLogger(name string) EventLogger {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
return m.loggers[name]
|
||||
}
|
||||
|
||||
// GetEventLoggerNames returns a list of names
|
||||
func (m *MultiChannelledLog) GetEventLoggerNames() []string {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
var keys []string
|
||||
for k := range m.loggers {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func (m *MultiChannelledLog) closeLoggers() {
|
||||
m.mutex.Lock()
|
||||
for _, logger := range m.loggers {
|
||||
logger.Flush()
|
||||
logger.Close()
|
||||
}
|
||||
m.mutex.Unlock()
|
||||
m.closed <- true
|
||||
return
|
||||
}
|
||||
|
||||
// Start processing the MultiChannelledLog
|
||||
func (m *MultiChannelledLog) Start() {
|
||||
m.mutex.Lock()
|
||||
if m.started {
|
||||
m.mutex.Unlock()
|
||||
return
|
||||
}
|
||||
m.started = true
|
||||
m.mutex.Unlock()
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-m.queue:
|
||||
if !ok {
|
||||
m.closeLoggers()
|
||||
return
|
||||
}
|
||||
m.mutex.Lock()
|
||||
for _, logger := range m.loggers {
|
||||
err := logger.LogEvent(event)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
m.mutex.Unlock()
|
||||
case _, ok := <-m.flush:
|
||||
if !ok {
|
||||
m.closeLoggers()
|
||||
return
|
||||
}
|
||||
m.mutex.Lock()
|
||||
for _, logger := range m.loggers {
|
||||
logger.Flush()
|
||||
}
|
||||
m.mutex.Unlock()
|
||||
case <-m.close:
|
||||
m.closeLoggers()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LogEvent logs an event to this MultiChannelledLog
|
||||
func (m *MultiChannelledLog) LogEvent(event *Event) error {
|
||||
select {
|
||||
case m.queue <- event:
|
||||
return nil
|
||||
case <-time.After(60 * time.Second):
|
||||
// We're blocked!
|
||||
return ErrTimeout{
|
||||
Name: m.name,
|
||||
Provider: "MultiChannelledLog",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close this MultiChannelledLog
|
||||
func (m *MultiChannelledLog) Close() {
|
||||
m.close <- true
|
||||
<-m.closed
|
||||
}
|
||||
|
||||
// Flush this ChannelledLog
|
||||
func (m *MultiChannelledLog) Flush() {
|
||||
m.flush <- true
|
||||
}
|
||||
|
||||
// GetLevel gets the level of this MultiChannelledLog
|
||||
func (m *MultiChannelledLog) GetLevel() Level {
|
||||
return m.level
|
||||
}
|
||||
|
||||
// GetStacktraceLevel gets the level of this MultiChannelledLog
|
||||
func (m *MultiChannelledLog) GetStacktraceLevel() Level {
|
||||
return m.stacktraceLevel
|
||||
}
|
||||
|
||||
func (m *MultiChannelledLog) internalResetLevel() Level {
|
||||
m.level = NONE
|
||||
for _, logger := range m.loggers {
|
||||
level := logger.GetLevel()
|
||||
if level < m.level {
|
||||
m.level = level
|
||||
}
|
||||
level = logger.GetStacktraceLevel()
|
||||
if level < m.stacktraceLevel {
|
||||
m.stacktraceLevel = level
|
||||
}
|
||||
}
|
||||
return m.level
|
||||
}
|
||||
|
||||
// ResetLevel will reset the level of this MultiChannelledLog
|
||||
func (m *MultiChannelledLog) ResetLevel() Level {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
return m.internalResetLevel()
|
||||
}
|
||||
|
||||
// GetName gets the name of this MultiChannelledLog
|
||||
func (m *MultiChannelledLog) GetName() string {
|
||||
return m.name
|
||||
}
|
@ -5,10 +5,11 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@ -16,10 +17,10 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// FileLogWriter implements LoggerInterface.
|
||||
// FileLogger implements LoggerProvider.
|
||||
// It writes messages by lines limit, file size limit, or time frequency.
|
||||
type FileLogWriter struct {
|
||||
*log.Logger
|
||||
type FileLogger struct {
|
||||
BaseLogger
|
||||
mw *MuxWriter
|
||||
// The opened file
|
||||
Filename string `json:"filename"`
|
||||
@ -35,47 +36,57 @@ type FileLogWriter struct {
|
||||
|
||||
Rotate bool `json:"rotate"`
|
||||
|
||||
startLock sync.Mutex // Only one log can write to the file
|
||||
Compress bool `json:"compress"`
|
||||
CompressionLevel int `json:"compressionLevel"`
|
||||
|
||||
Level int `json:"level"`
|
||||
startLock sync.Mutex // Only one log can write to the file
|
||||
}
|
||||
|
||||
// MuxWriter an *os.File writer with locker.
|
||||
type MuxWriter struct {
|
||||
sync.Mutex
|
||||
fd *os.File
|
||||
mu sync.Mutex
|
||||
fd *os.File
|
||||
owner *FileLogger
|
||||
}
|
||||
|
||||
// Write writes to os.File.
|
||||
func (l *MuxWriter) Write(b []byte) (int, error) {
|
||||
l.Lock()
|
||||
defer l.Unlock()
|
||||
return l.fd.Write(b)
|
||||
func (mw *MuxWriter) Write(b []byte) (int, error) {
|
||||
mw.mu.Lock()
|
||||
defer mw.mu.Unlock()
|
||||
mw.owner.docheck(len(b))
|
||||
return mw.fd.Write(b)
|
||||
}
|
||||
|
||||
// Close the internal writer
|
||||
func (mw *MuxWriter) Close() error {
|
||||
return mw.fd.Close()
|
||||
}
|
||||
|
||||
// SetFd sets os.File in writer.
|
||||
func (l *MuxWriter) SetFd(fd *os.File) {
|
||||
if l.fd != nil {
|
||||
l.fd.Close()
|
||||
func (mw *MuxWriter) SetFd(fd *os.File) {
|
||||
if mw.fd != nil {
|
||||
mw.fd.Close()
|
||||
}
|
||||
l.fd = fd
|
||||
mw.fd = fd
|
||||
}
|
||||
|
||||
// NewFileWriter create a FileLogWriter returning as LoggerInterface.
|
||||
func NewFileWriter() LoggerInterface {
|
||||
w := &FileLogWriter{
|
||||
Filename: "",
|
||||
Maxsize: 1 << 28, //256 MB
|
||||
Daily: true,
|
||||
Maxdays: 7,
|
||||
Rotate: true,
|
||||
Level: TRACE,
|
||||
// NewFileLogger create a FileLogger returning as LoggerProvider.
|
||||
func NewFileLogger() LoggerProvider {
|
||||
log := &FileLogger{
|
||||
Filename: "",
|
||||
Maxsize: 1 << 28, //256 MB
|
||||
Daily: true,
|
||||
Maxdays: 7,
|
||||
Rotate: true,
|
||||
Compress: true,
|
||||
CompressionLevel: gzip.DefaultCompression,
|
||||
}
|
||||
log.Level = TRACE
|
||||
// use MuxWriter instead direct use os.File for lock write when rotate
|
||||
w.mw = new(MuxWriter)
|
||||
// set MuxWriter as Logger's io.Writer
|
||||
w.Logger = log.New(w.mw, "", log.Ldate|log.Ltime)
|
||||
return w
|
||||
log.mw = new(MuxWriter)
|
||||
log.mw.owner = log
|
||||
|
||||
return log
|
||||
}
|
||||
|
||||
// Init file logger with json config.
|
||||
@ -87,109 +98,131 @@ func NewFileWriter() LoggerInterface {
|
||||
// "maxdays":15,
|
||||
// "rotate":true
|
||||
// }
|
||||
func (w *FileLogWriter) Init(config string) error {
|
||||
if err := json.Unmarshal([]byte(config), w); err != nil {
|
||||
func (log *FileLogger) Init(config string) error {
|
||||
if err := json.Unmarshal([]byte(config), log); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(w.Filename) == 0 {
|
||||
if len(log.Filename) == 0 {
|
||||
return errors.New("config must have filename")
|
||||
}
|
||||
return w.StartLogger()
|
||||
// set MuxWriter as Logger's io.Writer
|
||||
log.createLogger(log.mw)
|
||||
return log.StartLogger()
|
||||
}
|
||||
|
||||
// StartLogger start file logger. create log file and set to locker-inside file writer.
|
||||
func (w *FileLogWriter) StartLogger() error {
|
||||
fd, err := w.createLogFile()
|
||||
func (log *FileLogger) StartLogger() error {
|
||||
fd, err := log.createLogFile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.mw.SetFd(fd)
|
||||
return w.initFd()
|
||||
log.mw.SetFd(fd)
|
||||
return log.initFd()
|
||||
}
|
||||
|
||||
func (w *FileLogWriter) docheck(size int) {
|
||||
w.startLock.Lock()
|
||||
defer w.startLock.Unlock()
|
||||
if w.Rotate && ((w.Maxsize > 0 && w.maxsizeCursize >= w.Maxsize) ||
|
||||
(w.Daily && time.Now().Day() != w.dailyOpenDate)) {
|
||||
if err := w.DoRotate(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err)
|
||||
func (log *FileLogger) docheck(size int) {
|
||||
log.startLock.Lock()
|
||||
defer log.startLock.Unlock()
|
||||
if log.Rotate && ((log.Maxsize > 0 && log.maxsizeCursize >= log.Maxsize) ||
|
||||
(log.Daily && time.Now().Day() != log.dailyOpenDate)) {
|
||||
if err := log.DoRotate(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "FileLogger(%q): %s\n", log.Filename, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
w.maxsizeCursize += size
|
||||
log.maxsizeCursize += size
|
||||
}
|
||||
|
||||
// WriteMsg writes logger message into file.
|
||||
func (w *FileLogWriter) WriteMsg(msg string, skip, level int) error {
|
||||
if level < w.Level {
|
||||
return nil
|
||||
}
|
||||
n := 24 + len(msg) // 24 stand for the length "2013/06/23 21:00:22 [T] "
|
||||
w.docheck(n)
|
||||
w.Logger.Println(msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *FileLogWriter) createLogFile() (*os.File, error) {
|
||||
func (log *FileLogger) createLogFile() (*os.File, error) {
|
||||
// Open the log file
|
||||
return os.OpenFile(w.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660)
|
||||
return os.OpenFile(log.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660)
|
||||
}
|
||||
|
||||
func (w *FileLogWriter) initFd() error {
|
||||
fd := w.mw.fd
|
||||
func (log *FileLogger) initFd() error {
|
||||
fd := log.mw.fd
|
||||
finfo, err := fd.Stat()
|
||||
if err != nil {
|
||||
return fmt.Errorf("get stat: %v", err)
|
||||
}
|
||||
w.maxsizeCursize = int(finfo.Size())
|
||||
w.dailyOpenDate = time.Now().Day()
|
||||
log.maxsizeCursize = int(finfo.Size())
|
||||
log.dailyOpenDate = time.Now().Day()
|
||||
return nil
|
||||
}
|
||||
|
||||
// DoRotate means it need to write file in new file.
|
||||
// new file name like xx.log.2013-01-01.2
|
||||
func (w *FileLogWriter) DoRotate() error {
|
||||
_, err := os.Lstat(w.Filename)
|
||||
func (log *FileLogger) DoRotate() error {
|
||||
_, err := os.Lstat(log.Filename)
|
||||
if err == nil { // file exists
|
||||
// Find the next available number
|
||||
num := 1
|
||||
fname := ""
|
||||
for ; err == nil && num <= 999; num++ {
|
||||
fname = w.Filename + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), num)
|
||||
fname = log.Filename + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), num)
|
||||
_, err = os.Lstat(fname)
|
||||
if log.Compress && err != nil {
|
||||
_, err = os.Lstat(fname + ".gz")
|
||||
}
|
||||
}
|
||||
// return error if the last file checked still existed
|
||||
if err == nil {
|
||||
return fmt.Errorf("rotate: cannot find free log number to rename %s", w.Filename)
|
||||
return fmt.Errorf("rotate: cannot find free log number to rename %s", log.Filename)
|
||||
}
|
||||
|
||||
// block Logger's io.Writer
|
||||
w.mw.Lock()
|
||||
defer w.mw.Unlock()
|
||||
|
||||
fd := w.mw.fd
|
||||
fd := log.mw.fd
|
||||
fd.Close()
|
||||
|
||||
// close fd before rename
|
||||
// Rename the file to its newfound home
|
||||
if err = os.Rename(w.Filename, fname); err != nil {
|
||||
if err = os.Rename(log.Filename, fname); err != nil {
|
||||
return fmt.Errorf("Rotate: %v", err)
|
||||
}
|
||||
|
||||
if log.Compress {
|
||||
go compressOldLogFile(fname, log.CompressionLevel)
|
||||
}
|
||||
|
||||
// re-start logger
|
||||
if err = w.StartLogger(); err != nil {
|
||||
if err = log.StartLogger(); err != nil {
|
||||
return fmt.Errorf("Rotate StartLogger: %v", err)
|
||||
}
|
||||
|
||||
go w.deleteOldLog()
|
||||
go log.deleteOldLog()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *FileLogWriter) deleteOldLog() {
|
||||
dir := filepath.Dir(w.Filename)
|
||||
func compressOldLogFile(fname string, compressionLevel int) error {
|
||||
reader, err := os.Open(fname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer reader.Close()
|
||||
buffer := bufio.NewReader(reader)
|
||||
fw, err := os.OpenFile(fname+".gz", os.O_WRONLY|os.O_CREATE, 0660)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fw.Close()
|
||||
zw, err := gzip.NewWriterLevel(fw, compressionLevel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer zw.Close()
|
||||
_, err = buffer.WriteTo(zw)
|
||||
if err != nil {
|
||||
zw.Close()
|
||||
fw.Close()
|
||||
os.Remove(fname + ".gz")
|
||||
return err
|
||||
}
|
||||
reader.Close()
|
||||
return os.Remove(fname)
|
||||
}
|
||||
|
||||
func (log *FileLogger) deleteOldLog() {
|
||||
dir := filepath.Dir(log.Filename)
|
||||
filepath.Walk(dir, func(path string, info os.FileInfo, err error) (returnErr error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
@ -197,8 +230,8 @@ func (w *FileLogWriter) deleteOldLog() {
|
||||
}
|
||||
}()
|
||||
|
||||
if !info.IsDir() && info.ModTime().Unix() < (time.Now().Unix()-60*60*24*w.Maxdays) {
|
||||
if strings.HasPrefix(filepath.Base(path), filepath.Base(w.Filename)) {
|
||||
if !info.IsDir() && info.ModTime().Unix() < (time.Now().Unix()-60*60*24*log.Maxdays) {
|
||||
if strings.HasPrefix(filepath.Base(path), filepath.Base(log.Filename)) {
|
||||
|
||||
if err := os.Remove(path); err != nil {
|
||||
returnErr = fmt.Errorf("Failed to remove %s: %v", path, err)
|
||||
@ -209,18 +242,18 @@ func (w *FileLogWriter) deleteOldLog() {
|
||||
})
|
||||
}
|
||||
|
||||
// Destroy destroy file logger, close file writer.
|
||||
func (w *FileLogWriter) Destroy() {
|
||||
w.mw.fd.Close()
|
||||
}
|
||||
|
||||
// Flush flush file logger.
|
||||
// there are no buffering messages in file logger in memory.
|
||||
// flush file means sync file from disk.
|
||||
func (w *FileLogWriter) Flush() {
|
||||
w.mw.fd.Sync()
|
||||
func (log *FileLogger) Flush() {
|
||||
log.mw.fd.Sync()
|
||||
}
|
||||
|
||||
// GetName returns the default name for this implementation
|
||||
func (log *FileLogger) GetName() string {
|
||||
return "file"
|
||||
}
|
||||
|
||||
func init() {
|
||||
Register("file", NewFileWriter)
|
||||
Register("file", NewFileLogger)
|
||||
}
|
||||
|
247
modules/log/file_test.go
Normal file
247
modules/log/file_test.go
Normal file
@ -0,0 +1,247 @@
|
||||
// Copyright 2019 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 log
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFileLoggerFails(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir("", "TestFileLogger")
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
prefix := "TestPrefix "
|
||||
level := INFO
|
||||
flags := LstdFlags | LUTC | Lfuncname
|
||||
//filename := filepath.Join(tmpDir, "test.log")
|
||||
|
||||
fileLogger := NewFileLogger()
|
||||
//realFileLogger, ok := fileLogger.(*FileLogger)
|
||||
//assert.Equal(t, true, ok)
|
||||
|
||||
// Fail if there is bad json
|
||||
err = fileLogger.Init("{")
|
||||
assert.Error(t, err)
|
||||
|
||||
// Fail if there is no filename
|
||||
err = fileLogger.Init(fmt.Sprintf("{\"prefix\":\"%s\",\"level\":\"%s\",\"flags\":%d,\"filename\":\"%s\"}", prefix, level.String(), flags, ""))
|
||||
assert.Error(t, err)
|
||||
|
||||
// Fail if the file isn't a filename
|
||||
err = fileLogger.Init(fmt.Sprintf("{\"prefix\":\"%s\",\"level\":\"%s\",\"flags\":%d,\"filename\":\"%s\"}", prefix, level.String(), flags, filepath.ToSlash(tmpDir)))
|
||||
assert.Error(t, err)
|
||||
|
||||
}
|
||||
|
||||
func TestFileLogger(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir("", "TestFileLogger")
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
prefix := "TestPrefix "
|
||||
level := INFO
|
||||
flags := LstdFlags | LUTC | Lfuncname
|
||||
filename := filepath.Join(tmpDir, "test.log")
|
||||
|
||||
fileLogger := NewFileLogger()
|
||||
realFileLogger, ok := fileLogger.(*FileLogger)
|
||||
assert.Equal(t, true, ok)
|
||||
|
||||
location, _ := time.LoadLocation("EST")
|
||||
|
||||
date := time.Date(2019, time.January, 13, 22, 3, 30, 15, location)
|
||||
|
||||
dateString := date.UTC().Format("2006/01/02 15:04:05")
|
||||
|
||||
event := Event{
|
||||
level: INFO,
|
||||
msg: "TEST MSG",
|
||||
caller: "CALLER",
|
||||
filename: "FULL/FILENAME",
|
||||
line: 1,
|
||||
time: date,
|
||||
}
|
||||
|
||||
expected := fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
|
||||
fileLogger.Init(fmt.Sprintf("{\"prefix\":\"%s\",\"level\":\"%s\",\"flags\":%d,\"filename\":\"%s\",\"maxsize\":%d,\"compress\":false}", prefix, level.String(), flags, filepath.ToSlash(filename), len(expected)*2))
|
||||
|
||||
assert.Equal(t, flags, realFileLogger.Flags)
|
||||
assert.Equal(t, level, realFileLogger.Level)
|
||||
assert.Equal(t, level, fileLogger.GetLevel())
|
||||
|
||||
fileLogger.LogEvent(&event)
|
||||
fileLogger.Flush()
|
||||
logData, err := ioutil.ReadFile(filename)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, string(logData))
|
||||
|
||||
event.level = DEBUG
|
||||
expected = expected + ""
|
||||
fileLogger.LogEvent(&event)
|
||||
fileLogger.Flush()
|
||||
logData, err = ioutil.ReadFile(filename)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, string(logData))
|
||||
|
||||
event.level = TRACE
|
||||
expected = expected + ""
|
||||
fileLogger.LogEvent(&event)
|
||||
fileLogger.Flush()
|
||||
logData, err = ioutil.ReadFile(filename)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, string(logData))
|
||||
|
||||
event.level = WARN
|
||||
expected = expected + fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
fileLogger.LogEvent(&event)
|
||||
fileLogger.Flush()
|
||||
logData, err = ioutil.ReadFile(filename)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, string(logData))
|
||||
|
||||
// Should rotate
|
||||
fileLogger.LogEvent(&event)
|
||||
fileLogger.Flush()
|
||||
logData, err = ioutil.ReadFile(filename + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), 1))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, string(logData))
|
||||
|
||||
logData, err = ioutil.ReadFile(filename)
|
||||
assert.NoError(t, err)
|
||||
expected = fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
assert.Equal(t, expected, string(logData))
|
||||
|
||||
for num := 2; num <= 999; num++ {
|
||||
file, err := os.OpenFile(filename+fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), num), os.O_RDONLY|os.O_CREATE, 0666)
|
||||
assert.NoError(t, err)
|
||||
file.Close()
|
||||
}
|
||||
err = realFileLogger.DoRotate()
|
||||
assert.Error(t, err)
|
||||
|
||||
expected = expected + fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
fileLogger.LogEvent(&event)
|
||||
fileLogger.Flush()
|
||||
logData, err = ioutil.ReadFile(filename)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, string(logData))
|
||||
|
||||
// Should fail to rotate
|
||||
expected = expected + fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
fileLogger.LogEvent(&event)
|
||||
fileLogger.Flush()
|
||||
logData, err = ioutil.ReadFile(filename)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, string(logData))
|
||||
|
||||
fileLogger.Close()
|
||||
}
|
||||
|
||||
func TestCompressFileLogger(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir("", "TestFileLogger")
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
prefix := "TestPrefix "
|
||||
level := INFO
|
||||
flags := LstdFlags | LUTC | Lfuncname
|
||||
filename := filepath.Join(tmpDir, "test.log")
|
||||
|
||||
fileLogger := NewFileLogger()
|
||||
realFileLogger, ok := fileLogger.(*FileLogger)
|
||||
assert.Equal(t, true, ok)
|
||||
|
||||
location, _ := time.LoadLocation("EST")
|
||||
|
||||
date := time.Date(2019, time.January, 13, 22, 3, 30, 15, location)
|
||||
|
||||
dateString := date.UTC().Format("2006/01/02 15:04:05")
|
||||
|
||||
event := Event{
|
||||
level: INFO,
|
||||
msg: "TEST MSG",
|
||||
caller: "CALLER",
|
||||
filename: "FULL/FILENAME",
|
||||
line: 1,
|
||||
time: date,
|
||||
}
|
||||
|
||||
expected := fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
|
||||
fileLogger.Init(fmt.Sprintf("{\"prefix\":\"%s\",\"level\":\"%s\",\"flags\":%d,\"filename\":\"%s\",\"maxsize\":%d,\"compress\":true}", prefix, level.String(), flags, filepath.ToSlash(filename), len(expected)*2))
|
||||
|
||||
fileLogger.LogEvent(&event)
|
||||
fileLogger.Flush()
|
||||
logData, err := ioutil.ReadFile(filename)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, string(logData))
|
||||
|
||||
event.level = WARN
|
||||
expected = expected + fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
fileLogger.LogEvent(&event)
|
||||
fileLogger.Flush()
|
||||
logData, err = ioutil.ReadFile(filename)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, string(logData))
|
||||
|
||||
// Should rotate
|
||||
fileLogger.LogEvent(&event)
|
||||
fileLogger.Flush()
|
||||
|
||||
for num := 2; num <= 999; num++ {
|
||||
file, err := os.OpenFile(filename+fmt.Sprintf(".%s.%03d.gz", time.Now().Format("2006-01-02"), num), os.O_RDONLY|os.O_CREATE, 0666)
|
||||
assert.NoError(t, err)
|
||||
file.Close()
|
||||
}
|
||||
err = realFileLogger.DoRotate()
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestCompressOldFile(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir("", "TestFileLogger")
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
fname := filepath.Join(tmpDir, "test")
|
||||
nonGzip := filepath.Join(tmpDir, "test-nonGzip")
|
||||
|
||||
f, err := os.OpenFile(fname, os.O_CREATE|os.O_WRONLY, 0660)
|
||||
assert.NoError(t, err)
|
||||
ng, err := os.OpenFile(nonGzip, os.O_CREATE|os.O_WRONLY, 0660)
|
||||
assert.NoError(t, err)
|
||||
|
||||
for i := 0; i < 999; i++ {
|
||||
f.WriteString("This is a test file\n")
|
||||
ng.WriteString("This is a test file\n")
|
||||
}
|
||||
f.Close()
|
||||
ng.Close()
|
||||
|
||||
err = compressOldLogFile(fname, -1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = os.Lstat(fname + ".gz")
|
||||
assert.NoError(t, err)
|
||||
|
||||
f, err = os.Open(fname + ".gz")
|
||||
assert.NoError(t, err)
|
||||
zr, err := gzip.NewReader(f)
|
||||
assert.NoError(t, err)
|
||||
data, err := ioutil.ReadAll(zr)
|
||||
assert.NoError(t, err)
|
||||
original, err := ioutil.ReadFile(nonGzip)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, original, data)
|
||||
}
|
111
modules/log/level.go
Normal file
111
modules/log/level.go
Normal file
@ -0,0 +1,111 @@
|
||||
// Copyright 2019 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 log
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Level is the level of the logger
|
||||
type Level int
|
||||
|
||||
const (
|
||||
// TRACE represents the lowest log level
|
||||
TRACE Level = iota
|
||||
// DEBUG is for debug logging
|
||||
DEBUG
|
||||
// INFO is for information
|
||||
INFO
|
||||
// WARN is for warning information
|
||||
WARN
|
||||
// ERROR is for error reporting
|
||||
ERROR
|
||||
// CRITICAL is for critical errors
|
||||
CRITICAL
|
||||
// FATAL is for fatal errors
|
||||
FATAL
|
||||
// NONE is for no logging
|
||||
NONE
|
||||
)
|
||||
|
||||
var toString = map[Level]string{
|
||||
TRACE: "trace",
|
||||
DEBUG: "debug",
|
||||
INFO: "info",
|
||||
WARN: "warn",
|
||||
ERROR: "error",
|
||||
CRITICAL: "critical",
|
||||
FATAL: "fatal",
|
||||
NONE: "none",
|
||||
}
|
||||
|
||||
var toLevel = map[string]Level{
|
||||
"trace": TRACE,
|
||||
"debug": DEBUG,
|
||||
"info": INFO,
|
||||
"warn": WARN,
|
||||
"error": ERROR,
|
||||
"critical": CRITICAL,
|
||||
"fatal": FATAL,
|
||||
"none": NONE,
|
||||
}
|
||||
|
||||
// Levels returns all the possible logging levels
|
||||
func Levels() []string {
|
||||
keys := make([]string, 0)
|
||||
for key := range toLevel {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func (l Level) String() string {
|
||||
s, ok := toString[l]
|
||||
if ok {
|
||||
return s
|
||||
}
|
||||
return "info"
|
||||
}
|
||||
|
||||
// MarshalJSON takes a Level and turns it into text
|
||||
func (l Level) MarshalJSON() ([]byte, error) {
|
||||
buffer := bytes.NewBufferString(`"`)
|
||||
buffer.WriteString(toString[l])
|
||||
buffer.WriteString(`"`)
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
// FromString takes a level string and returns a Level
|
||||
func FromString(level string) Level {
|
||||
temp, ok := toLevel[strings.ToLower(level)]
|
||||
if !ok {
|
||||
return INFO
|
||||
}
|
||||
return temp
|
||||
}
|
||||
|
||||
// UnmarshalJSON takes text and turns it into a Level
|
||||
func (l *Level) UnmarshalJSON(b []byte) error {
|
||||
var tmp interface{}
|
||||
err := json.Unmarshal(b, &tmp)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Err: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
switch v := tmp.(type) {
|
||||
case string:
|
||||
*l = FromString(string(v))
|
||||
case int:
|
||||
*l = FromString(Level(v).String())
|
||||
default:
|
||||
*l = INFO
|
||||
}
|
||||
return nil
|
||||
}
|
55
modules/log/level_test.go
Normal file
55
modules/log/level_test.go
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright 2019 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 log
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type testLevel struct {
|
||||
Level Level `json:"level"`
|
||||
}
|
||||
|
||||
func TestLevelMarshalUnmarshalJSON(t *testing.T) {
|
||||
levelBytes, err := json.Marshal(testLevel{
|
||||
Level: INFO,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, string(makeTestLevelBytes(INFO.String())), string(levelBytes))
|
||||
|
||||
var testLevel testLevel
|
||||
err = json.Unmarshal(levelBytes, &testLevel)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, INFO, testLevel.Level)
|
||||
|
||||
err = json.Unmarshal(makeTestLevelBytes(`FOFOO`), &testLevel)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, INFO, testLevel.Level)
|
||||
|
||||
err = json.Unmarshal([]byte(fmt.Sprintf(`{"level":%d}`, 2)), &testLevel)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, INFO, testLevel.Level)
|
||||
|
||||
err = json.Unmarshal([]byte(fmt.Sprintf(`{"level":%d}`, 10012)), &testLevel)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, INFO, testLevel.Level)
|
||||
|
||||
err = json.Unmarshal([]byte(`{"level":{}}`), &testLevel)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, INFO, testLevel.Level)
|
||||
|
||||
assert.Equal(t, INFO.String(), Level(1001).String())
|
||||
|
||||
err = json.Unmarshal([]byte(`{"level":{}`), &testLevel.Level)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func makeTestLevelBytes(level string) []byte {
|
||||
return []byte(fmt.Sprintf(`{"level":"%s"}`, level))
|
||||
}
|
@ -8,48 +8,68 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sync/syncmap"
|
||||
)
|
||||
|
||||
var (
|
||||
loggers []*Logger
|
||||
// DEFAULT is the name of the default logger
|
||||
DEFAULT = "default"
|
||||
// NamedLoggers map of named loggers
|
||||
NamedLoggers = make(map[string]*Logger)
|
||||
// GitLogger logger for git
|
||||
GitLogger *Logger
|
||||
prefix string
|
||||
)
|
||||
|
||||
// NewLogger create a logger
|
||||
func NewLogger(bufLen int64, mode, config string) {
|
||||
logger := newLogger(bufLen)
|
||||
// NewLogger create a logger for the default logger
|
||||
func NewLogger(bufLen int64, name, provider, config string) *Logger {
|
||||
err := NewNamedLogger(DEFAULT, bufLen, name, provider, config)
|
||||
if err != nil {
|
||||
CriticalWithSkip(1, "Unable to create default logger: %v", err)
|
||||
panic(err)
|
||||
}
|
||||
return NamedLoggers[DEFAULT]
|
||||
}
|
||||
|
||||
isExist := false
|
||||
for i, l := range loggers {
|
||||
if l.adapter == mode {
|
||||
isExist = true
|
||||
loggers[i] = logger
|
||||
}
|
||||
// NewNamedLogger creates a new named logger for a given configuration
|
||||
func NewNamedLogger(name string, bufLen int64, subname, provider, config string) error {
|
||||
logger, ok := NamedLoggers[name]
|
||||
if !ok {
|
||||
logger = newLogger(name, bufLen)
|
||||
|
||||
NamedLoggers[name] = logger
|
||||
}
|
||||
if !isExist {
|
||||
loggers = append(loggers, logger)
|
||||
}
|
||||
if err := logger.SetLogger(mode, config); err != nil {
|
||||
Fatal(2, "Failed to set logger (%s): %v", mode, err)
|
||||
|
||||
return logger.SetLogger(subname, provider, config)
|
||||
}
|
||||
|
||||
// DelNamedLogger closes and deletes the named logger
|
||||
func DelNamedLogger(name string) {
|
||||
l, ok := NamedLoggers[name]
|
||||
if ok {
|
||||
delete(NamedLoggers, name)
|
||||
l.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// DelLogger removes loggers that are for the given mode
|
||||
func DelLogger(mode string) error {
|
||||
for _, l := range loggers {
|
||||
if _, ok := l.outputs.Load(mode); ok {
|
||||
return l.DelLogger(mode)
|
||||
}
|
||||
// DelLogger removes the named sublogger from the default logger
|
||||
func DelLogger(name string) error {
|
||||
logger := NamedLoggers[DEFAULT]
|
||||
found, err := logger.DelLogger(name)
|
||||
if !found {
|
||||
Trace("Log %s not found, no need to delete", name)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
Trace("Log adapter %s not found, no need to delete", mode)
|
||||
return nil
|
||||
// GetLogger returns either a named logger or the default logger
|
||||
func GetLogger(name string) *Logger {
|
||||
logger, ok := NamedLoggers[name]
|
||||
if ok {
|
||||
return logger
|
||||
}
|
||||
return NamedLoggers[DEFAULT]
|
||||
}
|
||||
|
||||
// NewGitLogger create a logger for git
|
||||
@ -58,333 +78,168 @@ func NewGitLogger(logPath string) {
|
||||
path := path.Dir(logPath)
|
||||
|
||||
if err := os.MkdirAll(path, os.ModePerm); err != nil {
|
||||
Fatal(4, "Failed to create dir %s: %v", path, err)
|
||||
Fatal("Failed to create dir %s: %v", path, err)
|
||||
}
|
||||
|
||||
GitLogger = newLogger(0)
|
||||
GitLogger.SetLogger("file", fmt.Sprintf(`{"level":0,"filename":"%s","rotate":false}`, logPath))
|
||||
GitLogger = newLogger("git", 0)
|
||||
GitLogger.SetLogger("file", "file", fmt.Sprintf(`{"level":"TRACE","filename":"%s","rotate":false}`, logPath))
|
||||
}
|
||||
|
||||
// GetLevel returns the minimum logger level
|
||||
func GetLevel() Level {
|
||||
return NamedLoggers[DEFAULT].GetLevel()
|
||||
}
|
||||
|
||||
// GetStacktraceLevel returns the minimum logger level
|
||||
func GetStacktraceLevel() Level {
|
||||
return NamedLoggers[DEFAULT].GetStacktraceLevel()
|
||||
}
|
||||
|
||||
// Trace records trace log
|
||||
func Trace(format string, v ...interface{}) {
|
||||
for _, logger := range loggers {
|
||||
logger.Trace(format, v...)
|
||||
}
|
||||
Log(1, TRACE, format, v...)
|
||||
}
|
||||
|
||||
// IsTrace returns true if at least one logger is TRACE
|
||||
func IsTrace() bool {
|
||||
return GetLevel() <= TRACE
|
||||
}
|
||||
|
||||
// Debug records debug log
|
||||
func Debug(format string, v ...interface{}) {
|
||||
for _, logger := range loggers {
|
||||
logger.Debug(format, v...)
|
||||
}
|
||||
Log(1, DEBUG, format, v...)
|
||||
}
|
||||
|
||||
// IsDebug returns true if at least one logger is DEBUG
|
||||
func IsDebug() bool {
|
||||
return GetLevel() <= DEBUG
|
||||
}
|
||||
|
||||
// Info records info log
|
||||
func Info(format string, v ...interface{}) {
|
||||
for _, logger := range loggers {
|
||||
logger.Info(format, v...)
|
||||
}
|
||||
Log(1, INFO, format, v...)
|
||||
}
|
||||
|
||||
// IsInfo returns true if at least one logger is INFO
|
||||
func IsInfo() bool {
|
||||
return GetLevel() <= INFO
|
||||
}
|
||||
|
||||
// Warn records warning log
|
||||
func Warn(format string, v ...interface{}) {
|
||||
for _, logger := range loggers {
|
||||
logger.Warn(format, v...)
|
||||
}
|
||||
Log(1, WARN, format, v...)
|
||||
}
|
||||
|
||||
// IsWarn returns true if at least one logger is WARN
|
||||
func IsWarn() bool {
|
||||
return GetLevel() <= WARN
|
||||
}
|
||||
|
||||
// Error records error log
|
||||
func Error(skip int, format string, v ...interface{}) {
|
||||
for _, logger := range loggers {
|
||||
logger.Error(skip, format, v...)
|
||||
}
|
||||
func Error(format string, v ...interface{}) {
|
||||
Log(1, ERROR, format, v...)
|
||||
}
|
||||
|
||||
// ErrorWithSkip records error log from "skip" calls back from this function
|
||||
func ErrorWithSkip(skip int, format string, v ...interface{}) {
|
||||
Log(skip+1, ERROR, format, v...)
|
||||
}
|
||||
|
||||
// IsError returns true if at least one logger is ERROR
|
||||
func IsError() bool {
|
||||
return GetLevel() <= ERROR
|
||||
}
|
||||
|
||||
// Critical records critical log
|
||||
func Critical(skip int, format string, v ...interface{}) {
|
||||
for _, logger := range loggers {
|
||||
logger.Critical(skip, format, v...)
|
||||
}
|
||||
func Critical(format string, v ...interface{}) {
|
||||
Log(1, CRITICAL, format, v...)
|
||||
}
|
||||
|
||||
// Fatal records error log and exit process
|
||||
func Fatal(skip int, format string, v ...interface{}) {
|
||||
Error(skip, format, v...)
|
||||
for _, l := range loggers {
|
||||
l.Close()
|
||||
}
|
||||
// CriticalWithSkip records critical log from "skip" calls back from this function
|
||||
func CriticalWithSkip(skip int, format string, v ...interface{}) {
|
||||
Log(skip+1, CRITICAL, format, v...)
|
||||
}
|
||||
|
||||
// IsCritical returns true if at least one logger is CRITICAL
|
||||
func IsCritical() bool {
|
||||
return GetLevel() <= CRITICAL
|
||||
}
|
||||
|
||||
// Fatal records fatal log and exit process
|
||||
func Fatal(format string, v ...interface{}) {
|
||||
Log(1, FATAL, format, v...)
|
||||
Close()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// FatalWithSkip records fatal log from "skip" calls back from this function
|
||||
func FatalWithSkip(skip int, format string, v ...interface{}) {
|
||||
Log(skip+1, FATAL, format, v...)
|
||||
Close()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// IsFatal returns true if at least one logger is FATAL
|
||||
func IsFatal() bool {
|
||||
return GetLevel() <= FATAL
|
||||
}
|
||||
|
||||
// Close closes all the loggers
|
||||
func Close() {
|
||||
for _, l := range loggers {
|
||||
l.Close()
|
||||
l, ok := NamedLoggers[DEFAULT]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
delete(NamedLoggers, DEFAULT)
|
||||
l.Close()
|
||||
}
|
||||
|
||||
// Log a message with defined skip and at logging level
|
||||
// A skip of 0 refers to the caller of this command
|
||||
func Log(skip int, level Level, format string, v ...interface{}) {
|
||||
l, ok := NamedLoggers[DEFAULT]
|
||||
if ok {
|
||||
l.Log(skip+1, level, format, v...)
|
||||
}
|
||||
}
|
||||
|
||||
// .___ __ _____
|
||||
// | | _____/ |_ ____________/ ____\____ ____ ____
|
||||
// | |/ \ __\/ __ \_ __ \ __\\__ \ _/ ___\/ __ \
|
||||
// | | | \ | \ ___/| | \/| | / __ \\ \__\ ___/
|
||||
// |___|___| /__| \___ >__| |__| (____ /\___ >___ >
|
||||
// \/ \/ \/ \/ \/
|
||||
|
||||
// LogLevel level type for log
|
||||
//type LogLevel int
|
||||
|
||||
// log levels
|
||||
const (
|
||||
TRACE = iota
|
||||
DEBUG
|
||||
INFO
|
||||
WARN
|
||||
ERROR
|
||||
CRITICAL
|
||||
FATAL
|
||||
)
|
||||
|
||||
// LoggerInterface represents behaviors of a logger provider.
|
||||
type LoggerInterface interface {
|
||||
Init(config string) error
|
||||
WriteMsg(msg string, skip, level int) error
|
||||
Destroy()
|
||||
Flush()
|
||||
}
|
||||
|
||||
type loggerType func() LoggerInterface
|
||||
|
||||
// LoggerAsWriter is a io.Writer shim around the gitea log
|
||||
type LoggerAsWriter struct {
|
||||
level int
|
||||
ourLoggers []*Logger
|
||||
level Level
|
||||
}
|
||||
|
||||
// NewLoggerAsWriter creates a Writer representation of the logger with setable log level
|
||||
func NewLoggerAsWriter(level string) *LoggerAsWriter {
|
||||
l := &LoggerAsWriter{}
|
||||
switch strings.ToUpper(level) {
|
||||
case "TRACE":
|
||||
l.level = TRACE
|
||||
case "DEBUG":
|
||||
l.level = DEBUG
|
||||
case "INFO":
|
||||
l.level = INFO
|
||||
case "WARN":
|
||||
l.level = WARN
|
||||
case "ERROR":
|
||||
l.level = ERROR
|
||||
case "CRITICAL":
|
||||
l.level = CRITICAL
|
||||
case "FATAL":
|
||||
l.level = FATAL
|
||||
default:
|
||||
l.level = INFO
|
||||
func NewLoggerAsWriter(level string, ourLoggers ...*Logger) *LoggerAsWriter {
|
||||
if len(ourLoggers) == 0 {
|
||||
ourLoggers = []*Logger{NamedLoggers[DEFAULT]}
|
||||
}
|
||||
l := &LoggerAsWriter{
|
||||
ourLoggers: ourLoggers,
|
||||
level: FromString(level),
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// Write implements the io.Writer interface to allow spoofing of macaron
|
||||
func (l *LoggerAsWriter) Write(p []byte) (int, error) {
|
||||
l.Log(string(p))
|
||||
for _, logger := range l.ourLoggers {
|
||||
// Skip = 3 because this presumes that we have been called by log.Println()
|
||||
// If the caller has used log.Output or the like this will be wrong
|
||||
logger.Log(3, l.level, string(p))
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// Log takes a given string and logs it at the set log-level
|
||||
func (l *LoggerAsWriter) Log(msg string) {
|
||||
for _, logger := range loggers {
|
||||
logger.writerMsg(0, l.level, msg)
|
||||
for _, logger := range l.ourLoggers {
|
||||
// Set the skip to reference the call just above this
|
||||
logger.Log(1, l.level, msg)
|
||||
}
|
||||
}
|
||||
|
||||
var adapters = make(map[string]loggerType)
|
||||
|
||||
// Register registers given logger provider to adapters.
|
||||
func Register(name string, log loggerType) {
|
||||
if log == nil {
|
||||
panic("log: register provider is nil")
|
||||
}
|
||||
if _, dup := adapters[name]; dup {
|
||||
panic("log: register called twice for provider \"" + name + "\"")
|
||||
}
|
||||
adapters[name] = log
|
||||
}
|
||||
|
||||
type logMsg struct {
|
||||
skip, level int
|
||||
msg string
|
||||
}
|
||||
|
||||
// Logger is default logger in beego application.
|
||||
// it can contain several providers and log message into all providers.
|
||||
type Logger struct {
|
||||
adapter string
|
||||
level int
|
||||
msg chan *logMsg
|
||||
outputs syncmap.Map
|
||||
quit chan bool
|
||||
}
|
||||
|
||||
// newLogger initializes and returns a new logger.
|
||||
func newLogger(buffer int64) *Logger {
|
||||
l := &Logger{
|
||||
msg: make(chan *logMsg, buffer),
|
||||
quit: make(chan bool),
|
||||
}
|
||||
go l.StartLogger()
|
||||
return l
|
||||
}
|
||||
|
||||
// SetLogger sets new logger instance with given logger adapter and config.
|
||||
func (l *Logger) SetLogger(adapter string, config string) error {
|
||||
if log, ok := adapters[adapter]; ok {
|
||||
lg := log()
|
||||
if err := lg.Init(config); err != nil {
|
||||
return err
|
||||
}
|
||||
l.outputs.Store(adapter, lg)
|
||||
l.adapter = adapter
|
||||
} else {
|
||||
panic("log: unknown adapter \"" + adapter + "\" (forgotten register?)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DelLogger removes a logger adapter instance.
|
||||
func (l *Logger) DelLogger(adapter string) error {
|
||||
if lg, ok := l.outputs.Load(adapter); ok {
|
||||
lg.(LoggerInterface).Destroy()
|
||||
l.outputs.Delete(adapter)
|
||||
} else {
|
||||
panic("log: unknown adapter \"" + adapter + "\" (forgotten register?)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Logger) writerMsg(skip, level int, msg string) error {
|
||||
if l.level > level {
|
||||
return nil
|
||||
}
|
||||
lm := &logMsg{
|
||||
skip: skip,
|
||||
level: level,
|
||||
}
|
||||
|
||||
// Only error information needs locate position for debugging.
|
||||
if lm.level >= ERROR {
|
||||
pc, file, line, ok := runtime.Caller(skip)
|
||||
if ok {
|
||||
// Get caller function name.
|
||||
fn := runtime.FuncForPC(pc)
|
||||
var fnName string
|
||||
if fn == nil {
|
||||
fnName = "?()"
|
||||
} else {
|
||||
fnName = strings.TrimLeft(filepath.Ext(fn.Name()), ".") + "()"
|
||||
}
|
||||
|
||||
fileName := file
|
||||
if len(fileName) > 20 {
|
||||
fileName = "..." + fileName[len(fileName)-20:]
|
||||
}
|
||||
lm.msg = fmt.Sprintf("[%s:%d %s] %s", fileName, line, fnName, msg)
|
||||
} else {
|
||||
lm.msg = msg
|
||||
}
|
||||
} else {
|
||||
lm.msg = msg
|
||||
}
|
||||
l.msg <- lm
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartLogger starts logger chan reading.
|
||||
func (l *Logger) StartLogger() {
|
||||
for {
|
||||
select {
|
||||
case bm := <-l.msg:
|
||||
l.outputs.Range(func(k, v interface{}) bool {
|
||||
if err := v.(LoggerInterface).WriteMsg(bm.msg, bm.skip, bm.level); err != nil {
|
||||
fmt.Println("ERROR, unable to WriteMsg:", err)
|
||||
}
|
||||
return true
|
||||
})
|
||||
case <-l.quit:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flush flushes all chan data.
|
||||
func (l *Logger) Flush() {
|
||||
l.outputs.Range(func(k, v interface{}) bool {
|
||||
v.(LoggerInterface).Flush()
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// Close closes logger, flush all chan data and destroy all adapter instances.
|
||||
func (l *Logger) Close() {
|
||||
l.quit <- true
|
||||
for {
|
||||
if len(l.msg) > 0 {
|
||||
bm := <-l.msg
|
||||
l.outputs.Range(func(k, v interface{}) bool {
|
||||
if err := v.(LoggerInterface).WriteMsg(bm.msg, bm.skip, bm.level); err != nil {
|
||||
fmt.Println("ERROR, unable to WriteMsg:", err)
|
||||
}
|
||||
return true
|
||||
})
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
l.outputs.Range(func(k, v interface{}) bool {
|
||||
v.(LoggerInterface).Flush()
|
||||
v.(LoggerInterface).Destroy()
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// Trace records trace log
|
||||
func (l *Logger) Trace(format string, v ...interface{}) {
|
||||
msg := fmt.Sprintf("[T] "+format, v...)
|
||||
l.writerMsg(0, TRACE, msg)
|
||||
}
|
||||
|
||||
// Debug records debug log
|
||||
func (l *Logger) Debug(format string, v ...interface{}) {
|
||||
msg := fmt.Sprintf("[D] "+format, v...)
|
||||
l.writerMsg(0, DEBUG, msg)
|
||||
}
|
||||
|
||||
// Info records information log
|
||||
func (l *Logger) Info(format string, v ...interface{}) {
|
||||
msg := fmt.Sprintf("[I] "+format, v...)
|
||||
l.writerMsg(0, INFO, msg)
|
||||
}
|
||||
|
||||
// Warn records warning log
|
||||
func (l *Logger) Warn(format string, v ...interface{}) {
|
||||
msg := fmt.Sprintf("[W] "+format, v...)
|
||||
l.writerMsg(0, WARN, msg)
|
||||
}
|
||||
|
||||
// Error records error log
|
||||
func (l *Logger) Error(skip int, format string, v ...interface{}) {
|
||||
msg := fmt.Sprintf("[E] "+format, v...)
|
||||
l.writerMsg(skip, ERROR, msg)
|
||||
}
|
||||
|
||||
// Critical records critical log
|
||||
func (l *Logger) Critical(skip int, format string, v ...interface{}) {
|
||||
msg := fmt.Sprintf("[C] "+format, v...)
|
||||
l.writerMsg(skip, CRITICAL, msg)
|
||||
}
|
||||
|
||||
// Fatal records error log and exit the process
|
||||
func (l *Logger) Fatal(skip int, format string, v ...interface{}) {
|
||||
msg := fmt.Sprintf("[F] "+format, v...)
|
||||
l.writerMsg(skip, FATAL, msg)
|
||||
l.Close()
|
||||
os.Exit(1)
|
||||
func init() {
|
||||
_, filename, _, _ := runtime.Caller(0)
|
||||
prefix = strings.TrimSuffix(filename, "modules/log/log.go")
|
||||
}
|
||||
|
154
modules/log/log_test.go
Normal file
154
modules/log/log_test.go
Normal file
@ -0,0 +1,154 @@
|
||||
// Copyright 2019 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 log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func baseConsoleTest(t *testing.T, logger *Logger) (chan []byte, chan bool) {
|
||||
written := make(chan []byte)
|
||||
closed := make(chan bool)
|
||||
|
||||
c := CallbackWriteCloser{
|
||||
callback: func(p []byte, close bool) {
|
||||
written <- p
|
||||
closed <- close
|
||||
},
|
||||
}
|
||||
m := logger.MultiChannelledLog
|
||||
|
||||
channelledLog := m.GetEventLogger("console")
|
||||
assert.NotEmpty(t, channelledLog)
|
||||
realChanLog, ok := channelledLog.(*ChannelledLog)
|
||||
assert.Equal(t, true, ok)
|
||||
realCL, ok := realChanLog.loggerProvider.(*ConsoleLogger)
|
||||
assert.Equal(t, true, ok)
|
||||
assert.Equal(t, INFO, realCL.Level)
|
||||
realCL.out = c
|
||||
|
||||
format := "test: %s"
|
||||
args := []interface{}{"A"}
|
||||
|
||||
logger.Log(0, INFO, format, args...)
|
||||
line := <-written
|
||||
assert.Contains(t, string(line), fmt.Sprintf(format, args...))
|
||||
assert.Equal(t, false, <-closed)
|
||||
|
||||
format = "test2: %s"
|
||||
logger.Warn(format, args...)
|
||||
line = <-written
|
||||
|
||||
assert.Contains(t, string(line), fmt.Sprintf(format, args...))
|
||||
assert.Equal(t, false, <-closed)
|
||||
|
||||
format = "testerror: %s"
|
||||
logger.Error(format, args...)
|
||||
line = <-written
|
||||
assert.Contains(t, string(line), fmt.Sprintf(format, args...))
|
||||
assert.Equal(t, false, <-closed)
|
||||
return written, closed
|
||||
}
|
||||
|
||||
func TestNewLoggerUnexported(t *testing.T) {
|
||||
level := INFO
|
||||
logger := newLogger("UNEXPORTED", 0)
|
||||
err := logger.SetLogger("console", "console", fmt.Sprintf(`{"level":"%s"}`, level.String()))
|
||||
assert.NoError(t, err)
|
||||
out := logger.MultiChannelledLog.GetEventLogger("console")
|
||||
assert.NotEmpty(t, out)
|
||||
chanlog, ok := out.(*ChannelledLog)
|
||||
assert.Equal(t, true, ok)
|
||||
assert.Equal(t, "console", chanlog.provider)
|
||||
assert.Equal(t, INFO, logger.GetLevel())
|
||||
baseConsoleTest(t, logger)
|
||||
}
|
||||
|
||||
func TestNewLoggger(t *testing.T) {
|
||||
level := INFO
|
||||
logger := NewLogger(0, "console", "console", fmt.Sprintf(`{"level":"%s"}`, level.String()))
|
||||
|
||||
assert.Equal(t, INFO, GetLevel())
|
||||
assert.Equal(t, false, IsTrace())
|
||||
assert.Equal(t, false, IsDebug())
|
||||
assert.Equal(t, true, IsInfo())
|
||||
assert.Equal(t, true, IsWarn())
|
||||
assert.Equal(t, true, IsError())
|
||||
|
||||
written, closed := baseConsoleTest(t, logger)
|
||||
|
||||
format := "test: %s"
|
||||
args := []interface{}{"A"}
|
||||
|
||||
Log(0, INFO, format, args...)
|
||||
line := <-written
|
||||
assert.Contains(t, string(line), fmt.Sprintf(format, args...))
|
||||
assert.Equal(t, false, <-closed)
|
||||
|
||||
Info(format, args...)
|
||||
line = <-written
|
||||
assert.Contains(t, string(line), fmt.Sprintf(format, args...))
|
||||
assert.Equal(t, false, <-closed)
|
||||
|
||||
go DelLogger("console")
|
||||
line = <-written
|
||||
assert.Equal(t, "", string(line))
|
||||
assert.Equal(t, true, <-closed)
|
||||
}
|
||||
|
||||
func TestNewLogggerRecreate(t *testing.T) {
|
||||
level := INFO
|
||||
NewLogger(0, "console", "console", fmt.Sprintf(`{"level":"%s"}`, level.String()))
|
||||
|
||||
assert.Equal(t, INFO, GetLevel())
|
||||
assert.Equal(t, false, IsTrace())
|
||||
assert.Equal(t, false, IsDebug())
|
||||
assert.Equal(t, true, IsInfo())
|
||||
assert.Equal(t, true, IsWarn())
|
||||
assert.Equal(t, true, IsError())
|
||||
|
||||
format := "test: %s"
|
||||
args := []interface{}{"A"}
|
||||
|
||||
Log(0, INFO, format, args...)
|
||||
|
||||
NewLogger(0, "console", "console", fmt.Sprintf(`{"level":"%s"}`, level.String()))
|
||||
|
||||
assert.Equal(t, INFO, GetLevel())
|
||||
assert.Equal(t, false, IsTrace())
|
||||
assert.Equal(t, false, IsDebug())
|
||||
assert.Equal(t, true, IsInfo())
|
||||
assert.Equal(t, true, IsWarn())
|
||||
assert.Equal(t, true, IsError())
|
||||
|
||||
Log(0, INFO, format, args...)
|
||||
|
||||
assert.Panics(t, func() {
|
||||
NewLogger(0, "console", "console", fmt.Sprintf(`{"level":"%s"`, level.String()))
|
||||
})
|
||||
|
||||
go DelLogger("console")
|
||||
|
||||
// We should be able to redelete without a problem
|
||||
go DelLogger("console")
|
||||
|
||||
}
|
||||
|
||||
func TestNewNamedLogger(t *testing.T) {
|
||||
level := INFO
|
||||
err := NewNamedLogger("test", 0, "console", "console", fmt.Sprintf(`{"level":"%s"}`, level.String()))
|
||||
assert.NoError(t, err)
|
||||
logger := NamedLoggers["test"]
|
||||
assert.Equal(t, level, logger.GetLevel())
|
||||
|
||||
written, closed := baseConsoleTest(t, logger)
|
||||
go DelNamedLogger("test")
|
||||
line := <-written
|
||||
assert.Equal(t, "", string(line))
|
||||
assert.Equal(t, true, <-closed)
|
||||
}
|
156
modules/log/logger.go
Normal file
156
modules/log/logger.go
Normal file
@ -0,0 +1,156 @@
|
||||
// Copyright 2019 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 log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Logger is default logger in the Gitea application.
|
||||
// it can contain several providers and log message into all providers.
|
||||
type Logger struct {
|
||||
*MultiChannelledLog
|
||||
bufferLength int64
|
||||
}
|
||||
|
||||
// newLogger initializes and returns a new logger.
|
||||
func newLogger(name string, buffer int64) *Logger {
|
||||
l := &Logger{
|
||||
MultiChannelledLog: NewMultiChannelledLog(name, buffer),
|
||||
bufferLength: buffer,
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// SetLogger sets new logger instance with given logger provider and config.
|
||||
func (l *Logger) SetLogger(name, provider, config string) error {
|
||||
eventLogger, err := NewChannelledLog(name, provider, config, l.bufferLength)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to create sublogger (%s): %v", name, err)
|
||||
}
|
||||
|
||||
l.MultiChannelledLog.DelLogger(name)
|
||||
|
||||
err = l.MultiChannelledLog.AddLogger(eventLogger)
|
||||
if err != nil {
|
||||
if IsErrDuplicateName(err) {
|
||||
return fmt.Errorf("Duplicate named sublogger %s %v", name, l.MultiChannelledLog.GetEventLoggerNames())
|
||||
}
|
||||
return fmt.Errorf("Failed to add sublogger (%s): %v", name, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DelLogger deletes a sublogger from this logger.
|
||||
func (l *Logger) DelLogger(name string) (bool, error) {
|
||||
return l.MultiChannelledLog.DelLogger(name), nil
|
||||
}
|
||||
|
||||
// Log msg at the provided level with the provided caller defined by skip (0 being the function that calls this function)
|
||||
func (l *Logger) Log(skip int, level Level, format string, v ...interface{}) error {
|
||||
if l.GetLevel() > level {
|
||||
return nil
|
||||
}
|
||||
caller := "?()"
|
||||
pc, filename, line, ok := runtime.Caller(skip + 1)
|
||||
if ok {
|
||||
// Get caller function name.
|
||||
fn := runtime.FuncForPC(pc)
|
||||
if fn != nil {
|
||||
caller = fn.Name() + "()"
|
||||
}
|
||||
}
|
||||
msg := format
|
||||
if len(v) > 0 {
|
||||
args := make([]interface{}, len(v))
|
||||
for i := 0; i < len(args); i++ {
|
||||
args[i] = NewColoredValuePointer(&v[i])
|
||||
}
|
||||
msg = fmt.Sprintf(format, args...)
|
||||
}
|
||||
stack := ""
|
||||
if l.GetStacktraceLevel() <= level {
|
||||
stack = Stack(skip + 1)
|
||||
}
|
||||
return l.SendLog(level, caller, strings.TrimPrefix(filename, prefix), line, msg, stack)
|
||||
}
|
||||
|
||||
// SendLog sends a log event at the provided level with the information given
|
||||
func (l *Logger) SendLog(level Level, caller, filename string, line int, msg string, stack string) error {
|
||||
if l.GetLevel() > level {
|
||||
return nil
|
||||
}
|
||||
event := &Event{
|
||||
level: level,
|
||||
caller: caller,
|
||||
filename: filename,
|
||||
line: line,
|
||||
msg: msg,
|
||||
time: time.Now(),
|
||||
stacktrace: stack,
|
||||
}
|
||||
l.LogEvent(event)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Trace records trace log
|
||||
func (l *Logger) Trace(format string, v ...interface{}) {
|
||||
l.Log(1, TRACE, format, v...)
|
||||
}
|
||||
|
||||
// Debug records debug log
|
||||
func (l *Logger) Debug(format string, v ...interface{}) {
|
||||
l.Log(1, DEBUG, format, v...)
|
||||
|
||||
}
|
||||
|
||||
// Info records information log
|
||||
func (l *Logger) Info(format string, v ...interface{}) {
|
||||
l.Log(1, INFO, format, v...)
|
||||
}
|
||||
|
||||
// Warn records warning log
|
||||
func (l *Logger) Warn(format string, v ...interface{}) {
|
||||
l.Log(1, WARN, format, v...)
|
||||
}
|
||||
|
||||
// Error records error log
|
||||
func (l *Logger) Error(format string, v ...interface{}) {
|
||||
l.Log(1, ERROR, format, v...)
|
||||
}
|
||||
|
||||
// ErrorWithSkip records error log from "skip" calls back from this function
|
||||
func (l *Logger) ErrorWithSkip(skip int, format string, v ...interface{}) {
|
||||
l.Log(skip+1, ERROR, format, v...)
|
||||
}
|
||||
|
||||
// Critical records critical log
|
||||
func (l *Logger) Critical(format string, v ...interface{}) {
|
||||
l.Log(1, CRITICAL, format, v...)
|
||||
}
|
||||
|
||||
// CriticalWithSkip records critical log from "skip" calls back from this function
|
||||
func (l *Logger) CriticalWithSkip(skip int, format string, v ...interface{}) {
|
||||
l.Log(skip+1, CRITICAL, format, v...)
|
||||
}
|
||||
|
||||
// Fatal records fatal log and exit the process
|
||||
func (l *Logger) Fatal(format string, v ...interface{}) {
|
||||
l.Log(1, FATAL, format, v...)
|
||||
l.Close()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// FatalWithSkip records fatal log from "skip" calls back from this function and exits the process
|
||||
func (l *Logger) FatalWithSkip(skip int, format string, v ...interface{}) {
|
||||
l.Log(skip+1, FATAL, format, v...)
|
||||
l.Close()
|
||||
os.Exit(1)
|
||||
}
|
26
modules/log/provider.go
Normal file
26
modules/log/provider.go
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2019 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 log
|
||||
|
||||
// LoggerProvider represents behaviors of a logger provider.
|
||||
type LoggerProvider interface {
|
||||
Init(config string) error
|
||||
EventLogger
|
||||
}
|
||||
|
||||
type loggerProvider func() LoggerProvider
|
||||
|
||||
var providers = make(map[string]loggerProvider)
|
||||
|
||||
// Register registers given logger provider to providers.
|
||||
func Register(name string, log loggerProvider) {
|
||||
if log == nil {
|
||||
panic("log: register provider is nil")
|
||||
}
|
||||
if _, dup := providers[name]; dup {
|
||||
panic("log: register called twice for provider \"" + name + "\"")
|
||||
}
|
||||
providers[name] = log
|
||||
}
|
103
modules/log/router.go
Normal file
103
modules/log/router.go
Normal file
@ -0,0 +1,103 @@
|
||||
// Copyright 2019 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 log
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
macaron "gopkg.in/macaron.v1"
|
||||
)
|
||||
|
||||
var statusToColor = map[int][]byte{
|
||||
100: ColorBytes(Bold),
|
||||
200: ColorBytes(FgGreen),
|
||||
300: ColorBytes(FgYellow),
|
||||
304: ColorBytes(FgCyan),
|
||||
400: ColorBytes(Bold, FgRed),
|
||||
401: ColorBytes(Bold, FgMagenta),
|
||||
403: ColorBytes(Bold, FgMagenta),
|
||||
500: ColorBytes(Bold, BgRed),
|
||||
}
|
||||
|
||||
func coloredStatus(status int, s ...string) *ColoredValue {
|
||||
color, ok := statusToColor[status]
|
||||
if !ok {
|
||||
color, ok = statusToColor[(status/100)*100]
|
||||
}
|
||||
if !ok {
|
||||
color = fgBoldBytes
|
||||
}
|
||||
if len(s) > 0 {
|
||||
return NewColoredValueBytes(s[0], &color)
|
||||
}
|
||||
return NewColoredValueBytes(status, &color)
|
||||
}
|
||||
|
||||
var methodToColor = map[string][]byte{
|
||||
"GET": ColorBytes(FgBlue),
|
||||
"POST": ColorBytes(FgGreen),
|
||||
"DELETE": ColorBytes(FgRed),
|
||||
"PATCH": ColorBytes(FgCyan),
|
||||
"PUT": ColorBytes(FgYellow, Faint),
|
||||
"HEAD": ColorBytes(FgBlue, Faint),
|
||||
}
|
||||
|
||||
func coloredMethod(method string) *ColoredValue {
|
||||
color, ok := methodToColor[method]
|
||||
if !ok {
|
||||
return NewColoredValueBytes(method, &fgBoldBytes)
|
||||
}
|
||||
return NewColoredValueBytes(method, &color)
|
||||
}
|
||||
|
||||
var durations = []time.Duration{
|
||||
10 * time.Millisecond,
|
||||
100 * time.Millisecond,
|
||||
1 * time.Second,
|
||||
5 * time.Second,
|
||||
10 * time.Second,
|
||||
}
|
||||
|
||||
var durationColors = [][]byte{
|
||||
ColorBytes(FgGreen),
|
||||
ColorBytes(Bold),
|
||||
ColorBytes(FgYellow),
|
||||
ColorBytes(FgRed, Bold),
|
||||
ColorBytes(BgRed),
|
||||
}
|
||||
|
||||
var wayTooLong = ColorBytes(BgMagenta)
|
||||
|
||||
func coloredTime(duration time.Duration) *ColoredValue {
|
||||
for i, k := range durations {
|
||||
if duration < k {
|
||||
return NewColoredValueBytes(duration, &durationColors[i])
|
||||
}
|
||||
}
|
||||
return NewColoredValueBytes(duration, &wayTooLong)
|
||||
}
|
||||
|
||||
// SetupRouterLogger will setup macaron to routing to the main gitea log
|
||||
func SetupRouterLogger(m *macaron.Macaron, level Level) {
|
||||
if GetLevel() <= level {
|
||||
m.Use(RouterHandler(level))
|
||||
}
|
||||
}
|
||||
|
||||
// RouterHandler is a macaron handler that will log the routing to the default gitea log
|
||||
func RouterHandler(level Level) func(ctx *macaron.Context) {
|
||||
return func(ctx *macaron.Context) {
|
||||
start := time.Now()
|
||||
|
||||
GetLogger("router").Log(0, level, "Started %s %s for %s", coloredMethod(ctx.Req.Method), ctx.Req.RequestURI, ctx.RemoteAddr())
|
||||
|
||||
rw := ctx.Resp.(macaron.ResponseWriter)
|
||||
ctx.Next()
|
||||
|
||||
status := rw.Status()
|
||||
GetLogger("router").Log(0, level, "Completed %s %s %v %s in %v", coloredMethod(ctx.Req.Method), ctx.Req.RequestURI, coloredStatus(status), coloredStatus(status, http.StatusText(rw.Status())), coloredTime(time.Since(start)))
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Copyright 2019 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.
|
||||
|
||||
@ -6,29 +7,45 @@ package log
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/smtp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
subjectPhrase = "Diagnostic message from server"
|
||||
)
|
||||
|
||||
// SMTPWriter implements LoggerInterface and is used to send emails via given SMTP-server.
|
||||
type SMTPWriter struct {
|
||||
Username string `json:"Username"`
|
||||
Password string `json:"password"`
|
||||
Host string `json:"Host"`
|
||||
Subject string `json:"subject"`
|
||||
RecipientAddresses []string `json:"sendTos"`
|
||||
Level int `json:"level"`
|
||||
type smtpWriter struct {
|
||||
owner *SMTPLogger
|
||||
}
|
||||
|
||||
// NewSMTPWriter creates smtp writer.
|
||||
func NewSMTPWriter() LoggerInterface {
|
||||
return &SMTPWriter{Level: TRACE}
|
||||
// Write sends the message as an email
|
||||
func (s *smtpWriter) Write(p []byte) (int, error) {
|
||||
return s.owner.sendMail(p)
|
||||
}
|
||||
|
||||
// Close does nothing
|
||||
func (s *smtpWriter) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SMTPLogger implements LoggerProvider and is used to send emails via given SMTP-server.
|
||||
type SMTPLogger struct {
|
||||
BaseLogger
|
||||
Username string `json:"Username"`
|
||||
Password string `json:"password"`
|
||||
Host string `json:"host"`
|
||||
Subject string `json:"subject"`
|
||||
RecipientAddresses []string `json:"sendTos"`
|
||||
sendMailFn func(string, smtp.Auth, string, []string, []byte) error
|
||||
}
|
||||
|
||||
// NewSMTPLogger creates smtp writer.
|
||||
func NewSMTPLogger() LoggerProvider {
|
||||
s := &SMTPLogger{}
|
||||
s.Level = TRACE
|
||||
s.sendMailFn = smtp.SendMail
|
||||
return s
|
||||
}
|
||||
|
||||
// Init smtp writer with json config.
|
||||
@ -41,49 +58,54 @@ func NewSMTPWriter() LoggerInterface {
|
||||
// "sendTos":["email1","email2"],
|
||||
// "level":LevelError
|
||||
// }
|
||||
func (sw *SMTPWriter) Init(jsonconfig string) error {
|
||||
return json.Unmarshal([]byte(jsonconfig), sw)
|
||||
func (log *SMTPLogger) Init(jsonconfig string) error {
|
||||
err := json.Unmarshal([]byte(jsonconfig), log)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.createLogger(&smtpWriter{
|
||||
owner: log,
|
||||
})
|
||||
log.sendMailFn = smtp.SendMail
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteMsg writes message in smtp writer.
|
||||
// it will send an email with subject and only this message.
|
||||
func (sw *SMTPWriter) WriteMsg(msg string, skip, level int) error {
|
||||
if level < sw.Level {
|
||||
return nil
|
||||
}
|
||||
|
||||
hp := strings.Split(sw.Host, ":")
|
||||
func (log *SMTPLogger) sendMail(p []byte) (int, error) {
|
||||
hp := strings.Split(log.Host, ":")
|
||||
|
||||
// Set up authentication information.
|
||||
auth := smtp.PlainAuth(
|
||||
"",
|
||||
sw.Username,
|
||||
sw.Password,
|
||||
log.Username,
|
||||
log.Password,
|
||||
hp[0],
|
||||
)
|
||||
// Connect to the server, authenticate, set the sender and recipient,
|
||||
// and send the email all in one step.
|
||||
contentType := "Content-Type: text/plain" + "; charset=UTF-8"
|
||||
mailmsg := []byte("To: " + strings.Join(sw.RecipientAddresses, ";") + "\r\nFrom: " + sw.Username + "<" + sw.Username +
|
||||
">\r\nSubject: " + sw.Subject + "\r\n" + contentType + "\r\n\r\n" + fmt.Sprintf(".%s", time.Now().Format("2006-01-02 15:04:05")) + msg)
|
||||
|
||||
return smtp.SendMail(
|
||||
sw.Host,
|
||||
mailmsg := []byte("To: " + strings.Join(log.RecipientAddresses, ";") + "\r\nFrom: " + log.Username + "<" + log.Username +
|
||||
">\r\nSubject: " + log.Subject + "\r\n" + contentType + "\r\n\r\n")
|
||||
mailmsg = append(mailmsg, p...)
|
||||
return len(p), log.sendMailFn(
|
||||
log.Host,
|
||||
auth,
|
||||
sw.Username,
|
||||
sw.RecipientAddresses,
|
||||
log.Username,
|
||||
log.RecipientAddresses,
|
||||
mailmsg,
|
||||
)
|
||||
}
|
||||
|
||||
// Flush when log should be flushed
|
||||
func (sw *SMTPWriter) Flush() {
|
||||
func (log *SMTPLogger) Flush() {
|
||||
}
|
||||
|
||||
// Destroy when writer is destroy
|
||||
func (sw *SMTPWriter) Destroy() {
|
||||
// GetName returns the default name for this implementation
|
||||
func (log *SMTPLogger) GetName() string {
|
||||
return "smtp"
|
||||
}
|
||||
|
||||
func init() {
|
||||
Register("smtp", NewSMTPWriter)
|
||||
Register("smtp", NewSMTPLogger)
|
||||
}
|
||||
|
86
modules/log/smtp_test.go
Normal file
86
modules/log/smtp_test.go
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright 2019 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 log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/smtp"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSMTPLogger(t *testing.T) {
|
||||
prefix := "TestPrefix "
|
||||
level := INFO
|
||||
flags := LstdFlags | LUTC | Lfuncname
|
||||
username := "testuser"
|
||||
password := "testpassword"
|
||||
host := "testhost"
|
||||
subject := "testsubject"
|
||||
sendTos := []string{"testto1", "testto2"}
|
||||
|
||||
logger := NewSMTPLogger()
|
||||
smtpLogger, ok := logger.(*SMTPLogger)
|
||||
assert.Equal(t, true, ok)
|
||||
|
||||
err := logger.Init(fmt.Sprintf("{\"prefix\":\"%s\",\"level\":\"%s\",\"flags\":%d,\"username\":\"%s\",\"password\":\"%s\",\"host\":\"%s\",\"subject\":\"%s\",\"sendTos\":[\"%s\",\"%s\"]}", prefix, level.String(), flags, username, password, host, subject, sendTos[0], sendTos[1]))
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, flags, smtpLogger.Flags)
|
||||
assert.Equal(t, level, smtpLogger.Level)
|
||||
assert.Equal(t, level, logger.GetLevel())
|
||||
|
||||
location, _ := time.LoadLocation("EST")
|
||||
|
||||
date := time.Date(2019, time.January, 13, 22, 3, 30, 15, location)
|
||||
|
||||
dateString := date.UTC().Format("2006/01/02 15:04:05")
|
||||
|
||||
event := Event{
|
||||
level: INFO,
|
||||
msg: "TEST MSG",
|
||||
caller: "CALLER",
|
||||
filename: "FULL/FILENAME",
|
||||
line: 1,
|
||||
time: date,
|
||||
}
|
||||
|
||||
expected := fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
|
||||
var envToHost string
|
||||
var envFrom string
|
||||
var envTo []string
|
||||
var envMsg []byte
|
||||
smtpLogger.sendMailFn = func(addr string, a smtp.Auth, from string, to []string, msg []byte) error {
|
||||
envToHost = addr
|
||||
envFrom = from
|
||||
envTo = to
|
||||
envMsg = msg
|
||||
return nil
|
||||
}
|
||||
|
||||
err = logger.LogEvent(&event)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, host, envToHost)
|
||||
assert.Equal(t, username, envFrom)
|
||||
assert.Equal(t, sendTos, envTo)
|
||||
assert.Contains(t, string(envMsg), expected)
|
||||
|
||||
logger.Flush()
|
||||
|
||||
event.level = WARN
|
||||
expected = fmt.Sprintf("%s%s %s:%d:%s [%c] %s\n", prefix, dateString, event.filename, event.line, event.caller, strings.ToUpper(event.level.String())[0], event.msg)
|
||||
err = logger.LogEvent(&event)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, host, envToHost)
|
||||
assert.Equal(t, username, envFrom)
|
||||
assert.Equal(t, sendTos, envTo)
|
||||
assert.Contains(t, string(envMsg), expected)
|
||||
|
||||
logger.Close()
|
||||
}
|
83
modules/log/stack.go
Normal file
83
modules/log/stack.go
Normal file
@ -0,0 +1,83 @@
|
||||
// Copyright 2019 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 log
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
unknown = []byte("???")
|
||||
)
|
||||
|
||||
// Stack will skip back the provided number of frames and return a stack trace with source code.
|
||||
// Although we could just use debug.Stack(), this routine will return the source code and
|
||||
// skip back the provided number of frames - i.e. allowing us to ignore preceding function calls.
|
||||
// A skip of 0 returns the stack trace for the calling function, not including this call.
|
||||
// If the problem is a lack of memory of course all this is not going to work...
|
||||
func Stack(skip int) string {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
// Store the last file we opened as its probable that the preceding stack frame
|
||||
// will be in the same file
|
||||
var lines [][]byte
|
||||
var lastFilename string
|
||||
for i := skip + 1; ; i++ { // Skip over frames
|
||||
programCounter, filename, lineNumber, ok := runtime.Caller(i)
|
||||
// If we can't retrieve the information break - basically we're into go internals at this point.
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
// Print equivalent of debug.Stack()
|
||||
fmt.Fprintf(buf, "%s:%d (0x%x)\n", filename, lineNumber, programCounter)
|
||||
// Now try to print the offending line
|
||||
if filename != lastFilename {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
// can't read this sourcefile
|
||||
// likely we don't have the sourcecode available
|
||||
continue
|
||||
}
|
||||
lines = bytes.Split(data, []byte{'\n'})
|
||||
lastFilename = filename
|
||||
}
|
||||
fmt.Fprintf(buf, "\t%s: %s\n", functionName(programCounter), source(lines, lineNumber))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// functionName converts the provided programCounter into a function name
|
||||
func functionName(programCounter uintptr) []byte {
|
||||
function := runtime.FuncForPC(programCounter)
|
||||
if function == nil {
|
||||
return unknown
|
||||
}
|
||||
name := []byte(function.Name())
|
||||
|
||||
// Because we provide the filename we can drop the preceding package name.
|
||||
if lastslash := bytes.LastIndex(name, []byte("/")); lastslash >= 0 {
|
||||
name = name[lastslash+1:]
|
||||
}
|
||||
// And the current package name.
|
||||
if period := bytes.Index(name, []byte(".")); period >= 0 {
|
||||
name = name[period+1:]
|
||||
}
|
||||
// And we should just replace the interpunct with a dot
|
||||
name = bytes.Replace(name, []byte("·"), []byte("."), -1)
|
||||
return name
|
||||
}
|
||||
|
||||
// source returns a space-trimmed slice of the n'th line.
|
||||
func source(lines [][]byte, n int) []byte {
|
||||
n-- // in stack trace, lines are 1-indexed but our array is 0-indexed
|
||||
if n < 0 || n >= len(lines) {
|
||||
return unknown
|
||||
}
|
||||
return bytes.TrimSpace(lines[n])
|
||||
}
|
@ -12,7 +12,6 @@ import (
|
||||
|
||||
// XORMLogBridge a logger bridge from Logger to xorm
|
||||
type XORMLogBridge struct {
|
||||
loggers []*Logger
|
||||
showSQL bool
|
||||
level core.LogLevel
|
||||
}
|
||||
@ -22,110 +21,80 @@ var (
|
||||
XORMLogger *XORMLogBridge
|
||||
)
|
||||
|
||||
// DiscardXORMLogger inits a blank logger for xorm
|
||||
func DiscardXORMLogger() {
|
||||
// InitXORMLogger inits a log bridge for xorm
|
||||
func InitXORMLogger(showSQL bool) {
|
||||
XORMLogger = &XORMLogBridge{
|
||||
showSQL: false,
|
||||
showSQL: showSQL,
|
||||
}
|
||||
}
|
||||
|
||||
// NewXORMLogger generate logger for xorm FIXME: configable
|
||||
func NewXORMLogger(bufferlen int64, mode, config string) {
|
||||
logger := newLogger(bufferlen)
|
||||
logger.SetLogger(mode, config)
|
||||
if XORMLogger == nil {
|
||||
XORMLogger = &XORMLogBridge{
|
||||
showSQL: true,
|
||||
}
|
||||
}
|
||||
XORMLogger.loggers = append(XORMLogger.loggers, logger)
|
||||
// GetGiteaLevel returns the minimum Gitea logger level
|
||||
func (l *XORMLogBridge) GetGiteaLevel() Level {
|
||||
return GetLogger("xorm").GetLevel()
|
||||
}
|
||||
|
||||
func (l *XORMLogBridge) writerMsg(skip, level int, msg string) error {
|
||||
for _, logger := range l.loggers {
|
||||
if err := logger.writerMsg(skip, level, msg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
// Log a message with defined skip and at logging level
|
||||
func (l *XORMLogBridge) Log(skip int, level Level, format string, v ...interface{}) error {
|
||||
return GetLogger("xorm").Log(skip+1, level, format, v...)
|
||||
}
|
||||
|
||||
// Debug show debug log
|
||||
func (l *XORMLogBridge) Debug(v ...interface{}) {
|
||||
if l.level <= core.LOG_DEBUG {
|
||||
msg := fmt.Sprint(v...)
|
||||
l.writerMsg(0, DEBUG, "[D]"+msg)
|
||||
}
|
||||
l.Log(2, DEBUG, fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Debugf show debug log
|
||||
func (l *XORMLogBridge) Debugf(format string, v ...interface{}) {
|
||||
if l.level <= core.LOG_DEBUG {
|
||||
for _, logger := range l.loggers {
|
||||
logger.Debug(format, v...)
|
||||
}
|
||||
}
|
||||
l.Log(2, DEBUG, format, v...)
|
||||
}
|
||||
|
||||
// Error show error log
|
||||
func (l *XORMLogBridge) Error(v ...interface{}) {
|
||||
if l.level <= core.LOG_ERR {
|
||||
msg := fmt.Sprint(v...)
|
||||
l.writerMsg(0, ERROR, "[E]"+msg)
|
||||
}
|
||||
l.Log(2, ERROR, fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Errorf show error log
|
||||
func (l *XORMLogBridge) Errorf(format string, v ...interface{}) {
|
||||
if l.level <= core.LOG_ERR {
|
||||
for _, logger := range l.loggers {
|
||||
logger.Error(0, format, v...)
|
||||
}
|
||||
}
|
||||
l.Log(2, ERROR, format, v...)
|
||||
}
|
||||
|
||||
// Info show information level log
|
||||
func (l *XORMLogBridge) Info(v ...interface{}) {
|
||||
if l.level <= core.LOG_INFO {
|
||||
msg := fmt.Sprint(v...)
|
||||
l.writerMsg(0, INFO, "[I]"+msg)
|
||||
}
|
||||
l.Log(2, INFO, fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Infof show information level log
|
||||
func (l *XORMLogBridge) Infof(format string, v ...interface{}) {
|
||||
if l.level <= core.LOG_INFO {
|
||||
for _, logger := range l.loggers {
|
||||
logger.Info(format, v...)
|
||||
}
|
||||
}
|
||||
l.Log(2, INFO, format, v...)
|
||||
}
|
||||
|
||||
// Warn show warning log
|
||||
func (l *XORMLogBridge) Warn(v ...interface{}) {
|
||||
if l.level <= core.LOG_WARNING {
|
||||
msg := fmt.Sprint(v...)
|
||||
l.writerMsg(0, WARN, "[W] "+msg)
|
||||
}
|
||||
l.Log(2, WARN, fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Warnf show warnning log
|
||||
func (l *XORMLogBridge) Warnf(format string, v ...interface{}) {
|
||||
if l.level <= core.LOG_WARNING {
|
||||
for _, logger := range l.loggers {
|
||||
logger.Warn(format, v...)
|
||||
}
|
||||
}
|
||||
l.Log(2, WARN, format, v...)
|
||||
}
|
||||
|
||||
// Level get logger level
|
||||
func (l *XORMLogBridge) Level() core.LogLevel {
|
||||
return l.level
|
||||
switch l.GetGiteaLevel() {
|
||||
case TRACE, DEBUG:
|
||||
return core.LOG_DEBUG
|
||||
case INFO:
|
||||
return core.LOG_INFO
|
||||
case WARN:
|
||||
return core.LOG_WARNING
|
||||
case ERROR, CRITICAL:
|
||||
return core.LOG_ERR
|
||||
}
|
||||
return core.LOG_OFF
|
||||
}
|
||||
|
||||
// SetLevel set logger level
|
||||
func (l *XORMLogBridge) SetLevel(level core.LogLevel) {
|
||||
l.level = level
|
||||
// SetLevel set the logger level
|
||||
func (l *XORMLogBridge) SetLevel(lvl core.LogLevel) {
|
||||
}
|
||||
|
||||
// ShowSQL set if record SQL
|
||||
|
@ -258,7 +258,7 @@ func processMailQueue() {
|
||||
case msg := <-mailQueue:
|
||||
log.Trace("New e-mail sending request %s: %s", msg.GetHeader("To"), msg.Info)
|
||||
if err := gomail.Send(Sender, msg.Message); err != nil {
|
||||
log.Error(3, "Failed to send emails %s: %s - %v", msg.GetHeader("To"), msg.Info, err)
|
||||
log.Error("Failed to send emails %s: %s - %v", msg.GetHeader("To"), msg.Info, err)
|
||||
} else {
|
||||
log.Trace("E-mails sent %s: %s", msg.GetHeader("To"), msg.Info)
|
||||
}
|
||||
|
8
modules/markup/external/external.go
vendored
8
modules/markup/external/external.go
vendored
@ -67,7 +67,7 @@ func (p *Parser) Render(rawBytes []byte, urlPrefix string, metas map[string]stri
|
||||
// write to temp file
|
||||
f, err := ioutil.TempFile("", "gitea_input")
|
||||
if err != nil {
|
||||
log.Error(4, "%s create temp file when rendering %s failed: %v", p.Name(), p.Command, err)
|
||||
log.Error("%s create temp file when rendering %s failed: %v", p.Name(), p.Command, err)
|
||||
return []byte("")
|
||||
}
|
||||
defer os.Remove(f.Name())
|
||||
@ -75,13 +75,13 @@ func (p *Parser) Render(rawBytes []byte, urlPrefix string, metas map[string]stri
|
||||
_, err = io.Copy(f, rd)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
log.Error(4, "%s write data to temp file when rendering %s failed: %v", p.Name(), p.Command, err)
|
||||
log.Error("%s write data to temp file when rendering %s failed: %v", p.Name(), p.Command, err)
|
||||
return []byte("")
|
||||
}
|
||||
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
log.Error(4, "%s close temp file when rendering %s failed: %v", p.Name(), p.Command, err)
|
||||
log.Error("%s close temp file when rendering %s failed: %v", p.Name(), p.Command, err)
|
||||
return []byte("")
|
||||
}
|
||||
args = append(args, f.Name())
|
||||
@ -98,7 +98,7 @@ func (p *Parser) Render(rawBytes []byte, urlPrefix string, metas map[string]stri
|
||||
}
|
||||
cmd.Stdout = buf
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Error(4, "%s render run command %s %v failed: %v", p.Name(), commands[0], args, err)
|
||||
log.Error("%s render run command %s %v failed: %v", p.Name(), commands[0], args, err)
|
||||
return []byte("")
|
||||
}
|
||||
return buf.Bytes()
|
||||
|
@ -74,7 +74,7 @@ func render(parser Parser, rawBytes []byte, urlPrefix string, metas map[string]s
|
||||
// TODO: one day the error should be returned.
|
||||
result, err := PostProcess(result, urlPrefix, metas, isWiki)
|
||||
if err != nil {
|
||||
log.Error(3, "PostProcess: %v", err)
|
||||
log.Error("PostProcess: %v", err)
|
||||
}
|
||||
return SanitizeBytes(result)
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ func (Parser) Extensions() []string {
|
||||
func Render(rawBytes []byte, urlPrefix string, metas map[string]string, isWiki bool) (result []byte) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Error(4, "Panic in orgmode.Render: %v Just returning the rawBytes", err)
|
||||
log.Error("Panic in orgmode.Render: %v Just returning the rawBytes", err)
|
||||
result = rawBytes
|
||||
}
|
||||
}()
|
||||
|
@ -29,7 +29,7 @@ func (r *indexerNotifier) NotifyCreateIssueComment(doer *models.User, repo *mode
|
||||
if comment.Type == models.CommentTypeComment {
|
||||
if issue.Comments == nil {
|
||||
if err := issue.LoadDiscussComments(); err != nil {
|
||||
log.Error(4, "LoadComments failed: %v", err)
|
||||
log.Error("LoadComments failed: %v", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@ -63,7 +63,7 @@ func (r *indexerNotifier) NotifyUpdateComment(doer *models.User, c *models.Comme
|
||||
|
||||
if !found {
|
||||
if err := c.Issue.LoadDiscussComments(); err != nil {
|
||||
log.Error(4, "LoadComments failed: %v", err)
|
||||
log.Error("LoadComments failed: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -87,7 +87,7 @@ func (r *indexerNotifier) NotifyDeleteComment(doer *models.User, comment *models
|
||||
|
||||
if !found {
|
||||
if err := comment.Issue.LoadDiscussComments(); err != nil {
|
||||
log.Error(4, "LoadComments failed: %v", err)
|
||||
log.Error("LoadComments failed: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -37,25 +37,25 @@ func (m *mailNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.
|
||||
}
|
||||
|
||||
if err := comment.MailParticipants(act, issue); err != nil {
|
||||
log.Error(4, "MailParticipants: %v", err)
|
||||
log.Error("MailParticipants: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mailNotifier) NotifyNewIssue(issue *models.Issue) {
|
||||
if err := issue.MailParticipants(); err != nil {
|
||||
log.Error(4, "MailParticipants: %v", err)
|
||||
log.Error("MailParticipants: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mailNotifier) NotifyIssueChangeStatus(doer *models.User, issue *models.Issue, isClosed bool) {
|
||||
if err := issue.MailParticipants(); err != nil {
|
||||
log.Error(4, "MailParticipants: %v", err)
|
||||
log.Error("MailParticipants: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mailNotifier) NotifyNewPullRequest(pr *models.PullRequest) {
|
||||
if err := pr.Issue.MailParticipants(); err != nil {
|
||||
log.Error(4, "MailParticipants: %v", err)
|
||||
log.Error("MailParticipants: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,6 +69,6 @@ func (m *mailNotifier) NotifyPullRequestReview(pr *models.PullRequest, r *models
|
||||
act = models.ActionCommentIssue
|
||||
}
|
||||
if err := comment.MailParticipants(act, pr.Issue); err != nil {
|
||||
log.Error(4, "MailParticipants: %v", err)
|
||||
log.Error("MailParticipants: %v", err)
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ func (ns *notificationService) Run() {
|
||||
select {
|
||||
case opts := <-ns.issueQueue:
|
||||
if err := models.CreateOrUpdateIssueNotifications(opts.issue, opts.notificationAuthorID); err != nil {
|
||||
log.Error(4, "Was unable to create issue notification: %v", err)
|
||||
log.Error("Was unable to create issue notification: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,12 +17,12 @@ import (
|
||||
func DumpMemProfileForUsername(pprofDataPath, username string) {
|
||||
f, err := ioutil.TempFile(pprofDataPath, fmt.Sprintf("memprofile_%s_", username))
|
||||
if err != nil {
|
||||
log.GitLogger.Fatal(4, "Could not create memory profile: %v", err)
|
||||
log.GitLogger.Fatal("Could not create memory profile: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
runtime.GC() // get up-to-date statistics
|
||||
if err := pprof.WriteHeapProfile(f); err != nil {
|
||||
log.GitLogger.Fatal(4, "Could not write memory profile: %v", err)
|
||||
log.GitLogger.Fatal("Could not write memory profile: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ func DumpMemProfileForUsername(pprofDataPath, username string) {
|
||||
func DumpCPUProfileForUsername(pprofDataPath, username string) func() {
|
||||
f, err := ioutil.TempFile(pprofDataPath, fmt.Sprintf("cpuprofile_%s_", username))
|
||||
if err != nil {
|
||||
log.GitLogger.Fatal(4, "Could not create cpu profile: %v", err)
|
||||
log.GitLogger.Fatal("Could not create cpu profile: %v", err)
|
||||
}
|
||||
|
||||
pprof.StartCPUProfile(f)
|
||||
|
@ -35,7 +35,7 @@ func newCacheService() {
|
||||
case "redis", "memcache":
|
||||
CacheService.Conn = strings.Trim(sec.Key("HOST").String(), "\" ")
|
||||
default:
|
||||
log.Fatal(4, "Unknown cache adapter: %s", CacheService.Adapter)
|
||||
log.Fatal("Unknown cache adapter: %s", CacheService.Adapter)
|
||||
}
|
||||
CacheService.TTL = sec.Key("ITEM_TTL").MustDuration(16 * time.Hour)
|
||||
|
||||
|
@ -119,6 +119,6 @@ var (
|
||||
|
||||
func newCron() {
|
||||
if err := Cfg.Section("cron").MapTo(&Cron); err != nil {
|
||||
log.Fatal(4, "Failed to map Cron settings: %v", err)
|
||||
log.Fatal("Failed to map Cron settings: %v", err)
|
||||
}
|
||||
}
|
||||
|
@ -56,13 +56,13 @@ var (
|
||||
|
||||
func newGit() {
|
||||
if err := Cfg.Section("git").MapTo(&Git); err != nil {
|
||||
log.Fatal(4, "Failed to map Git settings: %v", err)
|
||||
log.Fatal("Failed to map Git settings: %v", err)
|
||||
}
|
||||
git.DefaultCommandExecutionTimeout = time.Duration(Git.Timeout.Default) * time.Second
|
||||
|
||||
binVersion, err := git.BinVersion()
|
||||
if err != nil {
|
||||
log.Fatal(4, "Error retrieving git version: %v", err)
|
||||
log.Fatal("Error retrieving git version: %v", err)
|
||||
}
|
||||
|
||||
if version.Compare(binVersion, "2.9", ">=") {
|
||||
|
@ -5,40 +5,238 @@
|
||||
package setting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"encoding/json"
|
||||
golog "log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"github.com/go-xorm/core"
|
||||
|
||||
ini "gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
var logLevels = map[string]string{
|
||||
"Trace": "0",
|
||||
"Debug": "1",
|
||||
"Info": "2",
|
||||
"Warn": "3",
|
||||
"Error": "4",
|
||||
"Critical": "5",
|
||||
type defaultLogOptions struct {
|
||||
levelName string // LogLevel
|
||||
flags string
|
||||
filename string //path.Join(LogRootPath, "gitea.log")
|
||||
bufferLength int64
|
||||
disableConsole bool
|
||||
}
|
||||
|
||||
func getLogLevel(section string, key string, defaultValue string) string {
|
||||
validLevels := []string{"Trace", "Debug", "Info", "Warn", "Error", "Critical"}
|
||||
return Cfg.Section(section).Key(key).In(defaultValue, validLevels)
|
||||
func newDefaultLogOptions() defaultLogOptions {
|
||||
return defaultLogOptions{
|
||||
levelName: LogLevel,
|
||||
flags: "stdflags",
|
||||
filename: filepath.Join(LogRootPath, "gitea.log"),
|
||||
bufferLength: 10000,
|
||||
disableConsole: false,
|
||||
}
|
||||
}
|
||||
|
||||
// SubLogDescription describes a sublogger
|
||||
type SubLogDescription struct {
|
||||
Name string
|
||||
Provider string
|
||||
Config string
|
||||
}
|
||||
|
||||
// LogDescription describes a named logger
|
||||
type LogDescription struct {
|
||||
Name string
|
||||
SubLogDescriptions []SubLogDescription
|
||||
}
|
||||
|
||||
func getLogLevel(section *ini.Section, key string, defaultValue string) string {
|
||||
value := section.Key(key).MustString("info")
|
||||
return log.FromString(value).String()
|
||||
}
|
||||
|
||||
func getStacktraceLogLevel(section *ini.Section, key string, defaultValue string) string {
|
||||
value := section.Key(key).MustString("none")
|
||||
return log.FromString(value).String()
|
||||
}
|
||||
|
||||
func generateLogConfig(sec *ini.Section, name string, defaults defaultLogOptions) (mode, jsonConfig, levelName string) {
|
||||
levelName = getLogLevel(sec, "LEVEL", LogLevel)
|
||||
level := log.FromString(levelName)
|
||||
stacktraceLevelName := getStacktraceLogLevel(sec, "STACKTRACE_LEVEL", StacktraceLogLevel)
|
||||
stacktraceLevel := log.FromString(stacktraceLevelName)
|
||||
mode = name
|
||||
keys := sec.Keys()
|
||||
logPath := defaults.filename
|
||||
flags := log.FlagsFromString(defaults.flags)
|
||||
expression := ""
|
||||
prefix := ""
|
||||
for _, key := range keys {
|
||||
switch key.Name() {
|
||||
case "MODE":
|
||||
mode = key.MustString(name)
|
||||
case "FILE_NAME":
|
||||
logPath = key.MustString(defaults.filename)
|
||||
forcePathSeparator(logPath)
|
||||
if !filepath.IsAbs(logPath) {
|
||||
logPath = path.Join(LogRootPath, logPath)
|
||||
}
|
||||
case "FLAGS":
|
||||
flags = log.FlagsFromString(key.MustString(defaults.flags))
|
||||
case "EXPRESSION":
|
||||
expression = key.MustString("")
|
||||
case "PREFIX":
|
||||
prefix = key.MustString("")
|
||||
}
|
||||
}
|
||||
|
||||
logConfig := map[string]interface{}{
|
||||
"level": level.String(),
|
||||
"expression": expression,
|
||||
"prefix": prefix,
|
||||
"flags": flags,
|
||||
"stacktraceLevel": stacktraceLevel.String(),
|
||||
}
|
||||
|
||||
// Generate log configuration.
|
||||
switch mode {
|
||||
case "console":
|
||||
useStderr := sec.Key("STDERR").MustBool(false)
|
||||
logConfig["stderr"] = useStderr
|
||||
if useStderr {
|
||||
logConfig["colorize"] = sec.Key("COLORIZE").MustBool(log.CanColorStderr)
|
||||
} else {
|
||||
logConfig["colorize"] = sec.Key("COLORIZE").MustBool(log.CanColorStdout)
|
||||
}
|
||||
|
||||
case "file":
|
||||
if err := os.MkdirAll(path.Dir(logPath), os.ModePerm); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
logConfig["colorize"] = sec.Key("COLORIZE").MustBool(runtime.GOOS != "windows")
|
||||
logConfig["filename"] = logPath
|
||||
logConfig["rotate"] = sec.Key("LOG_ROTATE").MustBool(true)
|
||||
logConfig["maxsize"] = 1 << uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28))
|
||||
logConfig["daily"] = sec.Key("DAILY_ROTATE").MustBool(true)
|
||||
logConfig["maxdays"] = sec.Key("MAX_DAYS").MustInt(7)
|
||||
logConfig["compress"] = sec.Key("COMPRESS").MustBool(true)
|
||||
logConfig["compressionLevel"] = sec.Key("COMPRESSION_LEVEL").MustInt(-1)
|
||||
case "conn":
|
||||
logConfig["reconnectOnMsg"] = sec.Key("RECONNECT_ON_MSG").MustBool()
|
||||
logConfig["reconnect"] = sec.Key("RECONNECT").MustBool()
|
||||
logConfig["net"] = sec.Key("PROTOCOL").In("tcp", []string{"tcp", "unix", "udp"})
|
||||
logConfig["addr"] = sec.Key("ADDR").MustString(":7020")
|
||||
case "smtp":
|
||||
logConfig["username"] = sec.Key("USER").MustString("example@example.com")
|
||||
logConfig["password"] = sec.Key("PASSWD").MustString("******")
|
||||
logConfig["host"] = sec.Key("HOST").MustString("127.0.0.1:25")
|
||||
logConfig["sendTos"] = sec.Key("RECEIVERS").MustString("[]")
|
||||
logConfig["subject"] = sec.Key("SUBJECT").MustString("Diagnostic message from Gitea")
|
||||
}
|
||||
|
||||
logConfig["colorize"] = sec.Key("COLORIZE").MustBool(false)
|
||||
|
||||
byteConfig, err := json.Marshal(logConfig)
|
||||
if err != nil {
|
||||
log.Error("Failed to marshal log configuration: %v %v", logConfig, err)
|
||||
return
|
||||
}
|
||||
jsonConfig = string(byteConfig)
|
||||
return
|
||||
}
|
||||
|
||||
func generateNamedLogger(key string, options defaultLogOptions) *LogDescription {
|
||||
description := LogDescription{
|
||||
Name: key,
|
||||
}
|
||||
|
||||
sections := strings.Split(Cfg.Section("log").Key(strings.ToUpper(key)).MustString(""), ",")
|
||||
|
||||
//description.Configs = make([]string, len(description.Sections))
|
||||
|
||||
for i := 0; i < len(sections); i++ {
|
||||
sections[i] = strings.TrimSpace(sections[i])
|
||||
}
|
||||
|
||||
for _, name := range sections {
|
||||
if len(name) == 0 || (name == "console" && options.disableConsole) {
|
||||
continue
|
||||
}
|
||||
sec, err := Cfg.GetSection("log." + name + "." + key)
|
||||
if err != nil {
|
||||
sec, _ = Cfg.NewSection("log." + name + "." + key)
|
||||
}
|
||||
|
||||
provider, config, levelName := generateLogConfig(sec, name, options)
|
||||
|
||||
log.NewNamedLogger(key, options.bufferLength, name, provider, config)
|
||||
|
||||
description.SubLogDescriptions = append(description.SubLogDescriptions, SubLogDescription{
|
||||
Name: name,
|
||||
Provider: provider,
|
||||
Config: config,
|
||||
})
|
||||
log.Info("%s Log: %s(%s:%s)", strings.Title(key), strings.Title(name), provider, levelName)
|
||||
}
|
||||
|
||||
LogDescriptions[key] = &description
|
||||
|
||||
return &description
|
||||
}
|
||||
|
||||
func newMacaronLogService() {
|
||||
options := newDefaultLogOptions()
|
||||
options.filename = filepath.Join(LogRootPath, "macaron.log")
|
||||
options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000)
|
||||
|
||||
Cfg.Section("log").Key("MACARON").MustString("file")
|
||||
if RedirectMacaronLog {
|
||||
generateNamedLogger("macaron", options)
|
||||
}
|
||||
}
|
||||
|
||||
func newAccessLogService() {
|
||||
EnableAccessLog = Cfg.Section("log").Key("ENABLE_ACCESS_LOG").MustBool(false)
|
||||
AccessLogTemplate = Cfg.Section("log").Key("ACCESS_LOG_TEMPLATE").MustString(
|
||||
`{{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}"`)
|
||||
Cfg.Section("log").Key("ACCESS").MustString("file")
|
||||
if EnableAccessLog {
|
||||
options := newDefaultLogOptions()
|
||||
options.filename = filepath.Join(LogRootPath, "access.log")
|
||||
options.flags = "" // For the router we don't want any prefixed flags
|
||||
options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000)
|
||||
generateNamedLogger("access", options)
|
||||
}
|
||||
}
|
||||
|
||||
func newRouterLogService() {
|
||||
Cfg.Section("log").Key("ROUTER").MustString("console")
|
||||
|
||||
if !DisableRouterLog && RedirectMacaronLog {
|
||||
options := newDefaultLogOptions()
|
||||
options.filename = filepath.Join(LogRootPath, "router.log")
|
||||
options.flags = "date,time" // For the router we don't want any prefixed flags
|
||||
options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000)
|
||||
generateNamedLogger("router", options)
|
||||
}
|
||||
}
|
||||
|
||||
func newLogService() {
|
||||
log.Info("Gitea v%s%s", AppVer, AppBuiltWith)
|
||||
|
||||
LogModes = strings.Split(Cfg.Section("log").Key("MODE").MustString("console"), ",")
|
||||
LogConfigs = make([]string, len(LogModes))
|
||||
options := newDefaultLogOptions()
|
||||
options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000)
|
||||
|
||||
description := LogDescription{
|
||||
Name: log.DEFAULT,
|
||||
}
|
||||
|
||||
sections := strings.Split(Cfg.Section("log").Key("MODE").MustString("console"), ",")
|
||||
|
||||
useConsole := false
|
||||
for i := 0; i < len(LogModes); i++ {
|
||||
LogModes[i] = strings.TrimSpace(LogModes[i])
|
||||
if LogModes[i] == "console" {
|
||||
for i := 0; i < len(sections); i++ {
|
||||
sections[i] = strings.TrimSpace(sections[i])
|
||||
if sections[i] == "console" {
|
||||
useConsole = true
|
||||
}
|
||||
}
|
||||
@ -47,140 +245,47 @@ func newLogService() {
|
||||
log.DelLogger("console")
|
||||
}
|
||||
|
||||
for i, mode := range LogModes {
|
||||
sec, err := Cfg.GetSection("log." + mode)
|
||||
for _, name := range sections {
|
||||
if len(name) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
sec, err := Cfg.GetSection("log." + name)
|
||||
if err != nil {
|
||||
sec, _ = Cfg.NewSection("log." + mode)
|
||||
sec, _ = Cfg.NewSection("log." + name)
|
||||
}
|
||||
|
||||
// Log level.
|
||||
levelName := getLogLevel("log."+mode, "LEVEL", LogLevel)
|
||||
level, ok := logLevels[levelName]
|
||||
if !ok {
|
||||
log.Fatal(4, "Unknown log level: %s", levelName)
|
||||
}
|
||||
|
||||
// Generate log configuration.
|
||||
switch mode {
|
||||
case "console":
|
||||
LogConfigs[i] = fmt.Sprintf(`{"level":%s}`, level)
|
||||
case "file":
|
||||
logPath := sec.Key("FILE_NAME").MustString(path.Join(LogRootPath, "gitea.log"))
|
||||
if err = os.MkdirAll(path.Dir(logPath), os.ModePerm); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
LogConfigs[i] = fmt.Sprintf(
|
||||
`{"level":%s,"filename":"%s","rotate":%v,"maxsize":%d,"daily":%v,"maxdays":%d}`, level,
|
||||
logPath,
|
||||
sec.Key("LOG_ROTATE").MustBool(true),
|
||||
1<<uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28)),
|
||||
sec.Key("DAILY_ROTATE").MustBool(true),
|
||||
sec.Key("MAX_DAYS").MustInt(7))
|
||||
case "conn":
|
||||
LogConfigs[i] = fmt.Sprintf(`{"level":%s,"reconnectOnMsg":%v,"reconnect":%v,"net":"%s","addr":"%s"}`, level,
|
||||
sec.Key("RECONNECT_ON_MSG").MustBool(),
|
||||
sec.Key("RECONNECT").MustBool(),
|
||||
sec.Key("PROTOCOL").In("tcp", []string{"tcp", "unix", "udp"}),
|
||||
sec.Key("ADDR").MustString(":7020"))
|
||||
case "smtp":
|
||||
LogConfigs[i] = fmt.Sprintf(`{"level":%s,"username":"%s","password":"%s","host":"%s","sendTos":["%s"],"subject":"%s"}`, level,
|
||||
sec.Key("USER").MustString("example@example.com"),
|
||||
sec.Key("PASSWD").MustString("******"),
|
||||
sec.Key("HOST").MustString("127.0.0.1:25"),
|
||||
strings.Replace(sec.Key("RECEIVERS").MustString("example@example.com"), ",", "\",\"", -1),
|
||||
sec.Key("SUBJECT").MustString("Diagnostic message from serve"))
|
||||
case "database":
|
||||
LogConfigs[i] = fmt.Sprintf(`{"level":%s,"driver":"%s","conn":"%s"}`, level,
|
||||
sec.Key("DRIVER").String(),
|
||||
sec.Key("CONN").String())
|
||||
}
|
||||
|
||||
log.NewLogger(Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000), mode, LogConfigs[i])
|
||||
log.Info("Log Mode: %s(%s)", strings.Title(mode), levelName)
|
||||
provider, config, levelName := generateLogConfig(sec, name, options)
|
||||
log.NewLogger(options.bufferLength, name, provider, config)
|
||||
description.SubLogDescriptions = append(description.SubLogDescriptions, SubLogDescription{
|
||||
Name: name,
|
||||
Provider: provider,
|
||||
Config: config,
|
||||
})
|
||||
log.Info("Gitea Log Mode: %s(%s:%s)", strings.Title(name), strings.Title(provider), levelName)
|
||||
}
|
||||
|
||||
LogDescriptions[log.DEFAULT] = &description
|
||||
|
||||
// Finally redirect the default golog to here
|
||||
golog.SetFlags(0)
|
||||
golog.SetPrefix("")
|
||||
golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT)))
|
||||
}
|
||||
|
||||
// NewXORMLogService initializes xorm logger service
|
||||
func NewXORMLogService(disableConsole bool) {
|
||||
logModes := strings.Split(Cfg.Section("log").Key("MODE").MustString("console"), ",")
|
||||
var logConfigs string
|
||||
for _, mode := range logModes {
|
||||
mode = strings.TrimSpace(mode)
|
||||
EnableXORMLog = Cfg.Section("log").Key("ENABLE_XORM_LOG").MustBool(true)
|
||||
if EnableXORMLog {
|
||||
options := newDefaultLogOptions()
|
||||
options.filename = filepath.Join(LogRootPath, "xorm.log")
|
||||
options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000)
|
||||
options.disableConsole = disableConsole
|
||||
|
||||
if disableConsole && mode == "console" {
|
||||
continue
|
||||
}
|
||||
|
||||
sec, err := Cfg.GetSection("log." + mode)
|
||||
if err != nil {
|
||||
sec, _ = Cfg.NewSection("log." + mode)
|
||||
}
|
||||
|
||||
// Log level.
|
||||
levelName := getLogLevel("log."+mode, "LEVEL", LogLevel)
|
||||
level, ok := logLevels[levelName]
|
||||
if !ok {
|
||||
log.Fatal(4, "Unknown log level: %s", levelName)
|
||||
}
|
||||
|
||||
// Generate log configuration.
|
||||
switch mode {
|
||||
case "console":
|
||||
logConfigs = fmt.Sprintf(`{"level":%s}`, level)
|
||||
case "file":
|
||||
logPath := sec.Key("FILE_NAME").MustString(path.Join(LogRootPath, "xorm.log"))
|
||||
if err = os.MkdirAll(path.Dir(logPath), os.ModePerm); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
logPath = path.Join(filepath.Dir(logPath), "xorm.log")
|
||||
|
||||
logConfigs = fmt.Sprintf(
|
||||
`{"level":%s,"filename":"%s","rotate":%v,"maxsize":%d,"daily":%v,"maxdays":%d}`, level,
|
||||
logPath,
|
||||
sec.Key("LOG_ROTATE").MustBool(true),
|
||||
1<<uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28)),
|
||||
sec.Key("DAILY_ROTATE").MustBool(true),
|
||||
sec.Key("MAX_DAYS").MustInt(7))
|
||||
case "conn":
|
||||
logConfigs = fmt.Sprintf(`{"level":%s,"reconnectOnMsg":%v,"reconnect":%v,"net":"%s","addr":"%s"}`, level,
|
||||
sec.Key("RECONNECT_ON_MSG").MustBool(),
|
||||
sec.Key("RECONNECT").MustBool(),
|
||||
sec.Key("PROTOCOL").In("tcp", []string{"tcp", "unix", "udp"}),
|
||||
sec.Key("ADDR").MustString(":7020"))
|
||||
case "smtp":
|
||||
logConfigs = fmt.Sprintf(`{"level":%s,"username":"%s","password":"%s","host":"%s","sendTos":"%s","subject":"%s"}`, level,
|
||||
sec.Key("USER").MustString("example@example.com"),
|
||||
sec.Key("PASSWD").MustString("******"),
|
||||
sec.Key("HOST").MustString("127.0.0.1:25"),
|
||||
sec.Key("RECEIVERS").MustString("[]"),
|
||||
sec.Key("SUBJECT").MustString("Diagnostic message from serve"))
|
||||
case "database":
|
||||
logConfigs = fmt.Sprintf(`{"level":%s,"driver":"%s","conn":"%s"}`, level,
|
||||
sec.Key("DRIVER").String(),
|
||||
sec.Key("CONN").String())
|
||||
}
|
||||
|
||||
log.NewXORMLogger(Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000), mode, logConfigs)
|
||||
if !disableConsole {
|
||||
log.Info("XORM Log Mode: %s(%s)", strings.Title(mode), levelName)
|
||||
}
|
||||
|
||||
var lvl core.LogLevel
|
||||
switch levelName {
|
||||
case "Trace", "Debug":
|
||||
lvl = core.LOG_DEBUG
|
||||
case "Info":
|
||||
lvl = core.LOG_INFO
|
||||
case "Warn":
|
||||
lvl = core.LOG_WARNING
|
||||
case "Error", "Critical":
|
||||
lvl = core.LOG_ERR
|
||||
}
|
||||
log.XORMLogger.SetLevel(lvl)
|
||||
}
|
||||
|
||||
if len(logConfigs) == 0 {
|
||||
log.DiscardXORMLogger()
|
||||
Cfg.Section("log").Key("XORM").MustString(",")
|
||||
generateNamedLogger("xorm", options)
|
||||
log.InitXORMLogger(LogSQL)
|
||||
} else {
|
||||
log.InitXORMLogger(false)
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ func newMailService() {
|
||||
|
||||
parsed, err := mail.ParseAddress(MailService.From)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Invalid mailer.FROM (%s): %v", MailService.From, err)
|
||||
log.Fatal("Invalid mailer.FROM (%s): %v", MailService.From, err)
|
||||
}
|
||||
MailService.FromName = parsed.Name
|
||||
MailService.FromEmail = parsed.Address
|
||||
@ -96,7 +96,7 @@ func newMailService() {
|
||||
if MailService.MailerType == "sendmail" {
|
||||
MailService.SendmailArgs, err = shellquote.Split(sec.Key("SENDMAIL_ARGS").String())
|
||||
if err != nil {
|
||||
log.Error(4, "Failed to parse Sendmail args: %v", CustomConf, err)
|
||||
log.Error("Failed to parse Sendmail args: %s with error %v", CustomConf, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@ var (
|
||||
func newRepository() {
|
||||
homeDir, err := com.HomeDir()
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to get home directory: %v", err)
|
||||
log.Fatal("Failed to get home directory: %v", err)
|
||||
}
|
||||
homeDir = strings.Replace(homeDir, "\\", "/", -1)
|
||||
|
||||
@ -151,15 +151,15 @@ func newRepository() {
|
||||
ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash")
|
||||
|
||||
if err = Cfg.Section("repository").MapTo(&Repository); err != nil {
|
||||
log.Fatal(4, "Failed to map Repository settings: %v", err)
|
||||
log.Fatal("Failed to map Repository settings: %v", err)
|
||||
} else if err = Cfg.Section("repository.editor").MapTo(&Repository.Editor); err != nil {
|
||||
log.Fatal(4, "Failed to map Repository.Editor settings: %v", err)
|
||||
log.Fatal("Failed to map Repository.Editor settings: %v", err)
|
||||
} else if err = Cfg.Section("repository.upload").MapTo(&Repository.Upload); err != nil {
|
||||
log.Fatal(4, "Failed to map Repository.Upload settings: %v", err)
|
||||
log.Fatal("Failed to map Repository.Upload settings: %v", err)
|
||||
} else if err = Cfg.Section("repository.local").MapTo(&Repository.Local); err != nil {
|
||||
log.Fatal(4, "Failed to map Repository.Local settings: %v", err)
|
||||
log.Fatal("Failed to map Repository.Local settings: %v", err)
|
||||
} else if err = Cfg.Section("repository.pull-request").MapTo(&Repository.PullRequest); err != nil {
|
||||
log.Fatal(4, "Failed to map Repository.PullRequest settings: %v", err)
|
||||
log.Fatal("Failed to map Repository.PullRequest settings: %v", err)
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(Repository.Upload.TempPath) {
|
||||
|
@ -7,6 +7,7 @@ package setting
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
@ -15,7 +16,6 @@ import (
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -90,7 +90,6 @@ var (
|
||||
RedirectOtherPort bool
|
||||
PortToRedirect string
|
||||
OfflineMode bool
|
||||
DisableRouterLog bool
|
||||
CertFile string
|
||||
KeyFile string
|
||||
StaticRootPath string
|
||||
@ -259,10 +258,16 @@ var (
|
||||
|
||||
// Log settings
|
||||
LogLevel string
|
||||
StacktraceLogLevel string
|
||||
LogRootPath string
|
||||
LogModes []string
|
||||
LogConfigs []string
|
||||
LogDescriptions = make(map[string]*LogDescription)
|
||||
RedirectMacaronLog bool
|
||||
DisableRouterLog bool
|
||||
RouterLogLevel log.Level
|
||||
RouterLogMode string
|
||||
EnableAccessLog bool
|
||||
AccessLogTemplate string
|
||||
EnableXORMLog bool
|
||||
|
||||
// Attachment settings
|
||||
AttachmentPath string
|
||||
@ -398,19 +403,19 @@ func getWorkPath(appPath string) string {
|
||||
}
|
||||
|
||||
func init() {
|
||||
IsWindows = runtime.GOOS == "windows"
|
||||
log.NewLogger(0, "console", `{"level": 0}`)
|
||||
// We can rely on log.CanColorStdout being set properly because modules/log/console_windows.go comes before modules/setting/setting.go lexicographically
|
||||
log.NewLogger(0, "console", "console", fmt.Sprintf(`{"level": "trace", "colorize": %t, "stacktraceLevel": "none"}`, log.CanColorStdout))
|
||||
|
||||
var err error
|
||||
if AppPath, err = getAppPath(); err != nil {
|
||||
log.Fatal(4, "Failed to get app path: %v", err)
|
||||
log.Fatal("Failed to get app path: %v", err)
|
||||
}
|
||||
AppWorkPath = getWorkPath(AppPath)
|
||||
}
|
||||
|
||||
func forcePathSeparator(path string) {
|
||||
if strings.Contains(path, "\\") {
|
||||
log.Fatal(4, "Do not use '\\' or '\\\\' in paths, instead, please use '/' in all places")
|
||||
log.Fatal("Do not use '\\' or '\\\\' in paths, instead, please use '/' in all places")
|
||||
}
|
||||
}
|
||||
|
||||
@ -430,16 +435,16 @@ func IsRunUserMatchCurrentUser(runUser string) (string, bool) {
|
||||
func createPIDFile(pidPath string) {
|
||||
currentPid := os.Getpid()
|
||||
if err := os.MkdirAll(filepath.Dir(pidPath), os.ModePerm); err != nil {
|
||||
log.Fatal(4, "Failed to create PID folder: %v", err)
|
||||
log.Fatal("Failed to create PID folder: %v", err)
|
||||
}
|
||||
|
||||
file, err := os.Create(pidPath)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to create PID file: %v", err)
|
||||
log.Fatal("Failed to create PID file: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
if _, err := file.WriteString(strconv.FormatInt(int64(currentPid), 10)); err != nil {
|
||||
log.Fatal(4, "Failed to write PID information: %v", err)
|
||||
log.Fatal("Failed to write PID information: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -451,12 +456,12 @@ func CheckLFSVersion() {
|
||||
|
||||
binVersion, err := git.BinVersion()
|
||||
if err != nil {
|
||||
log.Fatal(4, "Error retrieving git version: %v", err)
|
||||
log.Fatal("Error retrieving git version: %v", err)
|
||||
}
|
||||
|
||||
if !version.Compare(binVersion, "2.1.2", ">=") {
|
||||
LFS.StartServer = false
|
||||
log.Error(4, "LFS server support needs at least Git v2.1.2")
|
||||
log.Error("LFS server support needs at least Git v2.1.2")
|
||||
} else {
|
||||
git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "filter.lfs.required=",
|
||||
"-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=")
|
||||
@ -488,7 +493,7 @@ func NewContext() {
|
||||
|
||||
if com.IsFile(CustomConf) {
|
||||
if err := Cfg.Append(CustomConf); err != nil {
|
||||
log.Fatal(4, "Failed to load custom conf '%s': %v", CustomConf, err)
|
||||
log.Fatal("Failed to load custom conf '%s': %v", CustomConf, err)
|
||||
}
|
||||
} else {
|
||||
log.Warn("Custom config '%s' not found, ignore this if you're running first time", CustomConf)
|
||||
@ -497,14 +502,16 @@ func NewContext() {
|
||||
|
||||
homeDir, err := com.HomeDir()
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to get home directory: %v", err)
|
||||
log.Fatal("Failed to get home directory: %v", err)
|
||||
}
|
||||
homeDir = strings.Replace(homeDir, "\\", "/", -1)
|
||||
|
||||
LogLevel = getLogLevel("log", "LEVEL", "Info")
|
||||
LogLevel = getLogLevel(Cfg.Section("log"), "LEVEL", "Info")
|
||||
StacktraceLogLevel = getStacktraceLogLevel(Cfg.Section("log"), "STACKTRACE_LEVEL", "None")
|
||||
LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(AppWorkPath, "log"))
|
||||
forcePathSeparator(LogRootPath)
|
||||
RedirectMacaronLog = Cfg.Section("log").Key("REDIRECT_MACARON_LOG").MustBool(false)
|
||||
RouterLogLevel = log.FromString(Cfg.Section("log").Key("ROUTER_LOG_LEVEL").MustString("Info"))
|
||||
|
||||
sec := Cfg.Section("server")
|
||||
AppName = Cfg.Section("").Key("APP_NAME").MustString("Gitea: Git with a cup of tea")
|
||||
@ -521,7 +528,7 @@ func NewContext() {
|
||||
UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666")
|
||||
UnixSocketPermissionParsed, err := strconv.ParseUint(UnixSocketPermissionRaw, 8, 32)
|
||||
if err != nil || UnixSocketPermissionParsed > 0777 {
|
||||
log.Fatal(4, "Failed to parse unixSocketPermission: %s", UnixSocketPermissionRaw)
|
||||
log.Fatal("Failed to parse unixSocketPermission: %s", UnixSocketPermissionRaw)
|
||||
}
|
||||
UnixSocketPermission = uint32(UnixSocketPermissionParsed)
|
||||
}
|
||||
@ -547,7 +554,7 @@ func NewContext() {
|
||||
// Check if has app suburl.
|
||||
url, err := url.Parse(AppURL)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Invalid ROOT_URL '%s': %s", AppURL, err)
|
||||
log.Fatal("Invalid ROOT_URL '%s': %s", AppURL, err)
|
||||
}
|
||||
// Suburl should start with '/' and end without '/', such as '/{subpath}'.
|
||||
// This value is empty if site does not have sub-url.
|
||||
@ -616,7 +623,7 @@ func NewContext() {
|
||||
}
|
||||
SSH.KeyTestPath = os.TempDir()
|
||||
if err = Cfg.Section("server").MapTo(&SSH); err != nil {
|
||||
log.Fatal(4, "Failed to map SSH settings: %v", err)
|
||||
log.Fatal("Failed to map SSH settings: %v", err)
|
||||
}
|
||||
|
||||
SSH.KeygenPath = sec.Key("SSH_KEYGEN_PATH").MustString("ssh-keygen")
|
||||
@ -630,9 +637,9 @@ func NewContext() {
|
||||
|
||||
if !SSH.Disabled && !SSH.StartBuiltinServer {
|
||||
if err := os.MkdirAll(SSH.RootPath, 0700); err != nil {
|
||||
log.Fatal(4, "Failed to create '%s': %v", SSH.RootPath, err)
|
||||
log.Fatal("Failed to create '%s': %v", SSH.RootPath, err)
|
||||
} else if err = os.MkdirAll(SSH.KeyTestPath, 0644); err != nil {
|
||||
log.Fatal(4, "Failed to create '%s': %v", SSH.KeyTestPath, err)
|
||||
log.Fatal("Failed to create '%s': %v", SSH.KeyTestPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -650,7 +657,7 @@ func NewContext() {
|
||||
|
||||
sec = Cfg.Section("server")
|
||||
if err = sec.MapTo(&LFS); err != nil {
|
||||
log.Fatal(4, "Failed to map LFS settings: %v", err)
|
||||
log.Fatal("Failed to map LFS settings: %v", err)
|
||||
}
|
||||
LFS.ContentPath = sec.Key("LFS_CONTENT_PATH").MustString(filepath.Join(AppDataPath, "lfs"))
|
||||
if !filepath.IsAbs(LFS.ContentPath) {
|
||||
@ -661,7 +668,7 @@ func NewContext() {
|
||||
|
||||
if LFS.StartServer {
|
||||
if err := os.MkdirAll(LFS.ContentPath, 0700); err != nil {
|
||||
log.Fatal(4, "Failed to create '%s': %v", LFS.ContentPath, err)
|
||||
log.Fatal("Failed to create '%s': %v", LFS.ContentPath, err)
|
||||
}
|
||||
|
||||
LFS.JWTSecretBytes = make([]byte, 32)
|
||||
@ -670,7 +677,7 @@ func NewContext() {
|
||||
if err != nil || n != 32 {
|
||||
LFS.JWTSecretBase64, err = generate.NewJwtSecret()
|
||||
if err != nil {
|
||||
log.Fatal(4, "Error generating JWT Secret for custom config: %v", err)
|
||||
log.Fatal("Error generating JWT Secret for custom config: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -679,24 +686,24 @@ func NewContext() {
|
||||
if com.IsFile(CustomConf) {
|
||||
// Keeps custom settings if there is already something.
|
||||
if err := cfg.Append(CustomConf); err != nil {
|
||||
log.Error(4, "Failed to load custom conf '%s': %v", CustomConf, err)
|
||||
log.Error("Failed to load custom conf '%s': %v", CustomConf, err)
|
||||
}
|
||||
}
|
||||
|
||||
cfg.Section("server").Key("LFS_JWT_SECRET").SetValue(LFS.JWTSecretBase64)
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(CustomConf), os.ModePerm); err != nil {
|
||||
log.Fatal(4, "Failed to create '%s': %v", CustomConf, err)
|
||||
log.Fatal("Failed to create '%s': %v", CustomConf, err)
|
||||
}
|
||||
if err := cfg.SaveTo(CustomConf); err != nil {
|
||||
log.Fatal(4, "Error saving generated JWT Secret to custom config: %v", err)
|
||||
log.Fatal("Error saving generated JWT Secret to custom config: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err = Cfg.Section("oauth2").MapTo(&OAuth2); err != nil {
|
||||
log.Fatal(4, "Failed to OAuth2 settings: %v", err)
|
||||
log.Fatal("Failed to OAuth2 settings: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -707,24 +714,24 @@ func NewContext() {
|
||||
if err != nil || n != 32 {
|
||||
OAuth2.JWTSecretBase64, err = generate.NewJwtSecret()
|
||||
if err != nil {
|
||||
log.Fatal(4, "error generating JWT secret: %v", err)
|
||||
log.Fatal("error generating JWT secret: %v", err)
|
||||
return
|
||||
}
|
||||
cfg := ini.Empty()
|
||||
if com.IsFile(CustomConf) {
|
||||
if err := cfg.Append(CustomConf); err != nil {
|
||||
log.Error(4, "failed to load custom conf %s: %v", CustomConf, err)
|
||||
log.Error("failed to load custom conf %s: %v", CustomConf, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
cfg.Section("oauth2").Key("JWT_SECRET").SetValue(OAuth2.JWTSecretBase64)
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(CustomConf), os.ModePerm); err != nil {
|
||||
log.Fatal(4, "failed to create '%s': %v", CustomConf, err)
|
||||
log.Fatal("failed to create '%s': %v", CustomConf, err)
|
||||
return
|
||||
}
|
||||
if err := cfg.SaveTo(CustomConf); err != nil {
|
||||
log.Fatal(4, "error saving generating JWT secret to custom config: %v", err)
|
||||
log.Fatal("error saving generating JWT secret to custom config: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -780,7 +787,7 @@ func NewContext() {
|
||||
TimeFormat = TimeFormatKey
|
||||
TestTimeFormat, _ := time.Parse(TimeFormat, TimeFormat)
|
||||
if TestTimeFormat.Format(time.RFC3339) != "2006-01-02T15:04:05Z" {
|
||||
log.Fatal(4, "Can't create time properly, please check your time format has 2006, 01, 02, 15, 04 and 05")
|
||||
log.Fatal("Can't create time properly, please check your time format has 2006, 01, 02, 15, 04 and 05")
|
||||
}
|
||||
log.Trace("Custom TimeFormat: %s", TimeFormat)
|
||||
}
|
||||
@ -790,7 +797,7 @@ func NewContext() {
|
||||
if InstallLock {
|
||||
currentUser, match := IsRunUserMatchCurrentUser(RunUser)
|
||||
if !match {
|
||||
log.Fatal(4, "Expect user '%s' but current user is: %s", RunUser, currentUser)
|
||||
log.Fatal("Expect user '%s' but current user is: %s", RunUser, currentUser)
|
||||
}
|
||||
}
|
||||
|
||||
@ -828,7 +835,7 @@ func NewContext() {
|
||||
if EnableFederatedAvatar || !DisableGravatar {
|
||||
GravatarSourceURL, err = url.Parse(GravatarSource)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to parse Gravatar URL(%s): %v",
|
||||
log.Fatal("Failed to parse Gravatar URL(%s): %v",
|
||||
GravatarSource, err)
|
||||
}
|
||||
}
|
||||
@ -845,15 +852,15 @@ func NewContext() {
|
||||
}
|
||||
|
||||
if err = Cfg.Section("ui").MapTo(&UI); err != nil {
|
||||
log.Fatal(4, "Failed to map UI settings: %v", err)
|
||||
log.Fatal("Failed to map UI settings: %v", err)
|
||||
} else if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil {
|
||||
log.Fatal(4, "Failed to map Markdown settings: %v", err)
|
||||
log.Fatal("Failed to map Markdown settings: %v", err)
|
||||
} else if err = Cfg.Section("admin").MapTo(&Admin); err != nil {
|
||||
log.Fatal(4, "Fail to map Admin settings: %v", err)
|
||||
log.Fatal("Fail to map Admin settings: %v", err)
|
||||
} else if err = Cfg.Section("api").MapTo(&API); err != nil {
|
||||
log.Fatal(4, "Failed to map API settings: %v", err)
|
||||
log.Fatal("Failed to map API settings: %v", err)
|
||||
} else if err = Cfg.Section("metrics").MapTo(&Metrics); err != nil {
|
||||
log.Fatal(4, "Failed to map Metrics settings: %v", err)
|
||||
log.Fatal("Failed to map Metrics settings: %v", err)
|
||||
}
|
||||
|
||||
newCron()
|
||||
@ -909,35 +916,35 @@ func loadInternalToken(sec *ini.Section) string {
|
||||
}
|
||||
tempURI, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to parse INTERNAL_TOKEN_URI (%s): %v", uri, err)
|
||||
log.Fatal("Failed to parse INTERNAL_TOKEN_URI (%s): %v", uri, err)
|
||||
}
|
||||
switch tempURI.Scheme {
|
||||
case "file":
|
||||
fp, err := os.OpenFile(tempURI.RequestURI(), os.O_RDWR, 0600)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to open InternalTokenURI (%s): %v", uri, err)
|
||||
log.Fatal("Failed to open InternalTokenURI (%s): %v", uri, err)
|
||||
}
|
||||
defer fp.Close()
|
||||
|
||||
buf, err := ioutil.ReadAll(fp)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to read InternalTokenURI (%s): %v", uri, err)
|
||||
log.Fatal("Failed to read InternalTokenURI (%s): %v", uri, err)
|
||||
}
|
||||
// No token in the file, generate one and store it.
|
||||
if len(buf) == 0 {
|
||||
token, err := generate.NewInternalToken()
|
||||
if err != nil {
|
||||
log.Fatal(4, "Error generate internal token: %v", err)
|
||||
log.Fatal("Error generate internal token: %v", err)
|
||||
}
|
||||
if _, err := io.WriteString(fp, token); err != nil {
|
||||
log.Fatal(4, "Error writing to InternalTokenURI (%s): %v", uri, err)
|
||||
log.Fatal("Error writing to InternalTokenURI (%s): %v", uri, err)
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
||||
return string(buf)
|
||||
default:
|
||||
log.Fatal(4, "Unsupported URI-Scheme %q (INTERNAL_TOKEN_URI = %q)", tempURI.Scheme, uri)
|
||||
log.Fatal("Unsupported URI-Scheme %q (INTERNAL_TOKEN_URI = %q)", tempURI.Scheme, uri)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@ -948,7 +955,7 @@ func loadOrGenerateInternalToken(sec *ini.Section) string {
|
||||
if len(token) == 0 {
|
||||
token, err = generate.NewInternalToken()
|
||||
if err != nil {
|
||||
log.Fatal(4, "Error generate internal token: %v", err)
|
||||
log.Fatal("Error generate internal token: %v", err)
|
||||
}
|
||||
|
||||
// Save secret
|
||||
@ -956,17 +963,17 @@ func loadOrGenerateInternalToken(sec *ini.Section) string {
|
||||
if com.IsFile(CustomConf) {
|
||||
// Keeps custom settings if there is already something.
|
||||
if err := cfgSave.Append(CustomConf); err != nil {
|
||||
log.Error(4, "Failed to load custom conf '%s': %v", CustomConf, err)
|
||||
log.Error("Failed to load custom conf '%s': %v", CustomConf, err)
|
||||
}
|
||||
}
|
||||
|
||||
cfgSave.Section("security").Key("INTERNAL_TOKEN").SetValue(token)
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(CustomConf), os.ModePerm); err != nil {
|
||||
log.Fatal(4, "Failed to create '%s': %v", CustomConf, err)
|
||||
log.Fatal("Failed to create '%s': %v", CustomConf, err)
|
||||
}
|
||||
if err := cfgSave.SaveTo(CustomConf); err != nil {
|
||||
log.Fatal(4, "Error saving generated INTERNAL_TOKEN to custom config: %v", err)
|
||||
log.Fatal("Error saving generated INTERNAL_TOKEN to custom config: %v", err)
|
||||
}
|
||||
}
|
||||
return token
|
||||
@ -976,6 +983,9 @@ func loadOrGenerateInternalToken(sec *ini.Section) string {
|
||||
func NewServices() {
|
||||
newService()
|
||||
newLogService()
|
||||
newMacaronLogService()
|
||||
newAccessLogService()
|
||||
newRouterLogService()
|
||||
NewXORMLogService(false)
|
||||
newCacheService()
|
||||
newSessionService()
|
||||
|
@ -43,7 +43,7 @@ func handleServerConn(keyID string, chans <-chan ssh.NewChannel) {
|
||||
|
||||
ch, reqs, err := newChan.Accept()
|
||||
if err != nil {
|
||||
log.Error(3, "Error accepting channel: %v", err)
|
||||
log.Error("Error accepting channel: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ func handleServerConn(keyID string, chans <-chan ssh.NewChannel) {
|
||||
args[0] = strings.TrimLeft(args[0], "\x04")
|
||||
_, _, err := com.ExecCmdBytes("env", args[0]+"="+args[1])
|
||||
if err != nil {
|
||||
log.Error(3, "env: %v", err)
|
||||
log.Error("env: %v", err)
|
||||
return
|
||||
}
|
||||
case "exec":
|
||||
@ -79,23 +79,23 @@ func handleServerConn(keyID string, chans <-chan ssh.NewChannel) {
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
log.Error(3, "SSH: StdoutPipe: %v", err)
|
||||
log.Error("SSH: StdoutPipe: %v", err)
|
||||
return
|
||||
}
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
log.Error(3, "SSH: StderrPipe: %v", err)
|
||||
log.Error("SSH: StderrPipe: %v", err)
|
||||
return
|
||||
}
|
||||
input, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
log.Error(3, "SSH: StdinPipe: %v", err)
|
||||
log.Error("SSH: StdinPipe: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// FIXME: check timeout
|
||||
if err = cmd.Start(); err != nil {
|
||||
log.Error(3, "SSH: Start: %v", err)
|
||||
log.Error("SSH: Start: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ func handleServerConn(keyID string, chans <-chan ssh.NewChannel) {
|
||||
io.Copy(ch.Stderr(), stderr)
|
||||
|
||||
if err = cmd.Wait(); err != nil {
|
||||
log.Error(3, "SSH: Wait: %v", err)
|
||||
log.Error("SSH: Wait: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -121,13 +121,13 @@ func handleServerConn(keyID string, chans <-chan ssh.NewChannel) {
|
||||
func listen(config *ssh.ServerConfig, host string, port int) {
|
||||
listener, err := net.Listen("tcp", host+":"+com.ToStr(port))
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to start SSH server: %v", err)
|
||||
log.Fatal("Failed to start SSH server: %v", err)
|
||||
}
|
||||
for {
|
||||
// Once a ServerConfig has been configured, connections can be accepted.
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
log.Error(3, "SSH: Error accepting incoming connection: %v", err)
|
||||
log.Error("SSH: Error accepting incoming connection: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -142,7 +142,7 @@ func listen(config *ssh.ServerConfig, host string, port int) {
|
||||
if err == io.EOF {
|
||||
log.Warn("SSH: Handshaking with %s was terminated: %v", conn.RemoteAddr(), err)
|
||||
} else {
|
||||
log.Error(3, "SSH: Error on handshaking with %s: %v", conn.RemoteAddr(), err)
|
||||
log.Error("SSH: Error on handshaking with %s: %v", conn.RemoteAddr(), err)
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -166,7 +166,7 @@ func Listen(host string, port int, ciphers []string, keyExchanges []string, macs
|
||||
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
|
||||
pkey, err := models.SearchPublicKeyByContent(strings.TrimSpace(string(ssh.MarshalAuthorizedKey(key))))
|
||||
if err != nil {
|
||||
log.Error(3, "SearchPublicKeyByContent: %v", err)
|
||||
log.Error("SearchPublicKeyByContent: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
return &ssh.Permissions{Extensions: map[string]string{"key-id": com.ToStr(pkey.ID)}}, nil
|
||||
@ -178,23 +178,23 @@ func Listen(host string, port int, ciphers []string, keyExchanges []string, macs
|
||||
filePath := filepath.Dir(keyPath)
|
||||
|
||||
if err := os.MkdirAll(filePath, os.ModePerm); err != nil {
|
||||
log.Error(4, "Failed to create dir %s: %v", filePath, err)
|
||||
log.Error("Failed to create dir %s: %v", filePath, err)
|
||||
}
|
||||
|
||||
err := GenKeyPair(keyPath)
|
||||
if err != nil {
|
||||
log.Fatal(4, "Failed to generate private key: %v", err)
|
||||
log.Fatal("Failed to generate private key: %v", err)
|
||||
}
|
||||
log.Trace("SSH: New private key is generateed: %s", keyPath)
|
||||
}
|
||||
|
||||
privateBytes, err := ioutil.ReadFile(keyPath)
|
||||
if err != nil {
|
||||
log.Fatal(4, "SSH: Failed to load private key")
|
||||
log.Fatal("SSH: Failed to load private key")
|
||||
}
|
||||
private, err := ssh.ParsePrivateKey(privateBytes)
|
||||
if err != nil {
|
||||
log.Fatal(4, "SSH: Failed to parse private key")
|
||||
log.Fatal("SSH: Failed to parse private key")
|
||||
}
|
||||
config.AddHostKey(private)
|
||||
|
||||
|
@ -351,7 +351,7 @@ func RenderCommitMessageLink(msg, urlPrefix, urlDefault string, metas map[string
|
||||
// shouldn't be any special HTML.
|
||||
fullMessage, err := markup.RenderCommitMessage([]byte(cleanMsg), urlPrefix, urlDefault, metas)
|
||||
if err != nil {
|
||||
log.Error(3, "RenderCommitMessage: %v", err)
|
||||
log.Error("RenderCommitMessage: %v", err)
|
||||
return ""
|
||||
}
|
||||
msgLines := strings.Split(strings.TrimSpace(string(fullMessage)), "\n")
|
||||
@ -366,7 +366,7 @@ func RenderCommitBody(msg, urlPrefix string, metas map[string]string) template.H
|
||||
cleanMsg := template.HTMLEscapeString(msg)
|
||||
fullMessage, err := markup.RenderCommitMessage([]byte(cleanMsg), urlPrefix, "", metas)
|
||||
if err != nil {
|
||||
log.Error(3, "RenderCommitMessage: %v", err)
|
||||
log.Error("RenderCommitMessage: %v", err)
|
||||
return ""
|
||||
}
|
||||
body := strings.Split(strings.TrimSpace(string(fullMessage)), "\n")
|
||||
@ -425,7 +425,7 @@ func ActionIcon(opType models.ActionType) string {
|
||||
func ActionContent2Commits(act Actioner) *models.PushCommits {
|
||||
push := models.NewPushCommits()
|
||||
if err := json.Unmarshal([]byte(act.GetContent()), push); err != nil {
|
||||
log.Error(4, "json.Unmarshal:\n%s\nERROR: %v", act.GetContent(), err)
|
||||
log.Error("json.Unmarshal:\n%s\nERROR: %v", act.GetContent(), err)
|
||||
}
|
||||
return push
|
||||
}
|
||||
|
@ -30,13 +30,13 @@ func URLJoin(base string, elems ...string) string {
|
||||
}
|
||||
baseURL, err := url.Parse(base)
|
||||
if err != nil {
|
||||
log.Error(4, "URLJoin: Invalid base URL %s", base)
|
||||
log.Error("URLJoin: Invalid base URL %s", base)
|
||||
return ""
|
||||
}
|
||||
joinedPath := path.Join(elems...)
|
||||
argURL, err := url.Parse(joinedPath)
|
||||
if err != nil {
|
||||
log.Error(4, "URLJoin: Invalid arg %s", joinedPath)
|
||||
log.Error("URLJoin: Invalid arg %s", joinedPath)
|
||||
return ""
|
||||
}
|
||||
joinedURL := baseURL.ResolveReference(argURL).String()
|
||||
|
@ -1742,6 +1742,16 @@ config.git_gc_timeout = GC Operation Timeout
|
||||
|
||||
config.log_config = Log Configuration
|
||||
config.log_mode = Log Mode
|
||||
config.macaron_log_mode = Macaron Log Mode
|
||||
config.own_named_logger = Named Logger
|
||||
config.routes_to_default_logger = Routes To Default Logger
|
||||
config.go_log = Uses Go Log (redirected to default)
|
||||
config.router_log_mode = Router Log Mode
|
||||
config.disabled_logger = Disabled
|
||||
config.access_log_mode = Access Log Mode
|
||||
config.access_log_template = Template
|
||||
config.xorm_log_mode = XORM Log Mode
|
||||
config.xorm_log_sql = Log SQL
|
||||
|
||||
monitor.cron = Cron Tasks
|
||||
monitor.name = Name
|
||||
|
@ -259,11 +259,13 @@ func Config(ctx *context.Context) {
|
||||
type logger struct {
|
||||
Mode, Config string
|
||||
}
|
||||
loggers := make([]*logger, len(setting.LogModes))
|
||||
for i := range setting.LogModes {
|
||||
loggers[i] = &logger{setting.LogModes[i], setting.LogConfigs[i]}
|
||||
}
|
||||
ctx.Data["Loggers"] = loggers
|
||||
ctx.Data["Loggers"] = setting.LogDescriptions
|
||||
ctx.Data["RedirectMacaronLog"] = setting.RedirectMacaronLog
|
||||
ctx.Data["EnableAccessLog"] = setting.EnableAccessLog
|
||||
ctx.Data["AccessLogTemplate"] = setting.AccessLogTemplate
|
||||
ctx.Data["DisableRouterLog"] = setting.DisableRouterLog
|
||||
ctx.Data["EnableXORMLog"] = setting.EnableXORMLog
|
||||
ctx.Data["LogSQL"] = setting.LogSQL
|
||||
|
||||
ctx.HTML(200, tplConfig)
|
||||
}
|
||||
|
@ -55,14 +55,14 @@ func ToCommit(repo *models.Repository, c *git.Commit) *api.PayloadCommit {
|
||||
if author, err := models.GetUserByEmail(c.Author.Email); err == nil {
|
||||
authorUsername = author.Name
|
||||
} else if !models.IsErrUserNotExist(err) {
|
||||
log.Error(4, "GetUserByEmail: %v", err)
|
||||
log.Error("GetUserByEmail: %v", err)
|
||||
}
|
||||
|
||||
committerUsername := ""
|
||||
if committer, err := models.GetUserByEmail(c.Committer.Email); err == nil {
|
||||
committerUsername = committer.Name
|
||||
} else if !models.IsErrUserNotExist(err) {
|
||||
log.Error(4, "GetUserByEmail: %v", err)
|
||||
log.Error("GetUserByEmail: %v", err)
|
||||
}
|
||||
|
||||
verif := models.ParseCommitWithSignature(c)
|
||||
|
@ -234,7 +234,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *models.User, opt api.CreateR
|
||||
} else {
|
||||
if repo != nil {
|
||||
if err = models.DeleteRepository(ctx.User, ctx.User.ID, repo.ID); err != nil {
|
||||
log.Error(4, "DeleteRepository: %v", err)
|
||||
log.Error("DeleteRepository: %v", err)
|
||||
}
|
||||
}
|
||||
ctx.Error(500, "CreateRepository", err)
|
||||
@ -417,7 +417,7 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
|
||||
err = util.URLSanitizedError(err, remoteAddr)
|
||||
if repo != nil {
|
||||
if errDelete := models.DeleteRepository(ctx.User, ctxUser.ID, repo.ID); errDelete != nil {
|
||||
log.Error(4, "DeleteRepository: %v", errDelete)
|
||||
log.Error("DeleteRepository: %v", errDelete)
|
||||
}
|
||||
}
|
||||
ctx.Error(500, "MigrateRepository", err)
|
||||
@ -597,7 +597,7 @@ func TopicSearch(ctx *context.Context) {
|
||||
Limit: 10,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error(2, "SearchTopics failed: %v", err)
|
||||
log.Error("SearchTopics failed: %v", err)
|
||||
ctx.JSON(500, map[string]interface{}{
|
||||
"message": "Search topics failed.",
|
||||
})
|
||||
|
@ -79,11 +79,11 @@ func GlobalInit() {
|
||||
if err := initDBEngine(); err == nil {
|
||||
log.Info("ORM engine initialization successful!")
|
||||
} else {
|
||||
log.Fatal(4, "ORM engine initialization failed: %v", err)
|
||||
log.Fatal("ORM engine initialization failed: %v", err)
|
||||
}
|
||||
|
||||
if err := models.InitOAuth2(); err != nil {
|
||||
log.Fatal(4, "Failed to initialize OAuth2 support: %v", err)
|
||||
log.Fatal("Failed to initialize OAuth2 support: %v", err)
|
||||
}
|
||||
|
||||
models.LoadRepoConfig()
|
||||
@ -92,7 +92,7 @@ func GlobalInit() {
|
||||
// Booting long running goroutines.
|
||||
cron.NewContext()
|
||||
if err := issue_indexer.InitIssueIndexer(false); err != nil {
|
||||
log.Fatal(4, "Failed to initialize issue indexer: %v", err)
|
||||
log.Fatal("Failed to initialize issue indexer: %v", err)
|
||||
}
|
||||
models.InitRepoIndexer()
|
||||
models.InitSyncMirrors()
|
||||
|
@ -236,7 +236,7 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
|
||||
if com.IsFile(setting.CustomConf) {
|
||||
// Keeps custom settings if there is already something.
|
||||
if err = cfg.Append(setting.CustomConf); err != nil {
|
||||
log.Error(4, "Failed to load custom conf '%s': %v", setting.CustomConf, err)
|
||||
log.Error("Failed to load custom conf '%s': %v", setting.CustomConf, err)
|
||||
}
|
||||
}
|
||||
cfg.Section("database").Key("DB_TYPE").SetValue(models.DbCfg.Type)
|
||||
|
@ -78,7 +78,7 @@ func MembersAction(ctx *context.Context) {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Error(4, "Action(%s): %v", ctx.Params(":action"), err)
|
||||
log.Error("Action(%s): %v", ctx.Params(":action"), err)
|
||||
ctx.JSON(200, map[string]interface{}{
|
||||
"ok": false,
|
||||
"err": err.Error(),
|
||||
|
@ -109,7 +109,7 @@ func TeamsAction(ctx *context.Context) {
|
||||
if models.IsErrLastOrgOwner(err) {
|
||||
ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
|
||||
} else {
|
||||
log.Error(3, "Action(%s): %v", ctx.Params(":action"), err)
|
||||
log.Error("Action(%s): %v", ctx.Params(":action"), err)
|
||||
ctx.JSON(200, map[string]interface{}{
|
||||
"ok": false,
|
||||
"err": err.Error(),
|
||||
@ -156,7 +156,7 @@ func TeamsRepoAction(ctx *context.Context) {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Error(3, "Action(%s): '%s' %v", ctx.Params(":action"), ctx.Org.Team.Name, err)
|
||||
log.Error("Action(%s): '%s' %v", ctx.Params(":action"), ctx.Org.Team.Name, err)
|
||||
ctx.ServerError("TeamsRepoAction", err)
|
||||
return
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user