zaplogger.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. package log
  2. import (
  3. "fmt"
  4. "os"
  5. "sync"
  6. "time"
  7. "go.uber.org/zap"
  8. "go.uber.org/zap/buffer"
  9. "go.uber.org/zap/zapcore"
  10. "gopkg.in/natefinch/lumberjack.v2"
  11. )
  12. // func InitLogger() {
  13. // writeSyncer := getLogWriter()
  14. // encoder := getEncoder()
  15. // core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)
  16. // logger := zap.New(core) //, zap.AddCaller(), zap.AddCallerSkip(1)
  17. // sugarLogger = logger.Sugar()
  18. // }
  19. // var l = new(zapcore.Level)
  20. // err = l.UnmarshalText([]byte(cfg.Level))
  21. // if err != nil {
  22. // return
  23. // }
  24. func InitLogger(appName string, isDisplayConsole bool) (*zap.SugaredLogger, *asyncWriter) {
  25. encoder := getEncoder()
  26. // test.log记录全量日志
  27. filePath1 := fmt.Sprintf("%s.log", appName)
  28. writeSyncer1, lumberJackLogger1 := getLogWriter(filePath1, 1024*1024*1024, 7, 7)
  29. filePath2 := fmt.Sprintf("%s.err.log", appName)
  30. writeSyncer2, lumberJackLogger2 := getLogWriter(filePath2, 1024*1024*1024, 7, 7)
  31. // c1 := zapcore.NewCore(encoder, writeSyncer1, zapcore.DebugLevel)
  32. // 异步写入器
  33. asyncWriter := NewAsyncWriter(writeSyncer1)
  34. asyncWriter.StartRunningAndRotate(func() {
  35. lumberJackLogger1.Rotate()
  36. lumberJackLogger2.Rotate()
  37. })
  38. asyncCore := zapcore.NewCore(encoder, zapcore.AddSync(asyncWriter), zapcore.InfoLevel)
  39. // test.err.log记录ERROR级别的日志
  40. // filePath2 := fmt.Sprintf("%s.err.log", appName)
  41. // writeSyncer2, lumberJackLogger2 := getLogWriter(filePath2, 1024*1024*1024, 7, 7)
  42. c2 := zapcore.NewCore(encoder, writeSyncer2, zap.ErrorLevel)
  43. // 使用NewTee将c1和c2合并到core
  44. var core zapcore.Core
  45. if isDisplayConsole {
  46. consoleWriter := zapcore.AddSync(os.Stdout)
  47. c3 := zapcore.NewCore(encoder, consoleWriter, zap.DebugLevel)
  48. core = zapcore.NewTee(asyncCore, c2, c3)
  49. } else {
  50. core = zapcore.NewTee(asyncCore, c2)
  51. }
  52. logger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(2)) //, zap.AddCaller(), zap.AddCallerSkip(1)
  53. sugarLogger := logger.Sugar()
  54. return sugarLogger, asyncWriter
  55. }
  56. func getEncoder() zapcore.Encoder {
  57. encoderConfig := zap.NewProductionEncoderConfig()
  58. encoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout(time.DateTime) //ISO8601TimeEncoder //
  59. encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
  60. return zapcore.NewJSONEncoder(encoderConfig)
  61. // NewJSONEncoder
  62. // NewConsoleEncoder
  63. }
  64. // func getLogWriter() zapcore.WriteSyncer {
  65. // file, _ := os.Create("./test.log")
  66. // // 利用io.MultiWriter支持文件和终端两个输出目标
  67. // ws := io.MultiWriter(file, os.Stdout)
  68. // return zapcore.AddSync(ws)
  69. // }
  70. func getLogWriter(filename string, maxSize, maxBackup, maxAge int) (zapcore.WriteSyncer, *lumberjack.Logger) {
  71. lumberJackLogger := &lumberjack.Logger{
  72. Filename: filename,
  73. MaxSize: maxSize,
  74. MaxBackups: maxBackup,
  75. MaxAge: maxAge,
  76. LocalTime: true,
  77. }
  78. return zapcore.AddSync(lumberJackLogger), lumberJackLogger
  79. }
  80. // 异步写入器
  81. type asyncWriter struct {
  82. entryChan chan *buffer.Buffer
  83. wg sync.WaitGroup
  84. writer zapcore.WriteSyncer
  85. pool buffer.Pool
  86. }
  87. func NewAsyncWriter(writeSyncer1 zapcore.WriteSyncer) *asyncWriter {
  88. entryChan := make(chan *buffer.Buffer, 1000) // 缓冲区大小可以根据实际需求调整
  89. asyncWriter := new(asyncWriter)
  90. asyncWriter.entryChan = entryChan
  91. asyncWriter.writer = writeSyncer1
  92. asyncWriter.pool = buffer.NewPool()
  93. return asyncWriter
  94. }
  95. func (w *asyncWriter) Write(p []byte) (n int, err error) {
  96. buffer := w.pool.Get()
  97. buffer.Write(p)
  98. w.entryChan <- buffer
  99. return len(p), nil
  100. }
  101. func (w *asyncWriter) Sync() error {
  102. buffer := w.pool.Get()
  103. w.entryChan <- buffer
  104. return nil
  105. // return w.writer.Sync()
  106. }
  107. func (w *asyncWriter) StartRunningAndRotate(rotateFunc func()) {
  108. w.wg.Add(1)
  109. go func() {
  110. defer w.wg.Done()
  111. safeWrite := func(entry *buffer.Buffer) {
  112. defer func() {
  113. if err := recover(); err != nil {
  114. fmt.Fprintln(os.Stderr, "panic writing to log file:", err)
  115. }
  116. }()
  117. var err error
  118. if entry.Len() == 0 {
  119. err = w.writer.Sync()
  120. } else {
  121. _, err = w.writer.Write(entry.Bytes())
  122. }
  123. if err != nil {
  124. fmt.Fprintln(os.Stderr, "Error writing to log file:", err)
  125. }
  126. }
  127. safeRote := func() {
  128. defer func() {
  129. if err := recover(); err != nil {
  130. fmt.Fprintln(os.Stderr, "panic writing to log file:", err)
  131. }
  132. }()
  133. rotateFunc()
  134. }
  135. lastRoteTime := time.Now()
  136. ticker := time.NewTicker(time.Minute)
  137. for {
  138. select {
  139. case ct := <-ticker.C:
  140. if ct.YearDay() != lastRoteTime.YearDay() {
  141. lastRoteTime = ct
  142. safeRote()
  143. }
  144. case entry, ok := <-w.entryChan:
  145. if !ok {
  146. return
  147. }
  148. safeWrite(entry)
  149. entry.Free()
  150. }
  151. }
  152. }()
  153. }
  154. func testzaplog() {
  155. log, w := InitLogger("test", false)
  156. defer func() {
  157. log.Sync()
  158. close(w.entryChan)
  159. w.wg.Wait()
  160. }()
  161. log.Info("info")
  162. log.Error("error")
  163. log.Debug("debug")
  164. log.Warn("warn")
  165. // log.Panic("panic")
  166. log.Fatal("fatal")
  167. // time.Sleep(time.Second * 1000)
  168. // defer sugarLogger.Sync()
  169. }