package log import ( "fmt" "os" "sync" "time" "go.uber.org/zap" "go.uber.org/zap/buffer" "go.uber.org/zap/zapcore" "gopkg.in/natefinch/lumberjack.v2" ) // func InitLogger() { // writeSyncer := getLogWriter() // encoder := getEncoder() // core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel) // logger := zap.New(core) //, zap.AddCaller(), zap.AddCallerSkip(1) // sugarLogger = logger.Sugar() // } // var l = new(zapcore.Level) // err = l.UnmarshalText([]byte(cfg.Level)) // if err != nil { // return // } func InitLogger(appName string, isDisplayConsole bool) (*zap.SugaredLogger, *asyncWriter) { encoder := getEncoder() // test.log记录全量日志 filePath1 := fmt.Sprintf("%s.log", appName) writeSyncer1, lumberJackLogger1 := getLogWriter(filePath1, 1024*1024*1024, 7, 7) filePath2 := fmt.Sprintf("%s.err.log", appName) writeSyncer2, lumberJackLogger2 := getLogWriter(filePath2, 1024*1024*1024, 7, 7) // c1 := zapcore.NewCore(encoder, writeSyncer1, zapcore.DebugLevel) // 异步写入器 asyncWriter := NewAsyncWriter(writeSyncer1) asyncWriter.StartRunningAndRotate(func() { lumberJackLogger1.Rotate() lumberJackLogger2.Rotate() }) asyncCore := zapcore.NewCore(encoder, zapcore.AddSync(asyncWriter), zapcore.InfoLevel) // test.err.log记录ERROR级别的日志 // filePath2 := fmt.Sprintf("%s.err.log", appName) // writeSyncer2, lumberJackLogger2 := getLogWriter(filePath2, 1024*1024*1024, 7, 7) c2 := zapcore.NewCore(encoder, writeSyncer2, zap.ErrorLevel) // 使用NewTee将c1和c2合并到core var core zapcore.Core if isDisplayConsole { consoleWriter := zapcore.AddSync(os.Stdout) c3 := zapcore.NewCore(encoder, consoleWriter, zap.DebugLevel) core = zapcore.NewTee(asyncCore, c2, c3) } else { core = zapcore.NewTee(asyncCore, c2) } logger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(2)) //, zap.AddCaller(), zap.AddCallerSkip(1) sugarLogger := logger.Sugar() return sugarLogger, asyncWriter } func getEncoder() zapcore.Encoder { encoderConfig := zap.NewProductionEncoderConfig() encoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout(time.DateTime) //ISO8601TimeEncoder // encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder return zapcore.NewJSONEncoder(encoderConfig) // NewJSONEncoder // NewConsoleEncoder } // func getLogWriter() zapcore.WriteSyncer { // file, _ := os.Create("./test.log") // // 利用io.MultiWriter支持文件和终端两个输出目标 // ws := io.MultiWriter(file, os.Stdout) // return zapcore.AddSync(ws) // } func getLogWriter(filename string, maxSize, maxBackup, maxAge int) (zapcore.WriteSyncer, *lumberjack.Logger) { lumberJackLogger := &lumberjack.Logger{ Filename: filename, MaxSize: maxSize, MaxBackups: maxBackup, MaxAge: maxAge, LocalTime: true, } return zapcore.AddSync(lumberJackLogger), lumberJackLogger } // 异步写入器 type asyncWriter struct { entryChan chan *buffer.Buffer wg sync.WaitGroup writer zapcore.WriteSyncer pool buffer.Pool } func NewAsyncWriter(writeSyncer1 zapcore.WriteSyncer) *asyncWriter { entryChan := make(chan *buffer.Buffer, 1000) // 缓冲区大小可以根据实际需求调整 asyncWriter := new(asyncWriter) asyncWriter.entryChan = entryChan asyncWriter.writer = writeSyncer1 asyncWriter.pool = buffer.NewPool() return asyncWriter } func (w *asyncWriter) Write(p []byte) (n int, err error) { buffer := w.pool.Get() buffer.Write(p) w.entryChan <- buffer return len(p), nil } func (w *asyncWriter) Sync() error { buffer := w.pool.Get() w.entryChan <- buffer return nil // return w.writer.Sync() } func (w *asyncWriter) StartRunningAndRotate(rotateFunc func()) { w.wg.Add(1) go func() { defer w.wg.Done() safeWrite := func(entry *buffer.Buffer) { defer func() { if err := recover(); err != nil { fmt.Fprintln(os.Stderr, "panic writing to log file:", err) } }() var err error if entry.Len() == 0 { err = w.writer.Sync() } else { _, err = w.writer.Write(entry.Bytes()) } if err != nil { fmt.Fprintln(os.Stderr, "Error writing to log file:", err) } } safeRote := func() { defer func() { if err := recover(); err != nil { fmt.Fprintln(os.Stderr, "panic writing to log file:", err) } }() rotateFunc() } lastRoteTime := time.Now() ticker := time.NewTicker(time.Minute) for { select { case ct := <-ticker.C: if ct.YearDay() != lastRoteTime.YearDay() { lastRoteTime = ct safeRote() } case entry, ok := <-w.entryChan: if !ok { return } safeWrite(entry) entry.Free() } } }() } func testzaplog() { log, w := InitLogger("test", false) defer func() { log.Sync() close(w.entryChan) w.wg.Wait() }() log.Info("info") log.Error("error") log.Debug("debug") log.Warn("warn") // log.Panic("panic") log.Fatal("fatal") // time.Sleep(time.Second * 1000) // defer sugarLogger.Sync() }