* Allow Macaron to be set to log through gitea.log Fix #4291tags/v1.21.12.1
| @@ -497,6 +497,7 @@ MODE = console | |||||
| BUFFER_LEN = 10000 | BUFFER_LEN = 10000 | ||||
| ; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace" | ; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace" | ||||
| LEVEL = Trace | LEVEL = Trace | ||||
| REDIRECT_MACARON_LOG = false | |||||
| ; For "console" mode only | ; For "console" mode only | ||||
| [log.console] | [log.console] | ||||
| @@ -279,6 +279,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. | |||||
| - `ROOT_PATH`: **\<empty\>**: Root path for log files. | - `ROOT_PATH`: **\<empty\>**: Root path for log files. | ||||
| - `MODE`: **console**: Logging mode. For multiple modes, use a comma to separate values. | - `MODE`: **console**: Logging mode. For multiple modes, use a comma to separate values. | ||||
| - `LEVEL`: **Trace**: General log level. \[Trace, Debug, Info, Warn, Error, Critical\] | - `LEVEL`: **Trace**: General log level. \[Trace, Debug, Info, Warn, Error, Critical\] | ||||
| - `REDIRECT_MACARON_LOG`: **false**: Redirects the Macaron log to the Gitea logger. | |||||
| ## Cron (`cron`) | ## Cron (`cron`) | ||||
| @@ -154,6 +154,48 @@ type LoggerInterface interface { | |||||
| type loggerType func() LoggerInterface | type loggerType func() LoggerInterface | ||||
| // LoggerAsWriter is a io.Writer shim around the gitea log | |||||
| type LoggerAsWriter struct { | |||||
| level int | |||||
| } | |||||
| // 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 | |||||
| } | |||||
| 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)) | |||||
| 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) | |||||
| } | |||||
| } | |||||
| var adapters = make(map[string]loggerType) | var adapters = make(map[string]loggerType) | ||||
| // Register registers given logger provider to adapters. | // Register registers given logger provider to adapters. | ||||
| @@ -393,10 +393,11 @@ var ( | |||||
| LibravatarService *libravatar.Libravatar | LibravatarService *libravatar.Libravatar | ||||
| // Log settings | // Log settings | ||||
| LogLevel string | |||||
| LogRootPath string | |||||
| LogModes []string | |||||
| LogConfigs []string | |||||
| LogLevel string | |||||
| LogRootPath string | |||||
| LogModes []string | |||||
| LogConfigs []string | |||||
| RedirectMacaronLog bool | |||||
| // Attachment settings | // Attachment settings | ||||
| AttachmentPath string | AttachmentPath string | ||||
| @@ -767,6 +768,7 @@ func NewContext() { | |||||
| LogLevel = getLogLevel("log", "LEVEL", "Info") | LogLevel = getLogLevel("log", "LEVEL", "Info") | ||||
| LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(AppWorkPath, "log")) | LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(AppWorkPath, "log")) | ||||
| forcePathSeparator(LogRootPath) | forcePathSeparator(LogRootPath) | ||||
| RedirectMacaronLog = Cfg.Section("log").Key("REDIRECT_MACARON_LOG").MustBool(false) | |||||
| sec := Cfg.Section("server") | sec := Cfg.Section("server") | ||||
| AppName = Cfg.Section("").Key("APP_NAME").MustString("Gitea: Git with a cup of tea") | AppName = Cfg.Section("").Key("APP_NAME").MustString("Gitea: Git with a cup of tea") | ||||
| @@ -6,6 +6,7 @@ package routes | |||||
| import ( | import ( | ||||
| "encoding/gob" | "encoding/gob" | ||||
| "fmt" | |||||
| "net/http" | "net/http" | ||||
| "os" | "os" | ||||
| "path" | "path" | ||||
| @@ -45,12 +46,34 @@ import ( | |||||
| macaron "gopkg.in/macaron.v1" | macaron "gopkg.in/macaron.v1" | ||||
| ) | ) | ||||
| func giteaLogger(l *log.LoggerAsWriter) macaron.Handler { | |||||
| return func(ctx *macaron.Context) { | |||||
| start := time.Now() | |||||
| l.Log(fmt.Sprintf("[Macaron] Started %s %s for %s", ctx.Req.Method, ctx.Req.RequestURI, ctx.RemoteAddr())) | |||||
| ctx.Next() | |||||
| rw := ctx.Resp.(macaron.ResponseWriter) | |||||
| l.Log(fmt.Sprintf("[Macaron] Completed %s %s %v %s in %v", ctx.Req.Method, ctx.Req.RequestURI, rw.Status(), http.StatusText(rw.Status()), time.Since(start))) | |||||
| } | |||||
| } | |||||
| // NewMacaron initializes Macaron instance. | // NewMacaron initializes Macaron instance. | ||||
| func NewMacaron() *macaron.Macaron { | func NewMacaron() *macaron.Macaron { | ||||
| gob.Register(&u2f.Challenge{}) | gob.Register(&u2f.Challenge{}) | ||||
| m := macaron.New() | |||||
| if !setting.DisableRouterLog { | |||||
| m.Use(macaron.Logger()) | |||||
| var m *macaron.Macaron | |||||
| if setting.RedirectMacaronLog { | |||||
| loggerAsWriter := log.NewLoggerAsWriter("INFO") | |||||
| m = macaron.NewWithLogger(loggerAsWriter) | |||||
| if !setting.DisableRouterLog { | |||||
| m.Use(giteaLogger(loggerAsWriter)) | |||||
| } | |||||
| } else { | |||||
| m = macaron.New() | |||||
| if !setting.DisableRouterLog { | |||||
| m.Use(macaron.Logger()) | |||||
| } | |||||
| } | } | ||||
| m.Use(macaron.Recovery()) | m.Use(macaron.Recovery()) | ||||
| if setting.EnableGzip { | if setting.EnableGzip { | ||||