logger
日志简介
在日常工作中,打日志是很常见的动作。毕竟不打日志,从内部来讲,一旦出问题,定位、排查都会变的非常困难。谁也不想大半夜在那靠猜解决问题。
在其他方面,对日志的存储的内容、时长、安全均有不同程度的合规要求,应对客户诉求和提单上门的事件。
日志好不好用,就成了重要的诉求了
why第三方库
golang的log fmt库用起来很方便,但是有局限性
在正式项目中,大多是优先使用几个爆款第三方库,例如:Logrus、Zap、zerolog。而标准库 log,在临时调试,屏幕输出的场景居多,占比较少。
这问题出在了哪里?主要集中在以下方面:
- 没有日志分级:不便于分类、定位、排查问题,例如:Error、Warn、Info、Debug 等。
- 没有结构化日志:只提供格式化日志,不提供结构化,不便于程序读取、解析,例如:Json 格式。
- 没有扩展性,灵活度差:标准库 log 的日志输出都是固定格式,没有一个 Logger 接口规范,让大家都遵守,以至于现在社区纯自然演进,难互相兼容。
除此之外,在用户场景上,有着不包含上下文(context)信息、性能不够强劲、无法引入自定义插件等扩展诉求。基本上第三方库均有实现的,基本都用户的痛点之一。
第三方logger性能对比
zap主打高性能, 结合性能排名,可以看到不论怎么比,zap都是独树一帜
因此我们就重点介绍下zap的用法
zap的简单使用
#install
go get -u go.uber.org/zap
注意:zap与时俱进,支持的golang版本为最近的2个minor version, documentation
zap提供了2中类型的日志记录器:
- Sugared Logger
- Logger
在性能很好但不是很关键的上下文,使用SugaredLogger
,它比其他结构化日志记录包快 4-10 倍,并且支持结构化和printf风格的日志记录
logger, _ := zap.NewProduction()
defer logger.Sync() // flushes buffer, if any
url := "www.scott-xiong.com"
sugar := logger.Sugar()
sugar.Infow("failed to fetch URL",
// Structured context as loosely typed key-value pairs.
"url", url,
"attempt", 3,
"backoff", time.Second,
)
sugar.Infof("Failed to fetch URL: %s", url)
sugar.Error("some error")
sugar.Errorf("error:%s", "some error")
sugar.Fatal("some fetal error")
sugar.Fatalf("error:%s","some fetal error")
在每一微妙和每一次内存分配都很重要的上下文中,使用Logger
,它比SugaredLogger
更快,内存分配次数更少,但是它只支持强类型的结构化日志记录(相比SugaredLogger
,少了反射)
logger, _ := zap.NewProduction()
defer logger.Sync()
url := "www.scott-xiong.com"
logger.Info("failed to fetch URL",
// Structured context as strongly typed Field values.
zap.String("url", url),
zap.Int("attempt", 3),
zap.Duration("backoff", time.Second),
)
将数据同时输入到文件和终端中:
package main
import (
"go.uber.org/zap"
"time"
)
func newLogger() (*zap.Logger, error) {
cfg := zap.NewProductionConfig()
cfg.OutputPaths = []string{
"stderr",//标准错误输出 stderr, stdout 2选1
//"stdout", 标准输入输出
"./my.log",//建议写成绝对路径
}
return cfg.Build()
}
func main() {
logger, _ := newLogger() //生产环境
defer logger.Sync() // flushes buffer, if any
sugar := logger.Sugar()
url := "www.scott-xiong.com"
sugar.Infow("failed to fetch URL",
// Structured context as loosely typed key-value pairs.
"url", url,
"attempt", 3,
"backoff", time.Second,
)
sugar.Infof("Failed to fetch URL: %s", url)
sugar.Error("some error")
sugar.Errorf("error:%s", "some error")
sugar.Fatal("some fetal error")
sugar.Fatalf("error:%s", "some fetal error")
}