zaplogger.go 5.5 KB

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