Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package setting
  4. import (
  5. "fmt"
  6. golog "log"
  7. "os"
  8. "path"
  9. "path/filepath"
  10. "strings"
  11. "code.gitea.io/gitea/modules/log"
  12. "code.gitea.io/gitea/modules/util"
  13. )
  14. type LogGlobalConfig struct {
  15. RootPath string
  16. Mode string
  17. Level log.Level
  18. StacktraceLogLevel log.Level
  19. BufferLen int
  20. EnableSSHLog bool
  21. AccessLogTemplate string
  22. RequestIDHeaders []string
  23. }
  24. var Log LogGlobalConfig
  25. 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}}"`
  26. func loadLogGlobalFrom(rootCfg ConfigProvider) {
  27. sec := rootCfg.Section("log")
  28. Log.Level = log.LevelFromString(sec.Key("LEVEL").MustString(log.INFO.String()))
  29. Log.StacktraceLogLevel = log.LevelFromString(sec.Key("STACKTRACE_LEVEL").MustString(log.NONE.String()))
  30. Log.BufferLen = sec.Key("BUFFER_LEN").MustInt(10000)
  31. Log.Mode = sec.Key("MODE").MustString("console")
  32. Log.RootPath = sec.Key("ROOT_PATH").MustString(path.Join(AppWorkPath, "log"))
  33. if !filepath.IsAbs(Log.RootPath) {
  34. Log.RootPath = filepath.Join(AppWorkPath, Log.RootPath)
  35. }
  36. Log.RootPath = util.FilePathJoinAbs(Log.RootPath)
  37. Log.EnableSSHLog = sec.Key("ENABLE_SSH_LOG").MustBool(false)
  38. Log.AccessLogTemplate = sec.Key("ACCESS_LOG_TEMPLATE").MustString(accessLogTemplateDefault)
  39. Log.RequestIDHeaders = sec.Key("REQUEST_ID_HEADERS").Strings(",")
  40. }
  41. func prepareLoggerConfig(rootCfg ConfigProvider) {
  42. sec := rootCfg.Section("log")
  43. if !sec.HasKey("logger.default.MODE") {
  44. sec.Key("logger.default.MODE").MustString(",")
  45. }
  46. deprecatedSetting(rootCfg, "log", "ACCESS", "log", "logger.access.MODE", "1.21")
  47. deprecatedSetting(rootCfg, "log", "ENABLE_ACCESS_LOG", "log", "logger.access.MODE", "1.21")
  48. if val := sec.Key("ACCESS").String(); val != "" {
  49. sec.Key("logger.access.MODE").MustString(val)
  50. }
  51. if sec.HasKey("ENABLE_ACCESS_LOG") && !sec.Key("ENABLE_ACCESS_LOG").MustBool() {
  52. sec.Key("logger.access.MODE").SetValue("")
  53. }
  54. deprecatedSetting(rootCfg, "log", "ROUTER", "log", "logger.router.MODE", "1.21")
  55. deprecatedSetting(rootCfg, "log", "DISABLE_ROUTER_LOG", "log", "logger.router.MODE", "1.21")
  56. if val := sec.Key("ROUTER").String(); val != "" {
  57. sec.Key("logger.router.MODE").MustString(val)
  58. }
  59. if !sec.HasKey("logger.router.MODE") {
  60. sec.Key("logger.router.MODE").MustString(",") // use default logger
  61. }
  62. if sec.HasKey("DISABLE_ROUTER_LOG") && sec.Key("DISABLE_ROUTER_LOG").MustBool() {
  63. sec.Key("logger.router.MODE").SetValue("")
  64. }
  65. deprecatedSetting(rootCfg, "log", "XORM", "log", "logger.xorm.MODE", "1.21")
  66. deprecatedSetting(rootCfg, "log", "ENABLE_XORM_LOG", "log", "logger.xorm.MODE", "1.21")
  67. if val := sec.Key("XORM").String(); val != "" {
  68. sec.Key("logger.xorm.MODE").MustString(val)
  69. }
  70. if !sec.HasKey("logger.xorm.MODE") {
  71. sec.Key("logger.xorm.MODE").MustString(",") // use default logger
  72. }
  73. if sec.HasKey("ENABLE_XORM_LOG") && !sec.Key("ENABLE_XORM_LOG").MustBool() {
  74. sec.Key("logger.xorm.MODE").SetValue("")
  75. }
  76. }
  77. func LogPrepareFilenameForWriter(fileName, defaultFileName string) string {
  78. if fileName == "" {
  79. fileName = defaultFileName
  80. }
  81. if !filepath.IsAbs(fileName) {
  82. fileName = filepath.Join(Log.RootPath, fileName)
  83. } else {
  84. fileName = filepath.Clean(fileName)
  85. }
  86. if err := os.MkdirAll(filepath.Dir(fileName), os.ModePerm); err != nil {
  87. panic(fmt.Sprintf("unable to create directory for log %q: %v", fileName, err.Error()))
  88. }
  89. return fileName
  90. }
  91. func loadLogModeByName(rootCfg ConfigProvider, loggerName, modeName string) (writerName, writerType string, writerMode log.WriterMode, err error) {
  92. sec := rootCfg.Section("log." + modeName)
  93. writerMode = log.WriterMode{}
  94. writerType = ConfigSectionKeyString(sec, "MODE")
  95. if writerType == "" {
  96. writerType = modeName
  97. }
  98. writerName = modeName
  99. defaultFlags := "stdflags"
  100. defaultFilaName := "gitea.log"
  101. if loggerName == "access" {
  102. // "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.
  103. // so "access" logger's writer name is usually "file.access" or "console.access"
  104. writerName += ".access"
  105. defaultFlags = "none"
  106. defaultFilaName = "access.log"
  107. }
  108. writerMode.Level = log.LevelFromString(ConfigInheritedKeyString(sec, "LEVEL", Log.Level.String()))
  109. writerMode.StacktraceLevel = log.LevelFromString(ConfigInheritedKeyString(sec, "STACKTRACE_LEVEL", Log.StacktraceLogLevel.String()))
  110. writerMode.Prefix = ConfigInheritedKeyString(sec, "PREFIX")
  111. writerMode.Expression = ConfigInheritedKeyString(sec, "EXPRESSION")
  112. writerMode.Flags = log.FlagsFromString(ConfigInheritedKeyString(sec, "FLAGS", defaultFlags))
  113. switch writerType {
  114. case "console":
  115. useStderr := ConfigInheritedKey(sec, "STDERR").MustBool(false)
  116. defaultCanColor := log.CanColorStdout
  117. if useStderr {
  118. defaultCanColor = log.CanColorStderr
  119. }
  120. writerOption := log.WriterConsoleOption{Stderr: useStderr}
  121. writerMode.Colorize = ConfigInheritedKey(sec, "COLORIZE").MustBool(defaultCanColor)
  122. writerMode.WriterOption = writerOption
  123. case "file":
  124. fileName := LogPrepareFilenameForWriter(ConfigInheritedKey(sec, "FILE_NAME").String(), defaultFilaName)
  125. writerOption := log.WriterFileOption{}
  126. writerOption.FileName = fileName + filenameSuffix // FIXME: the suffix doesn't seem right, see its related comments
  127. writerOption.LogRotate = ConfigInheritedKey(sec, "LOG_ROTATE").MustBool(true)
  128. writerOption.MaxSize = 1 << uint(ConfigInheritedKey(sec, "MAX_SIZE_SHIFT").MustInt(28))
  129. writerOption.DailyRotate = ConfigInheritedKey(sec, "DAILY_ROTATE").MustBool(true)
  130. writerOption.MaxDays = ConfigInheritedKey(sec, "MAX_DAYS").MustInt(7)
  131. writerOption.Compress = ConfigInheritedKey(sec, "COMPRESS").MustBool(true)
  132. writerOption.CompressionLevel = ConfigInheritedKey(sec, "COMPRESSION_LEVEL").MustInt(-1)
  133. writerMode.WriterOption = writerOption
  134. case "conn":
  135. writerOption := log.WriterConnOption{}
  136. writerOption.ReconnectOnMsg = ConfigInheritedKey(sec, "RECONNECT_ON_MSG").MustBool()
  137. writerOption.Reconnect = ConfigInheritedKey(sec, "RECONNECT").MustBool()
  138. writerOption.Protocol = ConfigInheritedKey(sec, "PROTOCOL").In("tcp", []string{"tcp", "unix", "udp"})
  139. writerOption.Addr = ConfigInheritedKey(sec, "ADDR").MustString(":7020")
  140. writerMode.WriterOption = writerOption
  141. default:
  142. if !log.HasEventWriter(writerType) {
  143. return "", "", writerMode, fmt.Errorf("invalid log writer type (mode): %s, maybe it needs something like 'MODE=file' in [log.%s] section", writerType, modeName)
  144. }
  145. }
  146. return writerName, writerType, writerMode, nil
  147. }
  148. var filenameSuffix = ""
  149. // RestartLogsWithPIDSuffix restarts the logs with a PID suffix on files
  150. // FIXME: it seems not right, it breaks log rotating or log collectors
  151. func RestartLogsWithPIDSuffix() {
  152. filenameSuffix = fmt.Sprintf(".%d", os.Getpid())
  153. initAllLoggers() // when forking, before restarting, rename logger file and re-init all loggers
  154. }
  155. func InitLoggersForTest() {
  156. initAllLoggers()
  157. }
  158. // initAllLoggers creates all the log services
  159. func initAllLoggers() {
  160. initManagedLoggers(log.GetManager(), CfgProvider)
  161. golog.SetFlags(0)
  162. golog.SetPrefix("")
  163. golog.SetOutput(log.LoggerToWriter(log.GetLogger(log.DEFAULT).Info))
  164. }
  165. func initManagedLoggers(manager *log.LoggerManager, cfg ConfigProvider) {
  166. loadLogGlobalFrom(cfg)
  167. prepareLoggerConfig(cfg)
  168. initLoggerByName(manager, cfg, log.DEFAULT) // default
  169. initLoggerByName(manager, cfg, "access")
  170. initLoggerByName(manager, cfg, "router")
  171. initLoggerByName(manager, cfg, "xorm")
  172. }
  173. func initLoggerByName(manager *log.LoggerManager, rootCfg ConfigProvider, loggerName string) {
  174. sec := rootCfg.Section("log")
  175. keyPrefix := "logger." + loggerName
  176. disabled := sec.HasKey(keyPrefix+".MODE") && sec.Key(keyPrefix+".MODE").String() == ""
  177. if disabled {
  178. return
  179. }
  180. modeVal := sec.Key(keyPrefix + ".MODE").String()
  181. if modeVal == "," {
  182. modeVal = Log.Mode
  183. }
  184. var eventWriters []log.EventWriter
  185. modes := strings.Split(modeVal, ",")
  186. for _, modeName := range modes {
  187. modeName = strings.TrimSpace(modeName)
  188. if modeName == "" {
  189. continue
  190. }
  191. writerName, writerType, writerMode, err := loadLogModeByName(rootCfg, loggerName, modeName)
  192. if err != nil {
  193. log.FallbackErrorf("Failed to load writer mode %q for logger %s: %v", modeName, loggerName, err)
  194. continue
  195. }
  196. if writerMode.BufferLen == 0 {
  197. writerMode.BufferLen = Log.BufferLen
  198. }
  199. eventWriter := manager.GetSharedWriter(writerName)
  200. if eventWriter == nil {
  201. eventWriter, err = manager.NewSharedWriter(writerName, writerType, writerMode)
  202. if err != nil {
  203. log.FallbackErrorf("Failed to create event writer for logger %s: %v", loggerName, err)
  204. continue
  205. }
  206. }
  207. eventWriters = append(eventWriters, eventWriter)
  208. }
  209. manager.GetLogger(loggerName).ReplaceAllWriters(eventWriters...)
  210. }
  211. func InitSQLLoggersForCli(level log.Level) {
  212. log.SetConsoleLogger("xorm", "console", level)
  213. }
  214. func IsAccessLogEnabled() bool {
  215. return log.IsLoggerEnabled("access")
  216. }
  217. func IsRouteLogEnabled() bool {
  218. return log.IsLoggerEnabled("router")
  219. }