logger.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. package core
  2. import (
  3. "app/commons/config"
  4. "fmt"
  5. rotateLogs "github.com/lestrrat-go/file-rotatelogs"
  6. "github.com/spf13/viper"
  7. "go.uber.org/zap"
  8. "go.uber.org/zap/zapcore"
  9. "io"
  10. "os"
  11. "strings"
  12. "time"
  13. )
  14. const (
  15. DefaultLog LogTagName = "app"
  16. JobLogName LogTagName = "job"
  17. )
  18. var loggerConfer *config.Zap
  19. func loggerConf() *config.Zap {
  20. if loggerConfer == nil {
  21. loggerInit()
  22. }
  23. return loggerConfer
  24. }
  25. var (
  26. errorLoggerMap = make(map[LogTagName]*zap.Logger)
  27. Log *zap.SugaredLogger
  28. JobLog *zap.SugaredLogger
  29. )
  30. func init() {
  31. tags := []LogTagName{DefaultLog, JobLogName}
  32. for _, lg := range tags {
  33. errorLoggerMap[lg] = newLogger(lg)
  34. }
  35. Log = errorLoggerMap[DefaultLog].Sugar()
  36. JobLog = errorLoggerMap[JobLogName].Sugar()
  37. }
  38. func loggerInit() {
  39. if config.EnvConf().Zap != nil {
  40. loggerConfer = config.EnvConf().Zap
  41. return
  42. }
  43. v := viper.New()
  44. v.SetDefault("prefix", "AppServer-")
  45. v.SetDefault("level", "LowercaseColorLevelEncoder")
  46. v.SetDefault("format", "_json")
  47. v.SetDefault("director", "logs")
  48. v.SetDefault("encode_level", "LowercaseLevelEncoder")
  49. v.SetDefault("stacktrace_key", "error")
  50. v.SetDefault("max_age", 3)
  51. v.SetDefault("rotation_size", 100)
  52. v.SetDefault("rotation_count", 3)
  53. v.SetDefault("show_line", true)
  54. v.SetDefault("log_in_console", true)
  55. v.SetDefault("log_output_file", true)
  56. if err := v.Unmarshal(&loggerConfer); err != nil {
  57. panic(fmt.Errorf("Fatal error config file: %s \n", err))
  58. }
  59. }
  60. type LogTagName string
  61. type logConfTags struct {
  62. Tag LogTagName `json:"tag" yaml:"tag"`
  63. FileName string `json:"filename" yaml:"filename"`
  64. ErrFileName string `json:"errFileName" yaml:"errFileName"`
  65. }
  66. func getWriter(filename string) io.Writer {
  67. // 生成 rotate_logs 的Logger 实际生成的文件名 demo.log.YY mm dd HH
  68. hook, err := rotateLogs.New(
  69. strings.Replace(filename, ".log", "", -1)+".%Y%m%d%H.log",
  70. rotateLogs.WithLinkName(filename),
  71. // 根据文件大小切割日志
  72. rotateLogs.WithRotationSize(1024*1024*loggerConf().LogSignSize()), // 每个日志文件大小设置:100M
  73. rotateLogs.WithRotationTime(time.Hour*24), // 日志轮询周期 默认1分钟:60秒
  74. rotateLogs.WithRotationCount(loggerConf().LogSaveCount()), // 日志保留份数
  75. // 根据时间分割日志
  76. // rotateLogs.WithMaxAge(time.Hour*24*2), // 保存2天日志
  77. )
  78. if err != nil {
  79. panic(err)
  80. }
  81. return hook
  82. }
  83. // 设置日志格式 非json可进行堆栈跟踪
  84. func getEncoder() zapcore.Encoder {
  85. if loggerConf().Format == "json" || loggerConf().Format == "" {
  86. return zapcore.NewJSONEncoder(getEncoderConfig())
  87. }
  88. return zapcore.NewConsoleEncoder(getEncoderConfig())
  89. }
  90. func getEncoderConfig() zapcore.EncoderConfig {
  91. return zapcore.EncoderConfig{
  92. MessageKey: "message",
  93. LevelKey: "level",
  94. EncodeLevel: loggerConf().ZapEncodeLevel(),
  95. TimeKey: "time",
  96. NameKey: "logger",
  97. CallerKey: "caller",
  98. StacktraceKey: loggerConf().StacktraceKey, // "error"
  99. LineEnding: zapcore.DefaultLineEnding,
  100. EncodeTime: customTimeEncoder,
  101. EncodeDuration: zapcore.SecondsDurationEncoder,
  102. EncodeCaller: zapcore.ShortCallerEncoder,
  103. }
  104. }
  105. func customTimeEncoder(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {
  106. encoder.AppendString(t.Format("2006/01/02-15:04:05.000"))
  107. }
  108. func NewLogger(tag LogTagName, args ...interface{}) *zap.Logger {
  109. if errorLoggerMap[tag] != nil {
  110. return errorLoggerMap[tag]
  111. }
  112. return newLogger(tag, args...)
  113. }
  114. func newLogger(tag LogTagName, args ...interface{}) *zap.Logger {
  115. savePath := fmt.Sprintf("./%s/", loggerConf().Director)
  116. if len(args) > 0 {
  117. savePath = fmt.Sprintf("./%s/", args[0])
  118. }
  119. tagConf := logConfTags{Tag: tag, FileName: fmt.Sprintf("%s.log", tag), ErrFileName: fmt.Sprintf("%s_err.log", tag)}
  120. encoder := getEncoder()
  121. infoLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
  122. return lvl >= loggerConf().TransportLevel()
  123. })
  124. errorLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
  125. return lvl >= zapcore.ErrorLevel
  126. })
  127. // 获取 info、error日志文件的io.Writer 抽象 getWriter() 在下方实现
  128. infoWriter := getWriter(savePath + tagConf.FileName)
  129. errorWriter := getWriter(savePath + tagConf.ErrFileName)
  130. cores := make([]zapcore.Core, 0)
  131. if loggerConf().LogOutputFile {
  132. cores = append(cores, zapcore.NewCore(encoder, zapcore.AddSync(infoWriter), infoLevel))
  133. cores = append(cores, zapcore.NewCore(encoder, zapcore.AddSync(errorWriter), errorLevel))
  134. }
  135. if loggerConf().LogInConsole {
  136. cores = append(cores, zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), infoLevel))
  137. }
  138. // 最后创建具体的Logger
  139. core := zapcore.NewTee(cores...)
  140. // 开启开发模式,堆栈跟踪
  141. caller := zap.AddCaller()
  142. development := zap.Development()
  143. filed := zap.Fields(zap.String("Tag", string(tagConf.Tag)))
  144. stackTrace := zap.AddStacktrace(zap.ErrorLevel) // 当错误等级error时 触发堆栈跟踪
  145. log := zap.New(core, caller, stackTrace, development, filed)
  146. if loggerConf().ShowLine {
  147. log = log.WithOptions(zap.AddCaller())
  148. }
  149. errorLoggerMap[tagConf.Tag] = log
  150. return errorLoggerMap[tagConf.Tag]
  151. }