在开发过程中 会使用到日志库去记录错误的日志,尤其是golang中 有无穷无尽的error 如果不记录,当你的代码出错,就无从排错了。
zap 是开源的 Go 高性能日志库 主要有以下特点:
官网:https://github.com/uber-go/zap
https://pkg.go.dev/go.uber.org/zap#section-readme
go get -u go.uber.org/zap
zap只支持Go的两个最新小版本。
zap库的使用与其他的日志库非常相似。先创建一个logger,然后调用各个级别的方法记录日志
而 zap库给我们提供两种模式的日志记录
logger, _ := zap.NewProduction() defer logger.Sync() logger.Info("failed to fetch URL", // Structured context as strongly typed Field values. zap.String("url", "https://www.baidu.com"), zap.Int("attempt", 3), zap.Duration("backoff", time.Second), )
说实话我是很不喜欢logger模式的日志的
调用起来是真的麻烦 还要指定 int类型 string类型 这个类型那个类型
但优点也很明显那就是快 而且内存分配少,性能至上
logger, _ := zap.NewProduction() defer logger.Sync() // flushes buffer, if any sugar := logger.Sugar() sugar.Infow("failed to fetch URL", // Structured context as loosely typed key-value pairs. "url", "https://www.baidu.com", "attempt", 3, "backoff", time.Second, ) sugar.Infof("Failed to fetch URL: %s", "https://www.baidu.com")
这种就是printf风格的调用起来方便。即开即用。
log := zap.NewExample() log.Debug("this is debug message") log.Info("this is info message") log.Info("this is info message with fileds", zap.Int("age", 24), zap.String("agender", "man")) log.Warn("this is warn message") log.Error("this is error message") log.Panic("this is panic message")
结果
log, _ := zap.NewProduction() log.Debug("this is debug message") log.Info("this is info message") log.Info("this is info message with fileds", zap.Int("age", 24), zap.String("agender", "man")) log.Warn("this is warn message") log.Error("this is error message") log.Panic("this is panic message")
结果
log, _ := zap.NewDevelopment() log.Debug("this is debug message") log.Info("this is info message") log.Info("this is info message with fileds", zap.Int("age", 24), zap.String("agender", "man")) log.Warn("this is warn message") log.Error("this is error message") log.Panic("this is panic message")
结果
由上文可见
Example和Production使用的是json格式
而development使用行的形式
除此之外
Example和Production 所输出的多少也不一样。
具体如下:
Development
Production
如下文代码所示
func getEncoder() zapcore.Encoder { encoderConfig := zap.NewDevelopmentEncoderConfig() { // LevelKey值变为 level encoderConfig.LevelKey = "level" // MessageKey值变为 msg encoderConfig.MessageKey = "msg" // TimeKey值 变成time encoderConfig.TimeKey = "time" // 把输出的info 变成INFO 只需要丢对象 不许执行 encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder // 对时间进行格式化处理 encoderConfig.EncodeTime = func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) { encoder.AppendString(t.Local().Format("2006-01-02 15:04:05")) } } return zapcore.NewJSONEncoder(encoderConfig) }
如上代码所示,可以调节任意位置,我注释也标的很清楚
官网: https://pkg.go.dev/gopkg.in/natefinch/lumberjack.v2
zap没有切割日志的功能,所以我们必须借助第三方库来实现
要将 lumberjack 与标准库的日志包一起使用,只需在应用程序启动时将其传递到 SetOutput 函数中即可。
log.SetOutput(&lumberjack.Logger{ Filename: "/var/log/myapp/foo.log", MaxSize: 500, // megabytes MaxBackups: 3, MaxAge: 28, //days Compress: true, // disabled by default })
如果要和Zap所结合的话 需要放入到zapcore.AddSync中
zapcore.AddSync(&lumberjack.Logger{ Filename: "/var/log/myapp/foo.log", MaxSize: 500, // megabytes MaxBackups: 3, MaxAge: 28, //days Compress: true, // disabled by default })
我们上文以及配置好了日志的格式以及规定了日志输出的位置 也做好了 lumberjack日志的切割
那我们该如何初始化呢
只需要声明core 然后把这三个丢进去即可
如下代码所示
core := zapcore.NewCore(getEncoder(), zapcore.NewMultiWriteSyncer(zapcore.AddSync(&lumberjack.Logger{ Filename: "/var/log/myapp/foo.log", MaxSize: 500, // megabytes MaxBackups: 3, MaxAge: 28, //days Compress: true, // disabled by default }) , zapcore.AddSync(os.Stdout)), zapcore.DebugLevel) zap.New(core).Sugar()
当然 会发现 我还加了一个值 zapcore.AddSync(os.Stdout))
这句代码是代表除了输出到文件中还会输出到终端中,完成多个终端的输出
package conf import ( "fmt" "github.com/natefinch/lumberjack" "github.com/spf13/viper" "go.uber.org/zap" "go.uber.org/zap/zapcore" "os" "path/filepath" "time" ) func InitLogger() *zap.SugaredLogger { logMode := zapcore.InfoLevel if viper.GetBool("model.development") { logMode = zapcore.DebugLevel } // 第一个参数是输出的格式 第二个参数 输出的位置 //zapcore.NewMultiWriteSyncer 输出到多个终端 比如 文件 console中 core := zapcore.NewCore(getEncoder(), zapcore.NewMultiWriteSyncer(getWriterSyncer(), zapcore.AddSync(os.Stdout)), logMode) return zap.New(core).Sugar() } // def 输出日志的格式 func getEncoder() zapcore.Encoder { encoderConfig := zap.NewDevelopmentEncoderConfig() { // LevelKey值变为 level encoderConfig.LevelKey = "level" // MessageKey值变为 msg encoderConfig.MessageKey = "msg" // TimeKey值 变成time encoderConfig.TimeKey = "time" // 把输出的info 变成INFO 只需要丢对象 不许执行 encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder // 对时间进行格式化处理 encoderConfig.EncodeTime = func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) { encoder.AppendString(t.Local().Format("2006-01-02 15:04:05")) } } return zapcore.NewJSONEncoder(encoderConfig) } // def 日志要输出到什么地方 func getWriterSyncer() zapcore.WriteSyncer { stSeparator := string(filepath.Separator) stRootDir, _ := os.Getwd() stLogFilePath := stRootDir + stSeparator + "log" + stSeparator + time.Now().Format("2006-01-02") + ".log" fmt.Println(stLogFilePath) // 日志分割 hook := lumberjack.Logger{ Filename: stLogFilePath, // 日志文件路径,默认 os.TempDir() MaxSize: viper.GetInt("log.MaxSize"), // 每个日志文件保存500M,默认 100M MaxBackups: viper.GetInt("log.MaxBackups"), // 保留3个备份,默认不限 MaxAge: viper.GetInt("log.MaxAge"), // 保留28天,默认不限 Compress: viper.GetBool("log.Compress"), // 是否压缩,默认不压缩 } return zapcore.AddSync(&hook) }