You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

log.go 9.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package setting
  5. import (
  6. "encoding/json"
  7. golog "log"
  8. "os"
  9. "path"
  10. "path/filepath"
  11. "strings"
  12. "code.gitea.io/gitea/modules/log"
  13. ini "gopkg.in/ini.v1"
  14. )
  15. type defaultLogOptions struct {
  16. levelName string // LogLevel
  17. flags string
  18. filename string //path.Join(LogRootPath, "gitea.log")
  19. bufferLength int64
  20. disableConsole bool
  21. }
  22. func newDefaultLogOptions() defaultLogOptions {
  23. return defaultLogOptions{
  24. levelName: LogLevel,
  25. flags: "stdflags",
  26. filename: filepath.Join(LogRootPath, "gitea.log"),
  27. bufferLength: 10000,
  28. disableConsole: false,
  29. }
  30. }
  31. // SubLogDescription describes a sublogger
  32. type SubLogDescription struct {
  33. Name string
  34. Provider string
  35. Config string
  36. }
  37. // LogDescription describes a named logger
  38. type LogDescription struct {
  39. Name string
  40. SubLogDescriptions []SubLogDescription
  41. }
  42. func getLogLevel(section *ini.Section, key string, defaultValue string) string {
  43. value := section.Key(key).MustString("info")
  44. return log.FromString(value).String()
  45. }
  46. func getStacktraceLogLevel(section *ini.Section, key string, defaultValue string) string {
  47. value := section.Key(key).MustString("none")
  48. return log.FromString(value).String()
  49. }
  50. func generateLogConfig(sec *ini.Section, name string, defaults defaultLogOptions) (mode, jsonConfig, levelName string) {
  51. levelName = getLogLevel(sec, "LEVEL", LogLevel)
  52. level := log.FromString(levelName)
  53. stacktraceLevelName := getStacktraceLogLevel(sec, "STACKTRACE_LEVEL", StacktraceLogLevel)
  54. stacktraceLevel := log.FromString(stacktraceLevelName)
  55. mode = name
  56. keys := sec.Keys()
  57. logPath := defaults.filename
  58. flags := log.FlagsFromString(defaults.flags)
  59. expression := ""
  60. prefix := ""
  61. for _, key := range keys {
  62. switch key.Name() {
  63. case "MODE":
  64. mode = key.MustString(name)
  65. case "FILE_NAME":
  66. logPath = key.MustString(defaults.filename)
  67. forcePathSeparator(logPath)
  68. if !filepath.IsAbs(logPath) {
  69. logPath = path.Join(LogRootPath, logPath)
  70. }
  71. case "FLAGS":
  72. flags = log.FlagsFromString(key.MustString(defaults.flags))
  73. case "EXPRESSION":
  74. expression = key.MustString("")
  75. case "PREFIX":
  76. prefix = key.MustString("")
  77. }
  78. }
  79. logConfig := map[string]interface{}{
  80. "level": level.String(),
  81. "expression": expression,
  82. "prefix": prefix,
  83. "flags": flags,
  84. "stacktraceLevel": stacktraceLevel.String(),
  85. }
  86. // Generate log configuration.
  87. switch mode {
  88. case "console":
  89. useStderr := sec.Key("STDERR").MustBool(false)
  90. logConfig["stderr"] = useStderr
  91. if useStderr {
  92. logConfig["colorize"] = sec.Key("COLORIZE").MustBool(log.CanColorStderr)
  93. } else {
  94. logConfig["colorize"] = sec.Key("COLORIZE").MustBool(log.CanColorStdout)
  95. }
  96. case "file":
  97. if err := os.MkdirAll(path.Dir(logPath), os.ModePerm); err != nil {
  98. panic(err.Error())
  99. }
  100. logConfig["filename"] = logPath
  101. logConfig["rotate"] = sec.Key("LOG_ROTATE").MustBool(true)
  102. logConfig["maxsize"] = 1 << uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28))
  103. logConfig["daily"] = sec.Key("DAILY_ROTATE").MustBool(true)
  104. logConfig["maxdays"] = sec.Key("MAX_DAYS").MustInt(7)
  105. logConfig["compress"] = sec.Key("COMPRESS").MustBool(true)
  106. logConfig["compressionLevel"] = sec.Key("COMPRESSION_LEVEL").MustInt(-1)
  107. case "conn":
  108. logConfig["reconnectOnMsg"] = sec.Key("RECONNECT_ON_MSG").MustBool()
  109. logConfig["reconnect"] = sec.Key("RECONNECT").MustBool()
  110. logConfig["net"] = sec.Key("PROTOCOL").In("tcp", []string{"tcp", "unix", "udp"})
  111. logConfig["addr"] = sec.Key("ADDR").MustString(":7020")
  112. case "smtp":
  113. logConfig["username"] = sec.Key("USER").MustString("example@example.com")
  114. logConfig["password"] = sec.Key("PASSWD").MustString("******")
  115. logConfig["host"] = sec.Key("HOST").MustString("127.0.0.1:25")
  116. logConfig["sendTos"] = sec.Key("RECEIVERS").MustString("[]")
  117. logConfig["subject"] = sec.Key("SUBJECT").MustString("Diagnostic message from Gitea")
  118. }
  119. logConfig["colorize"] = sec.Key("COLORIZE").MustBool(false)
  120. byteConfig, err := json.Marshal(logConfig)
  121. if err != nil {
  122. log.Error("Failed to marshal log configuration: %v %v", logConfig, err)
  123. return
  124. }
  125. jsonConfig = string(byteConfig)
  126. return
  127. }
  128. func generateNamedLogger(key string, options defaultLogOptions) *LogDescription {
  129. description := LogDescription{
  130. Name: key,
  131. }
  132. sections := strings.Split(Cfg.Section("log").Key(strings.ToUpper(key)).MustString(""), ",")
  133. //description.Configs = make([]string, len(description.Sections))
  134. for i := 0; i < len(sections); i++ {
  135. sections[i] = strings.TrimSpace(sections[i])
  136. }
  137. for _, name := range sections {
  138. if len(name) == 0 || (name == "console" && options.disableConsole) {
  139. continue
  140. }
  141. sec, err := Cfg.GetSection("log." + name + "." + key)
  142. if err != nil {
  143. sec, _ = Cfg.NewSection("log." + name + "." + key)
  144. }
  145. provider, config, levelName := generateLogConfig(sec, name, options)
  146. log.NewNamedLogger(key, options.bufferLength, name, provider, config)
  147. description.SubLogDescriptions = append(description.SubLogDescriptions, SubLogDescription{
  148. Name: name,
  149. Provider: provider,
  150. Config: config,
  151. })
  152. log.Info("%s Log: %s(%s:%s)", strings.Title(key), strings.Title(name), provider, levelName)
  153. }
  154. LogDescriptions[key] = &description
  155. return &description
  156. }
  157. func newMacaronLogService() {
  158. options := newDefaultLogOptions()
  159. options.filename = filepath.Join(LogRootPath, "macaron.log")
  160. options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000)
  161. Cfg.Section("log").Key("MACARON").MustString("file")
  162. if RedirectMacaronLog {
  163. generateNamedLogger("macaron", options)
  164. }
  165. }
  166. func newAccessLogService() {
  167. EnableAccessLog = Cfg.Section("log").Key("ENABLE_ACCESS_LOG").MustBool(false)
  168. AccessLogTemplate = Cfg.Section("log").Key("ACCESS_LOG_TEMPLATE").MustString(
  169. `{{.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}}"`)
  170. Cfg.Section("log").Key("ACCESS").MustString("file")
  171. if EnableAccessLog {
  172. options := newDefaultLogOptions()
  173. options.filename = filepath.Join(LogRootPath, "access.log")
  174. options.flags = "" // For the router we don't want any prefixed flags
  175. options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000)
  176. generateNamedLogger("access", options)
  177. }
  178. }
  179. func newRouterLogService() {
  180. Cfg.Section("log").Key("ROUTER").MustString("console")
  181. // Allow [log] DISABLE_ROUTER_LOG to override [server] DISABLE_ROUTER_LOG
  182. DisableRouterLog = Cfg.Section("log").Key("DISABLE_ROUTER_LOG").MustBool(DisableRouterLog)
  183. if !DisableRouterLog && RedirectMacaronLog {
  184. options := newDefaultLogOptions()
  185. options.filename = filepath.Join(LogRootPath, "router.log")
  186. options.flags = "date,time" // For the router we don't want any prefixed flags
  187. options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000)
  188. generateNamedLogger("router", options)
  189. }
  190. }
  191. func newLogService() {
  192. log.Info("Gitea v%s%s", AppVer, AppBuiltWith)
  193. options := newDefaultLogOptions()
  194. options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000)
  195. description := LogDescription{
  196. Name: log.DEFAULT,
  197. }
  198. sections := strings.Split(Cfg.Section("log").Key("MODE").MustString("console"), ",")
  199. useConsole := false
  200. for i := 0; i < len(sections); i++ {
  201. sections[i] = strings.TrimSpace(sections[i])
  202. if sections[i] == "console" {
  203. useConsole = true
  204. }
  205. }
  206. if !useConsole {
  207. log.DelLogger("console")
  208. }
  209. for _, name := range sections {
  210. if len(name) == 0 {
  211. continue
  212. }
  213. sec, err := Cfg.GetSection("log." + name)
  214. if err != nil {
  215. sec, _ = Cfg.NewSection("log." + name)
  216. }
  217. provider, config, levelName := generateLogConfig(sec, name, options)
  218. log.NewLogger(options.bufferLength, name, provider, config)
  219. description.SubLogDescriptions = append(description.SubLogDescriptions, SubLogDescription{
  220. Name: name,
  221. Provider: provider,
  222. Config: config,
  223. })
  224. log.Info("Gitea Log Mode: %s(%s:%s)", strings.Title(name), strings.Title(provider), levelName)
  225. }
  226. LogDescriptions[log.DEFAULT] = &description
  227. // Finally redirect the default golog to here
  228. golog.SetFlags(0)
  229. golog.SetPrefix("")
  230. golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT)))
  231. }
  232. // NewLogServices creates all the log services
  233. func NewLogServices(disableConsole bool) {
  234. newLogService()
  235. newMacaronLogService()
  236. newRouterLogService()
  237. newAccessLogService()
  238. NewXORMLogService(disableConsole)
  239. }
  240. // NewXORMLogService initializes xorm logger service
  241. func NewXORMLogService(disableConsole bool) {
  242. EnableXORMLog = Cfg.Section("log").Key("ENABLE_XORM_LOG").MustBool(true)
  243. if EnableXORMLog {
  244. options := newDefaultLogOptions()
  245. options.filename = filepath.Join(LogRootPath, "xorm.log")
  246. options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000)
  247. options.disableConsole = disableConsole
  248. Cfg.Section("log").Key("XORM").MustString(",")
  249. generateNamedLogger("xorm", options)
  250. }
  251. }