在GO项目中使用Uber-zap日志框架

现在需要把一个日志框架加入到新的项目中,对比了一下GO语言里的几个日志框架,最后发现zap是个不错的选择。
https://github.com/uber-go/zap
官网也把zap和其他框架做了一些对比,看起挺不错。

不过在集成到Cobra里的过程中遇到了一点点小坑,记录一下。

utils/zap_logger.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package utils

import (
"os"
"sync"

"github.com/natefinch/lumberjack"
"github.com/spf13/viper"

"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)

var sugarLogger *zap.SugaredLogger

func getEncoder() zapcore.Encoder {
encoderConfig := zap.NewProductionEncoderConfig()
// The format time can be customized
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
return zapcore.NewConsoleEncoder(encoderConfig)
}

// Save file log cut
func getLogWriter() zapcore.WriteSyncer {
lumberJackLogger := &lumberjack.Logger{
Filename: "./nuke.log", // Log name
MaxSize: 10, // File content size, MB
MaxBackups: 5, // Maximum number of old files retained
MaxAge: 30, // Maximum number of days to keep old files
Compress: false, // Is the file compressed
}
return zapcore.AddSync(lumberJackLogger)
}

func InitLog() *zap.SugaredLogger {
var allCore []zapcore.Core
writeSyncer := getLogWriter()
encoder := getEncoder()

consoleDebugging := zapcore.Lock(os.Stdout)
// for human operators.
consoleEncoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())

log_level := viper.GetString("log")

if log_level == zapcore.DebugLevel.String() {
allCore = append(allCore, zapcore.NewCore(consoleEncoder, consoleDebugging, zapcore.DebugLevel))
allCore = append(allCore, zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel))
} else {
allCore = append(allCore, zapcore.NewCore(consoleEncoder, consoleDebugging, zapcore.InfoLevel))
allCore = append(allCore, zapcore.NewCore(encoder, writeSyncer, zapcore.InfoLevel))
}

core := zapcore.NewTee(allCore...)
// Print function lines
logger := zap.New(core).WithOptions(zap.AddCaller())
return logger.Sugar()
}

var once sync.Once

func SugaredLogger() *zap.SugaredLogger {
once.Do(func() {
sugarLogger = InitLog()
})
return sugarLogger
}

代码中使用了单例,尝试过使用init(), preRun和postRun,发现都无法正常读取viper里的值,很明显是因为初始化先后顺序的问题。
不太确定最佳的解决方案是啥,但是这里弄一个单例,看似是最保险的。

初始后,在core里放了两个对象,可以同时输出到控制台和文件中,文件加了循环。

在别的文件用的时候

1
2
3
utils.SugaredLogger().Infof("info log")
utils.SugaredLogger().Debugf("debug format log")
utils.SugaredLogger().Debug("debug log")
Notice: 正常情况下,这里会有一个基于utteranc.es的留言系统,如果看不到,可能需要科学上网方式。