package logger import ( "fmt" "os" "runtime" "strings" "time" "go.uber.org/zap" "go.uber.org/zap/zapcore" "gopkg.in/natefinch/lumberjack.v2" ) var ( zlog *zap.SugaredLogger ) type LoggerConfig struct { Filename string `mapstructure:"filename" json:"filename" yaml:"filename"` Level string `mapstructure:"level" json:"level" yaml:"level"` Format string `mapstructure:"format" json:"format" yaml:"format"` Prefix string `mapstructure:"prefix" json:"prefix" yaml:"prefix"` Director string `mapstructure:"director" json:"director" yaml:"director"` ShowLine bool `mapstructure:"show-line" json:"show-line" yaml:"show-line"` EncodeLevel string `mapstructure:"encode-level" json:"encode-level" yaml:"encode-level"` StacktraceKey string `mapstructure:"stacktrace-key" json:"stacktrace-key" yaml:"stacktrace-key"` LogInConsole bool `mapstructure:"log-in-console" json:"log-in-console" yaml:"log-in-console"` } func Init(conf *LoggerConfig) { if conf.Filename == "/dev/stdout" { ecf := zap.NewProductionEncoderConfig() ecf.FunctionKey = "func" ecf.EncodeTime = zapcore.ISO8601TimeEncoder ecf.ConsoleSeparator = " " ecf.EncodeCaller = zapcore.ShortCallerEncoder core := zapcore.NewCore( zapcore.NewConsoleEncoder(ecf), zapcore.AddSync(os.Stdout), zap.DebugLevel, ) zl := zap.New(core, zap.AddCallerSkip(1), zap.AddCaller()) zlog = zl.Sugar() return } _, err := os.Stat(conf.Filename) if err != nil { if os.IsNotExist(err) { err = os.MkdirAll(conf.Filename, os.ModePerm) if err != nil { panic(err) } } else { fmt.Println("logger init error:", err) } } if strings.LastIndex(conf.Filename, "/") != 0 { conf.Filename = conf.Filename + "/" } encoder := zapcore.NewConsoleEncoder(zapcore.EncoderConfig{ MessageKey: "msg", LevelKey: "level", EncodeLevel: zapcore.CapitalLevelEncoder, TimeKey: "ts", EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { enc.AppendString(t.Format("2006-01-02 15:04:05")) }, CallerKey: "file", EncodeCaller: zapcore.ShortCallerEncoder, EncodeDuration: func(d time.Duration, enc zapcore.PrimitiveArrayEncoder) { enc.AppendInt64(int64(d) / 1000000) }, }) // 实现两个判断日志等级的interface infoLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { return lvl >= zapcore.InfoLevel }) errorLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { return lvl >= zapcore.ErrorLevel }) // 获取 info、error日志文件的io.Writer 抽象 getWriter() 在下方实现 now := time.Now() fileTime := now.Format("20060102") + "-" + now.Format("150405") fileFormat := "%s%s-%s.log" infoWriter := getWriter(fmt.Sprintf(fileFormat, conf.Filename, "info", fileTime)) errorWriter := getWriter(fmt.Sprintf(fileFormat, conf.Filename, "error", fileTime)) // 最后创建具体的Logger core := zapcore.NewTee( zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), infoLevel), //打印到控制台 zapcore.NewCore(encoder, infoWriter, infoLevel), zapcore.NewCore(encoder, errorWriter, errorLevel), ) zl := zap.New(core, zap.AddCallerSkip(1), zap.AddCaller()) zlog = zl.Sugar() } func GetDefault() *zap.SugaredLogger { return zlog } func InitDefault() { Init(&LoggerConfig{ Filename: "/dev/stdout", }) } func Sync() { _ = zlog.Sync() } func getWriter(filename string) zapcore.WriteSyncer { lumberJackLogger := &lumberjack.Logger{ Filename: filename, // 文件位置 MaxSize: 100, // 进行切割之前,日志文件的最大大小(MB为单位) MaxAge: 10, // 保留旧文件的最大天数 MaxBackups: 3, // 保留旧文件的最大个数 Compress: false, // 是否压缩/归档旧文件 } // AddSync 将 io.Writer 转换为 WriteSyncer。 // 它试图变得智能:如果 io.Writer 的具体类型实现了 WriteSyncer,我们将使用现有的 Sync 方法。 // 如果没有,我们将添加一个无操作同步。 return zapcore.AddSync(lumberJackLogger) } func Debug(args ...interface{}) { zlog.Debug(args...) } func Debugf(template string, args ...interface{}) { zlog.Debugf(template, args...) } func Info(args ...interface{}) { zlog.Info(args...) } func Infof(template string, args ...interface{}) { zlog.Infof(template, args...) } func Warn(args ...interface{}) { zlog.Warn(args...) } func Warnf(template string, args ...interface{}) { zlog.Warnf(template, args...) } func Error(args ...interface{}) { zlog.Error(args...) } func Errorf(template string, args ...interface{}) { zlog.Errorf(template, args...) } func DPanic(args ...interface{}) { zlog.DPanic(args...) } func DPanicf(template string, args ...interface{}) { zlog.DPanicf(template, args...) } func Panic(args ...interface{}) { zlog.Panic(args...) } func Panicf(template string, args ...interface{}) { zlog.Panicf(template, args...) } func Fatal(args ...interface{}) { zlog.Fatal(args...) } func Fatalf(template string, args ...interface{}) { zlog.Fatalf(template, args...) } func SafeGoroutine(fn func()) { go func() { defer func() { if r := recover(); r != nil { buf := make([]byte, 1<<16) // 64KB stackSize := runtime.Stack(buf, false) msg := fmt.Sprintf("panic: %v\n%s\n", r, buf[:stackSize]) Errorf(msg) } }() fn() }() }