本站源代码
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.

311 line
9.4KB

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