Skip to content

Commit 5bf8d54

Browse files
authored
Refactor Router Logger (#17308)
Make router logger more friendly, show the related function name/file/line. [BREAKING] This PR substantially changes the logging format of the router logger. If you use this logging for monitoring e.g. fail2ban you will need to update this to match the new format.
1 parent bbd3078 commit 5bf8d54

23 files changed

+910
-265
lines changed

cmd/web.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func runWeb(ctx *cli.Context) error {
8888
}
8989
defer func() {
9090
if panicked := recover(); panicked != nil {
91-
log.Fatal("PANIC: %v\n%s", panicked, string(log.Stack(2)))
91+
log.Fatal("PANIC: %v\n%s", panicked, log.Stack(2))
9292
}
9393
}()
9494

custom/conf/app.example.ini

+13-4
Original file line numberDiff line numberDiff line change
@@ -455,26 +455,35 @@ APP_ID = ; e.g. http://localhost:3000/
455455
;; Use comma to separate multiple modes, e.g. "console, file"
456456
MODE = console
457457
;;
458-
;; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"
458+
;; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical" or "None", default is "Info"
459459
LEVEL = Info
460460
;;
461461
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
462462
;; Router Logger
463463
;;
464464
;; Switch off the router log
465-
;DISABLE_ROUTER_LOG= ; false
465+
;DISABLE_ROUTER_LOG=false
466466
;;
467467
;; Set the log "modes" for the router log (if file is set the log file will default to router.log)
468468
ROUTER = console
469469
;;
470-
;; The level at which the router logs
471-
;ROUTER_LOG_LEVEL = Info
470+
;; The router will log different things at different levels.
472471
;;
472+
;; * started messages will be logged at TRACE level
473+
;; * polling/completed routers will be logged at INFO
474+
;; * slow routers will be logged at WARN
475+
;; * failed routers will be logged at WARN
476+
;;
477+
;; The routing level will default to that of the system but individual router level can be set in
478+
;; [log.<mode>.router] LEVEL
479+
;;
480+
473481
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
474482
;;
475483
;; Access Logger (Creates log in NCSA common log format)
476484
;;
477485
;ENABLE_ACCESS_LOG = false
486+
;;
478487
;; Set the log "modes" for the access log (if file is set the log file will default to access.log)
479488
;ACCESS = file
480489
;;

docs/content/doc/advanced/config-cheat-sheet.en-us.md

+8-5
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,6 @@ The following configuration set `Content-Type: application/vnd.android.package-a
291291
- `MINIMUM_KEY_SIZE_CHECK`: **true**: Indicate whether to check minimum key size with corresponding type.
292292

293293
- `OFFLINE_MODE`: **false**: Disables use of CDN for static files and Gravatar for profile pictures.
294-
- `DISABLE_ROUTER_LOG`: **false**: Mute printing of the router log.
295294
- `CERT_FILE`: **https/cert.pem**: Cert file path used for HTTPS. When chaining, the server certificate must come first, then intermediate CA certificates (if any). From 1.11 paths are relative to `CUSTOM_PATH`.
296295
- `KEY_FILE`: **https/key.pem**: Key file path used for HTTPS. From 1.11 paths are relative to `CUSTOM_PATH`.
297296
- `STATIC_ROOT_PATH`: **./**: Upper level of template and static files path.
@@ -752,11 +751,16 @@ Default templates for project boards:
752751
- `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`.
753752
- `LEVEL`: **Info**: General log level. \[Trace, Debug, Info, Warn, Error, Critical, Fatal, None\]
754753
- `STACKTRACE_LEVEL`: **None**: Default log level at which to log create stack traces. \[Trace, Debug, Info, Warn, Error, Critical, Fatal, None\]
755-
- `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.)
754+
- `ENABLE_SSH_LOG`: **false**: save ssh log to log file
755+
- `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.
756+
757+
### Router Log (`log`)
758+
- `DISABLE_ROUTER_LOG`: **false**: Mute printing of the router log.
756759
- `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.)
757-
NB: You must have `DISABLE_ROUTER_LOG` set to `false` for this option to take effect. Configure each mode in per mode log subsections `\[log.modename.router\]`.
760+
NB: You must have `DISABLE_ROUTER_LOG` set to `false` for this option to take effect. Configure each mode in per mode log subsections `\[log.modename.router\]`.
761+
762+
### Access Log (`log`)
758763
- `ENABLE_ACCESS_LOG`: **false**: Creates an access.log in NCSA common log format, or as per the following template
759-
- `ENABLE_SSH_LOG`: **false**: save ssh log to log file
760764
- `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.)
761765
- `ACCESS_LOG_TEMPLATE`: **`{{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}"`**: Sets the template used to create the access log.
762766
- The following variables are available:
@@ -765,7 +769,6 @@ NB: You must have `DISABLE_ROUTER_LOG` set to `false` for this option to take ef
765769
- `Start`: the start time of the request.
766770
- `ResponseWriter`: the responseWriter from the request.
767771
- 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.
768-
- `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.
769772

770773
### Log subsections (`log.name`, `log.name.*`)
771774

docs/content/doc/advanced/logging-documentation.en-us.md

+13-6
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,23 @@ multiple subloggers that will log to files.
6868

6969
### The "Router" logger
7070

71-
You can disable Router log by setting `DISABLE_ROUTER_LOG`.
71+
The Router logger has been substantially changed in v1.17. If you are using the router logger for fail2ban or other monitoring
72+
you will need to update this configuration.
73+
74+
You can disable Router log by setting `DISABLE_ROUTER_LOG` or by setting all of its sublogger configurations to `none`.
7275

7376
You can configure the outputs of this
7477
router log by setting the `ROUTER` value in the `[log]` section of the
75-
configuration. `ROUTER` will default to `console` if unset. The Gitea
76-
Router logs at the `Info` level by default, but this can be
77-
changed if desired by setting the `ROUTER_LOG_LEVEL` value.
78+
configuration. `ROUTER` will default to `console` if unset and will default to same level as main logger.
79+
80+
The Router logger logs the following:
81+
82+
- `started` messages will be logged at TRACE level
83+
- `polling`/`completed` routers will be logged at INFO
84+
- `slow` routers will be logged at WARN
85+
- `failed` routers will be logged at WARN
7886

79-
Please note, setting the `LEVEL` of this logger to a level above
80-
`ROUTER_LOG_LEVEL` will result in no router logs.
87+
The logging level for the router will default to that of the main configuration. Set `[log.<mode>.router]` `LEVEL` to change this.
8188

8289
Each output sublogger for this logger is configured in
8390
`[log.sublogger.router]` sections. There are certain default values

modules/log/colors_router.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package log
66

77
import (
8+
"fmt"
89
"time"
910
)
1011

@@ -72,12 +73,16 @@ var (
7273
wayTooLong = ColorBytes(BgMagenta)
7374
)
7475

75-
// ColoredTime adds colors for time on log
76+
// ColoredTime converts the provided time to a ColoredValue for logging. The duration is always formatted in milliseconds.
7677
func ColoredTime(duration time.Duration) *ColoredValue {
78+
// the output of duration in Millisecond is more readable:
79+
// * before: "100.1ms" "100.1μs" "100.1s"
80+
// * better: "100.1ms" "0.1ms" "100100.0ms", readers can compare the values at first glance.
81+
str := fmt.Sprintf("%.1fms", float64(duration.Microseconds())/1000)
7782
for i, k := range durations {
7883
if duration < k {
79-
return NewColoredValueBytes(duration, &durationColors[i])
84+
return NewColoredValueBytes(str, &durationColors[i])
8085
}
8186
}
82-
return NewColoredValueBytes(duration, &wayTooLong)
87+
return NewColoredValueBytes(str, &wayTooLong)
8388
}

modules/log/log.go

+4
Original file line numberDiff line numberDiff line change
@@ -288,4 +288,8 @@ func (l *LoggerAsWriter) Log(msg string) {
288288
func init() {
289289
_, filename, _, _ := runtime.Caller(0)
290290
prefix = strings.TrimSuffix(filename, "modules/log/log.go")
291+
if prefix == filename {
292+
// in case the source code file is moved, we can not trim the suffix, the code above should also be updated.
293+
panic("unable to detect correct package prefix, please update file: " + filename)
294+
}
291295
}

modules/public/public.go

+43-46
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@ type Options struct {
2323
CorsHandler func(http.Handler) http.Handler
2424
}
2525

26-
// AssetsHandler implements the static handler for serving custom or original assets.
27-
func AssetsHandler(opts *Options) func(next http.Handler) http.Handler {
26+
// AssetsURLPathPrefix is the path prefix for static asset files
27+
const AssetsURLPathPrefix = "/assets/"
28+
29+
// AssetsHandlerFunc implements the static handler for serving custom or original assets.
30+
func AssetsHandlerFunc(opts *Options) http.HandlerFunc {
2831
var custPath = filepath.Join(setting.CustomPath, "public")
2932
if !filepath.IsAbs(custPath) {
3033
custPath = filepath.Join(setting.AppWorkPath, custPath)
@@ -36,52 +39,46 @@ func AssetsHandler(opts *Options) func(next http.Handler) http.Handler {
3639
opts.Prefix += "/"
3740
}
3841

39-
return func(next http.Handler) http.Handler {
40-
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
41-
if !strings.HasPrefix(req.URL.Path, opts.Prefix) {
42-
next.ServeHTTP(resp, req)
43-
return
44-
}
45-
if req.Method != "GET" && req.Method != "HEAD" {
46-
resp.WriteHeader(http.StatusNotFound)
47-
return
48-
}
49-
50-
file := req.URL.Path
51-
file = file[len(opts.Prefix):]
52-
if len(file) == 0 {
53-
resp.WriteHeader(http.StatusNotFound)
54-
return
55-
}
56-
if strings.Contains(file, "\\") {
57-
resp.WriteHeader(http.StatusBadRequest)
58-
return
59-
}
60-
file = "/" + file
61-
62-
var written bool
63-
if opts.CorsHandler != nil {
64-
written = true
65-
opts.CorsHandler(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
66-
written = false
67-
})).ServeHTTP(resp, req)
68-
}
69-
if written {
70-
return
71-
}
72-
73-
// custom files
74-
if opts.handle(resp, req, http.Dir(custPath), file) {
75-
return
76-
}
77-
78-
// internal files
79-
if opts.handle(resp, req, fileSystem(opts.Directory), file) {
80-
return
81-
}
42+
return func(resp http.ResponseWriter, req *http.Request) {
43+
if req.Method != "GET" && req.Method != "HEAD" {
44+
resp.WriteHeader(http.StatusNotFound)
45+
return
46+
}
8247

48+
file := req.URL.Path
49+
file = file[len(opts.Prefix):]
50+
if len(file) == 0 {
8351
resp.WriteHeader(http.StatusNotFound)
84-
})
52+
return
53+
}
54+
if strings.Contains(file, "\\") {
55+
resp.WriteHeader(http.StatusBadRequest)
56+
return
57+
}
58+
file = "/" + file
59+
60+
var written bool
61+
if opts.CorsHandler != nil {
62+
written = true
63+
opts.CorsHandler(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
64+
written = false
65+
})).ServeHTTP(resp, req)
66+
}
67+
if written {
68+
return
69+
}
70+
71+
// custom files
72+
if opts.handle(resp, req, http.Dir(custPath), file) {
73+
return
74+
}
75+
76+
// internal files
77+
if opts.handle(resp, req, fileSystem(opts.Directory), file) {
78+
return
79+
}
80+
81+
resp.WriteHeader(http.StatusNotFound)
8582
}
8683
}
8784

modules/setting/log.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ func getStacktraceLogLevel(section *ini.Section, key, defaultValue string) strin
126126

127127
func generateLogConfig(sec *ini.Section, name string, defaults defaultLogOptions) (mode, jsonConfig, levelName string) {
128128
level := getLogLevel(sec, "LEVEL", LogLevel)
129+
levelName = level.String()
129130
stacktraceLevelName := getStacktraceLogLevel(sec, "STACKTRACE_LEVEL", StacktraceLogLevel)
130131
stacktraceLevel := log.FromString(stacktraceLevelName)
131132
mode = name
@@ -254,8 +255,10 @@ func generateNamedLogger(key string, options defaultLogOptions) *LogDescription
254255
func newAccessLogService() {
255256
EnableAccessLog = Cfg.Section("log").Key("ENABLE_ACCESS_LOG").MustBool(false)
256257
AccessLogTemplate = Cfg.Section("log").Key("ACCESS_LOG_TEMPLATE").MustString(
257-
`{{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}"`)
258-
Cfg.Section("log").Key("ACCESS").MustString("file")
258+
`{{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}"`,
259+
)
260+
// the `MustString` updates the default value, and `log.ACCESS` is used by `generateNamedLogger("access")` later
261+
_ = Cfg.Section("log").Key("ACCESS").MustString("file")
259262
if EnableAccessLog {
260263
options := newDefaultLogOptions()
261264
options.filename = filepath.Join(LogRootPath, "access.log")

modules/setting/setting.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -333,13 +333,14 @@ var (
333333
LogLevel log.Level
334334
StacktraceLogLevel string
335335
LogRootPath string
336-
DisableRouterLog bool
337-
RouterLogLevel log.Level
338-
EnableAccessLog bool
339336
EnableSSHLog bool
340-
AccessLogTemplate string
341337
EnableXORMLog bool
342338

339+
DisableRouterLog bool
340+
341+
EnableAccessLog bool
342+
AccessLogTemplate string
343+
343344
// Time settings
344345
TimeFormat string
345346
// UILocation is the location on the UI, so that we can display the time on UI.
@@ -601,7 +602,6 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
601602
StacktraceLogLevel = getStacktraceLogLevel(Cfg.Section("log"), "STACKTRACE_LEVEL", "None")
602603
LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(AppWorkPath, "log"))
603604
forcePathSeparator(LogRootPath)
604-
RouterLogLevel = log.FromString(Cfg.Section("log").Key("ROUTER_LOG_LEVEL").MustString("Info"))
605605

606606
sec := Cfg.Section("server")
607607
AppName = Cfg.Section("").Key("APP_NAME").MustString("Gitea: Git with a cup of tea")

0 commit comments

Comments
 (0)