Go log package 选择
Table of Contents
可能是 Go 尚年轻,行业对 Go 的应用领域还比较宽泛,也可能是开源的缘故,Go package 普遍造轮子的现象比较明显。
对于日志包也是如此,没有像 google/glog 和 log4plus 之于 C++ 这么权威。尝试了一些的 Go logging package,结论如下:
1. 标准库
功能较少,不同级别的日志区分不开,小的测试项目可以取代 fmt 来 debug。
2. google/glog
google 类似 C++ 日志版本的 Go 版本,性能较好,使用也比较简单。
- 优点:代码很短,性能好,易用性较好,稳定;K8s 内置的就是 glog,不过最近好像要基于 glog 做二次开发 klog;
- 缺点:已经四五年没更新了···,日志级别区分的比较乱,需要二次封装
3. sirupsen/logrus
结构化的,可插拔的日志系统。
- 业内评价较高,易用性好,定制化也很强,人性化。
- 支持 hook,logrus-hook 我是自己写的 hook
4. uber-go/zap
Uber 开源的日志系统。
- 性能 非常 好
- 支持 Hook
可能是设计就是为了设计之初就是为了高性能,定制性很强,就是非常不人性化,以至于不知道怎么定制···,好在有这个 sandipb/zap-examples
性能相比:
zap > glog > logrus > log
,值得一提的是,zap 是远大于 glog 和 logrus 的。
5. 结论
- 高性能的系统,推荐使用 zap;
- 业务系统使用 zap/logrus,glog 的日志级别(
V()
)很容易误导开发人员,体验并不是很好。
6. 初始化范例
6.1. logrus
func init() { // TEXT logrus.SetFormatter(&logrus.TextFormatter{ ForceColors: false, DisableColors: true, FullTimestamp: true, TimestampFormat: "2006-01-02 15:04:05.000", CallerPrettyfier: func(frame *runtime.Frame) (function string, file string) { ss := strings.Split(frame.Function, ".") function = ss[len(ss)-1] file = fmt.Sprintf("%s:%d", filepath.Base(frame.File), frame.Line) return function, file }, }) // JSON logrus.SetFormatter(&logrus.JSONFormatter{ TimestampFormat: "2006-01-02 15:04:05.000", CallerPrettyfier: func(frame *runtime.Frame) (function string, file string) { ss := strings.Split(frame.Function, ".") function = ss[len(ss)-1] file = fmt.Sprintf("%s:%d", filepath.Base(frame.File), frame.Line) return function, file }, // FieldMap: logrus.FieldMap{ // logrus.FieldKeyTime: "@timestamp", // logrus.FieldKeyLevel: "@level", // logrus.FieldKeyMsg: "@message", // logrus.FieldKeyFunc: "@caller", // }, PrettyPrint: true, }) // 设置输出流 logrus.SetOutput(os.Stdout) // include calling method logrus.SetReportCaller(true) // 日志级别 logrus.SetLevel(logrus.TraceLevel) }
6.2. zap
logger, _ := zap.Config{ Encoding: "console", Level: zap.NewAtomicLevelAt(logLevel), DisableCaller: true, OutputPaths: []string{"stdout"}, EncoderConfig: zapcore.EncoderConfig{ TimeKey: "ts", LevelKey: "level", MessageKey: "msg", EncodeLevel: zapcore.CapitalLevelEncoder, EncodeTime: zapcore.RFC3339TimeEncoder, }, }.Build() zap.ReplaceGlobals(logger)