2019-02-10 09:37:37 +08:00
// Copyright 2019 The Gitea Authors. All rights reserved.
2022-11-27 13:20:29 -05:00
// SPDX-License-Identifier: MIT
2019-02-10 09:37:37 +08:00
package setting
import (
2019-10-15 14:39:51 +01:00
"fmt"
2019-04-02 08:48:31 +01:00
golog "log"
2019-02-10 09:37:37 +08:00
"os"
"path"
"path/filepath"
"strings"
"code.gitea.io/gitea/modules/log"
2022-05-10 23:55:54 +02:00
"code.gitea.io/gitea/modules/util"
2019-02-10 09:37:37 +08:00
)
2023-05-22 06:35:11 +08:00
type LogGlobalConfig struct {
RootPath string
2020-07-06 01:07:07 +01:00
2023-05-22 06:35:11 +08:00
Mode string
2023-02-20 00:12:01 +08:00
Level log . Level
2023-05-22 06:35:11 +08:00
StacktraceLogLevel log . Level
BufferLen int
2023-02-20 00:12:01 +08:00
2023-05-22 06:35:11 +08:00
EnableSSHLog bool
2023-02-20 00:12:01 +08:00
AccessLogTemplate string
2023-03-10 23:54:32 +08:00
RequestIDHeaders [ ] string
2023-02-20 00:12:01 +08:00
}
2023-05-22 06:35:11 +08:00
var Log LogGlobalConfig
2020-07-06 01:07:07 +01:00
2023-05-22 06:35:11 +08:00
const accessLogTemplateDefault = ` {{ .Ctx .RemoteHost }} - {{ .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 }} " `
2020-07-06 01:07:07 +01:00
2023-05-22 06:35:11 +08:00
func loadLogGlobalFrom ( rootCfg ConfigProvider ) {
sec := rootCfg . Section ( "log" )
2020-07-06 01:07:07 +01:00
2023-05-22 06:35:11 +08:00
Log . Level = log . LevelFromString ( sec . Key ( "LEVEL" ) . MustString ( log . INFO . String ( ) ) )
Log . StacktraceLogLevel = log . LevelFromString ( sec . Key ( "STACKTRACE_LEVEL" ) . MustString ( log . NONE . String ( ) ) )
Log . BufferLen = sec . Key ( "BUFFER_LEN" ) . MustInt ( 10000 )
Log . Mode = sec . Key ( "MODE" ) . MustString ( "console" )
2019-02-10 09:37:37 +08:00
2023-05-22 06:35:11 +08:00
Log . RootPath = sec . Key ( "ROOT_PATH" ) . MustString ( path . Join ( AppWorkPath , "log" ) )
if ! filepath . IsAbs ( Log . RootPath ) {
Log . RootPath = filepath . Join ( AppWorkPath , Log . RootPath )
2019-04-02 08:48:31 +01:00
}
2023-05-22 06:35:11 +08:00
Log . RootPath = util . FilePathJoinAbs ( Log . RootPath )
2019-02-10 09:37:37 +08:00
2023-05-22 06:35:11 +08:00
Log . EnableSSHLog = sec . Key ( "ENABLE_SSH_LOG" ) . MustBool ( false )
2019-02-10 09:37:37 +08:00
2023-05-22 06:35:11 +08:00
Log . AccessLogTemplate = sec . Key ( "ACCESS_LOG_TEMPLATE" ) . MustString ( accessLogTemplateDefault )
Log . RequestIDHeaders = sec . Key ( "REQUEST_ID_HEADERS" ) . Strings ( "," )
2019-04-02 08:48:31 +01:00
}
2019-02-10 09:37:37 +08:00
2023-05-22 06:35:11 +08:00
func prepareLoggerConfig ( rootCfg ConfigProvider ) {
sec := rootCfg . Section ( "log" )
2019-04-02 08:48:31 +01:00
2023-05-22 06:35:11 +08:00
if ! sec . HasKey ( "logger.default.MODE" ) {
sec . Key ( "logger.default.MODE" ) . MustString ( "," )
}
2019-04-02 08:48:31 +01:00
2023-05-22 06:35:11 +08:00
deprecatedSetting ( rootCfg , "log" , "ACCESS" , "log" , "logger.access.MODE" , "1.21" )
deprecatedSetting ( rootCfg , "log" , "ENABLE_ACCESS_LOG" , "log" , "logger.access.MODE" , "1.21" )
if val := sec . Key ( "ACCESS" ) . String ( ) ; val != "" {
sec . Key ( "logger.access.MODE" ) . MustString ( val )
}
if sec . HasKey ( "ENABLE_ACCESS_LOG" ) && ! sec . Key ( "ENABLE_ACCESS_LOG" ) . MustBool ( ) {
sec . Key ( "logger.access.MODE" ) . SetValue ( "" )
}
2023-02-20 00:12:01 +08:00
2023-05-22 06:35:11 +08:00
deprecatedSetting ( rootCfg , "log" , "ROUTER" , "log" , "logger.router.MODE" , "1.21" )
deprecatedSetting ( rootCfg , "log" , "DISABLE_ROUTER_LOG" , "log" , "logger.router.MODE" , "1.21" )
if val := sec . Key ( "ROUTER" ) . String ( ) ; val != "" {
sec . Key ( "logger.router.MODE" ) . MustString ( val )
}
if ! sec . HasKey ( "logger.router.MODE" ) {
sec . Key ( "logger.router.MODE" ) . MustString ( "," ) // use default logger
}
if sec . HasKey ( "DISABLE_ROUTER_LOG" ) && sec . Key ( "DISABLE_ROUTER_LOG" ) . MustBool ( ) {
sec . Key ( "logger.router.MODE" ) . SetValue ( "" )
}
2023-02-20 00:12:01 +08:00
2023-05-22 06:35:11 +08:00
deprecatedSetting ( rootCfg , "log" , "XORM" , "log" , "logger.xorm.MODE" , "1.21" )
deprecatedSetting ( rootCfg , "log" , "ENABLE_XORM_LOG" , "log" , "logger.xorm.MODE" , "1.21" )
if val := sec . Key ( "XORM" ) . String ( ) ; val != "" {
sec . Key ( "logger.xorm.MODE" ) . MustString ( val )
}
if ! sec . HasKey ( "logger.xorm.MODE" ) {
sec . Key ( "logger.xorm.MODE" ) . MustString ( "," ) // use default logger
}
if sec . HasKey ( "ENABLE_XORM_LOG" ) && ! sec . Key ( "ENABLE_XORM_LOG" ) . MustBool ( ) {
sec . Key ( "logger.xorm.MODE" ) . SetValue ( "" )
}
}
2023-02-20 00:12:01 +08:00
2023-05-22 06:35:11 +08:00
func LogPrepareFilenameForWriter ( fileName , defaultFileName string ) string {
if fileName == "" {
fileName = defaultFileName
}
if ! filepath . IsAbs ( fileName ) {
fileName = filepath . Join ( Log . RootPath , fileName )
} else {
fileName = filepath . Clean ( fileName )
}
if err := os . MkdirAll ( filepath . Dir ( fileName ) , os . ModePerm ) ; err != nil {
panic ( fmt . Sprintf ( "unable to create directory for log %q: %v" , fileName , err . Error ( ) ) )
}
return fileName
2023-02-20 00:12:01 +08:00
}
2023-05-22 06:35:11 +08:00
func loadLogModeByName ( rootCfg ConfigProvider , loggerName , modeName string ) ( writerName , writerType string , writerMode log . WriterMode , err error ) {
sec := rootCfg . Section ( "log." + modeName )
writerMode = log . WriterMode { }
writerType = ConfigSectionKeyString ( sec , "MODE" )
if writerType == "" {
writerType = modeName
2019-02-10 09:37:37 +08:00
}
2023-05-22 06:35:11 +08:00
writerName = modeName
defaultFlags := "stdflags"
defaultFilaName := "gitea.log"
if loggerName == "access" {
// "access" logger is special, by default it doesn't have output flags, so it also needs a new writer name to avoid conflicting with other writers.
// so "access" logger's writer name is usually "file.access" or "console.access"
writerName += ".access"
defaultFlags = "none"
defaultFilaName = "access.log"
2019-02-10 09:37:37 +08:00
}
2023-05-22 06:35:11 +08:00
writerMode . Level = log . LevelFromString ( ConfigInheritedKeyString ( sec , "LEVEL" , Log . Level . String ( ) ) )
writerMode . StacktraceLevel = log . LevelFromString ( ConfigInheritedKeyString ( sec , "STACKTRACE_LEVEL" , Log . StacktraceLogLevel . String ( ) ) )
writerMode . Prefix = ConfigInheritedKeyString ( sec , "PREFIX" )
writerMode . Expression = ConfigInheritedKeyString ( sec , "EXPRESSION" )
writerMode . Flags = log . FlagsFromString ( ConfigInheritedKeyString ( sec , "FLAGS" , defaultFlags ) )
switch writerType {
2019-04-02 08:48:31 +01:00
case "console" :
2023-05-22 06:35:11 +08:00
useStderr := ConfigInheritedKey ( sec , "STDERR" ) . MustBool ( false )
defaultCanColor := log . CanColorStdout
2019-04-02 08:48:31 +01:00
if useStderr {
2023-05-22 06:35:11 +08:00
defaultCanColor = log . CanColorStderr
2019-02-10 09:37:37 +08:00
}
2023-05-22 06:35:11 +08:00
writerOption := log . WriterConsoleOption { Stderr : useStderr }
writerMode . Colorize = ConfigInheritedKey ( sec , "COLORIZE" ) . MustBool ( defaultCanColor )
writerMode . WriterOption = writerOption
2019-04-02 08:48:31 +01:00
case "file" :
2023-05-22 06:35:11 +08:00
fileName := LogPrepareFilenameForWriter ( ConfigInheritedKey ( sec , "FILE_NAME" ) . String ( ) , defaultFilaName )
writerOption := log . WriterFileOption { }
writerOption . FileName = fileName + filenameSuffix // FIXME: the suffix doesn't seem right, see its related comments
writerOption . LogRotate = ConfigInheritedKey ( sec , "LOG_ROTATE" ) . MustBool ( true )
writerOption . MaxSize = 1 << uint ( ConfigInheritedKey ( sec , "MAX_SIZE_SHIFT" ) . MustInt ( 28 ) )
writerOption . DailyRotate = ConfigInheritedKey ( sec , "DAILY_ROTATE" ) . MustBool ( true )
writerOption . MaxDays = ConfigInheritedKey ( sec , "MAX_DAYS" ) . MustInt ( 7 )
writerOption . Compress = ConfigInheritedKey ( sec , "COMPRESS" ) . MustBool ( true )
writerOption . CompressionLevel = ConfigInheritedKey ( sec , "COMPRESSION_LEVEL" ) . MustInt ( - 1 )
writerMode . WriterOption = writerOption
2019-04-02 08:48:31 +01:00
case "conn" :
2023-05-22 06:35:11 +08:00
writerOption := log . WriterConnOption { }
writerOption . ReconnectOnMsg = ConfigInheritedKey ( sec , "RECONNECT_ON_MSG" ) . MustBool ( )
writerOption . Reconnect = ConfigInheritedKey ( sec , "RECONNECT" ) . MustBool ( )
writerOption . Protocol = ConfigInheritedKey ( sec , "PROTOCOL" ) . In ( "tcp" , [ ] string { "tcp" , "unix" , "udp" } )
writerOption . Addr = ConfigInheritedKey ( sec , "ADDR" ) . MustString ( ":7020" )
writerMode . WriterOption = writerOption
default :
if ! log . HasEventWriter ( writerType ) {
2023-08-02 02:28:23 +08:00
return "" , "" , writerMode , fmt . Errorf ( "invalid log writer type (mode): %s, maybe it needs something like 'MODE=file' in [log.%s] section" , writerType , modeName )
2019-11-25 13:38:57 +00:00
}
2019-04-02 08:48:31 +01:00
}
2019-02-10 09:37:37 +08:00
2023-05-22 06:35:11 +08:00
return writerName , writerType , writerMode , nil
2019-02-10 09:37:37 +08:00
}
2023-05-22 06:35:11 +08:00
var filenameSuffix = ""
2019-04-02 08:48:31 +01:00
2023-05-22 06:35:11 +08:00
// RestartLogsWithPIDSuffix restarts the logs with a PID suffix on files
// FIXME: it seems not right, it breaks log rotating or log collectors
func RestartLogsWithPIDSuffix ( ) {
filenameSuffix = fmt . Sprintf ( ".%d" , os . Getpid ( ) )
initAllLoggers ( ) // when forking, before restarting, rename logger file and re-init all loggers
}
2019-02-10 09:37:37 +08:00
2023-05-22 06:35:11 +08:00
func InitLoggersForTest ( ) {
initAllLoggers ( )
}
2019-02-10 09:37:37 +08:00
2023-05-22 06:35:11 +08:00
// initAllLoggers creates all the log services
func initAllLoggers ( ) {
initManagedLoggers ( log . GetManager ( ) , CfgProvider )
2019-04-02 08:48:31 +01:00
2023-05-22 06:35:11 +08:00
golog . SetFlags ( 0 )
golog . SetPrefix ( "" )
golog . SetOutput ( log . LoggerToWriter ( log . GetLogger ( log . DEFAULT ) . Info ) )
}
2019-04-02 08:48:31 +01:00
2023-05-22 06:35:11 +08:00
func initManagedLoggers ( manager * log . LoggerManager , cfg ConfigProvider ) {
loadLogGlobalFrom ( cfg )
prepareLoggerConfig ( cfg )
2019-04-02 08:48:31 +01:00
2023-05-22 06:35:11 +08:00
initLoggerByName ( manager , cfg , log . DEFAULT ) // default
initLoggerByName ( manager , cfg , "access" )
initLoggerByName ( manager , cfg , "router" )
initLoggerByName ( manager , cfg , "xorm" )
2019-04-02 08:48:31 +01:00
}
2023-05-22 06:35:11 +08:00
func initLoggerByName ( manager * log . LoggerManager , rootCfg ConfigProvider , loggerName string ) {
2023-02-20 00:12:01 +08:00
sec := rootCfg . Section ( "log" )
2023-05-22 06:35:11 +08:00
keyPrefix := "logger." + loggerName
2019-04-02 08:48:31 +01:00
2023-05-22 06:35:11 +08:00
disabled := sec . HasKey ( keyPrefix + ".MODE" ) && sec . Key ( keyPrefix + ".MODE" ) . String ( ) == ""
if disabled {
return
2019-04-02 08:48:31 +01:00
}
2023-05-22 06:35:11 +08:00
modeVal := sec . Key ( keyPrefix + ".MODE" ) . String ( )
if modeVal == "," {
modeVal = Log . Mode
}
2019-04-02 08:48:31 +01:00
2023-05-22 06:35:11 +08:00
var eventWriters [ ] log . EventWriter
modes := strings . Split ( modeVal , "," )
for _ , modeName := range modes {
modeName = strings . TrimSpace ( modeName )
if modeName == "" {
2019-04-02 08:48:31 +01:00
continue
2019-02-10 09:37:37 +08:00
}
2023-05-22 06:35:11 +08:00
writerName , writerType , writerMode , err := loadLogModeByName ( rootCfg , loggerName , modeName )
2019-04-02 08:48:31 +01:00
if err != nil {
2023-05-22 06:35:11 +08:00
log . FallbackErrorf ( "Failed to load writer mode %q for logger %s: %v" , modeName , loggerName , err )
continue
}
if writerMode . BufferLen == 0 {
writerMode . BufferLen = Log . BufferLen
}
eventWriter := manager . GetSharedWriter ( writerName )
if eventWriter == nil {
eventWriter , err = manager . NewSharedWriter ( writerName , writerType , writerMode )
2020-05-16 03:38:52 +01:00
if err != nil {
2023-05-22 06:35:11 +08:00
log . FallbackErrorf ( "Failed to create event writer for logger %s: %v" , loggerName , err )
continue
2020-05-16 03:38:52 +01:00
}
2019-02-10 09:37:37 +08:00
}
2023-05-22 06:35:11 +08:00
eventWriters = append ( eventWriters , eventWriter )
2023-01-01 22:00:33 +08:00
}
2023-06-28 14:02:06 +08:00
manager . GetLogger ( loggerName ) . ReplaceAllWriters ( eventWriters ... )
2019-04-02 08:48:31 +01:00
}
2023-05-22 06:35:11 +08:00
func InitSQLLoggersForCli ( level log . Level ) {
log . SetConsoleLogger ( "xorm" , "console" , level )
2023-02-20 00:12:01 +08:00
}
2023-05-22 06:35:11 +08:00
func IsAccessLogEnabled ( ) bool {
return log . IsLoggerEnabled ( "access" )
2019-04-07 01:25:14 +01:00
}
2023-05-22 06:35:11 +08:00
func IsRouteLogEnabled ( ) bool {
return log . IsLoggerEnabled ( "router" )
2019-02-10 09:37:37 +08:00
}