参考文档:https://liwenzhou.com/posts/Go/zap/
无论是软件开发的调试阶段还是软件上线之后的运行阶段,日志始终都是十分重要的一个环节,咱们也应该养成在程序中记录日志的好习惯。
Go 语言内置的log
包实现了简略的日志服务。本文介绍了规范库log
的根本应用和第三日志库的选型和应用。
1、原生Logger
log 包定义了 Logger 类型,该类型提供了一些格式化输入的办法。本包也提供了一个预约义的 “规范”logger,能够通过调用函数Print系列
(Print|Printf|Println)、Fatal系列
(Fatal|Fatalf|Fatalln)、和Panic系列
(Panic|Panicf|Panicln)来应用,比自行创立一个 logger 对象更容易应用。
例如,咱们能够像上面的代码一样间接通过log
包来调用下面提到的办法,默认它们会将日志信息打印到终端界面:
package mainimport ( "log")func main() { log.Println("这是一条很一般的日志。") v := "很一般的" log.Printf("这是一条%s日志。\n", v) log.Fatalln("这是一条会触发fatal的日志。") log.Panicln("这是一条会触发panic的日志。")}
编译并执行下面的代码会失去如下输入:
2017/06/19 14:04:17 这是一条很一般的日志。2017/06/19 14:04:17 这是一条很一般的日志。2017/06/19 14:04:17 这是一条会触发fatal的日志。
logger 会打印每条日志信息的日期、工夫,默认输入到零碎的规范谬误。Fatal 系列函数会在写入日志信息后调用 os.Exit(1)。Panic 系列函数会在写入日志信息后 panic。
1.1 配置 logger配置
默认状况下的 logger 只会提供日志的工夫信息,然而很多状况下咱们心愿失去更多信息,比方记录该日志的文件名和行号等。log
规范库中为咱们提供了定制这些设置的办法。log
规范库中的Flags
函数会返回规范 logger 的输入配置,而SetFlags
函数用来设置规范 logger 的输入配置。
func Flags() intfunc SetFlags(flag int)
1.1.1 flag 选项
log
规范库提供了如下的 flag 选项,它们是一系列定义好的常量。
const ( // 管制输入日志信息的细节,不能管制输入的程序和格局。 // 输入的日志在每一项后会有一个冒号分隔:例如2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message Ldate = 1 << iota // 日期:2009/01/23 Ltime // 工夫:01:23:23 Lmicroseconds // 微秒级别的工夫:01:23:23.123123(用于加强Ltime位) Llongfile // 文件全路径名+行号: /a/b/c/d.go:23 Lshortfile // 文件名+行号:d.go:23(会笼罩掉Llongfile) LUTC // 应用UTC工夫 LstdFlags = Ldate | Ltime // 规范logger的初始值)
上面咱们在记录日志之前先设置一下规范 logger 的输入选项如下:
func main() { log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate) log.Println("这是一条很一般的日志。")}
编译执行后失去的输入后果如下:
2017/06/19 14:05:17.494943 .../log_demo/main.go:11: 这是一条很一般的日志。
1.1.2 配置日志前缀
log
规范库中还提供了对于日志信息前缀的两个办法:
func Prefix() stringfunc SetPrefix(prefix string)
其中Prefix
函数用来查看规范 logger 的输入前缀,SetPrefix
函数用来设置输入前缀。
func main() { log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate) log.Println("这是一条很一般的日志。") log.SetPrefix("[小王子]") log.Println("这是一条很一般的日志。")}
下面的代码输入如下:
[小王子]2017/06/19 14:05:57.940542 .../log_demo/main.go:13: 这是一条很一般的日志。
这样咱们就可能在代码中为咱们的日志信息增加指定的前缀,不便之后对日志信息进行检索和解决。
1.1.3 配置日志输入地位
func SetOutput(w io.Writer)
SetOutput
函数用来设置规范 logger 的输入目的地,默认是规范谬误输入。
例如,上面的代码会把日志输入到同目录下的xx.log
文件中。
func main() { logFile, err := os.OpenFile("./xx.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) if err != nil { fmt.Println("open log file failed, err:", err) return } log.SetOutput(logFile) log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate) log.Println("这是一条很一般的日志。") log.SetPrefix("[小王子]") log.Println("这是一条很一般的日志。")}
如果你要应用规范的 logger,咱们通常会把下面的配置操作写到init
函数中。
func init() { logFile, err := os.OpenFile("./xx.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) if err != nil { fmt.Println("open log file failed, err:", err) return } log.SetOutput(logFile) log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate)}
1.2 创立 logger
log
规范库中还提供了一个创立新 logger 对象的构造函数–New
,反对咱们创立本人的 logger 示例。New
函数的签名如下:
func New(out io.Writer, prefix string, flag int) *Logger
New 创立一个 Logger 对象。其中,参数 out 设置日志信息写入的目的地。参数 prefix 会增加到生成的每一条日志后面。参数 flag 定义日志的属性(工夫、文件等等)。
举个例子:
func main() { logger := log.New(os.Stdout, "<New>", log.Lshortfile|log.Ldate|log.Ltime) logger.Println("这是自定义的logger记录的日志。")}
将下面的代码编译执行之后,失去后果如下:
<New>2017/06/19 14:06:51 main.go:34: 这是自定义的logger记录的日志。
1.3 总结
Go 内置的 log 库性能无限,例如无奈满足记录不同级别日志的状况,咱们在理论的我的项目中依据本人的须要抉择应用第三方的日志库,如 logrus、zap 等。
2、第三方日志库
2.1 日志选型需要整顿
- 日志写入性能
- 日志级别拆散,并且可拆散成多个日志文件
- 可读性与结构化,Json格局或有分隔符,不便后续的日志采集、监控等
- 可能打印根本信息,如调用文件 / 函数名和行号,日志工夫等
- 日志书写敌对,反对通过context主动log trace等
- 文件切割,可按小时、天进行日志拆分,或者按文件大小
- 文件定时删除
- 开源性,与其余开源框架反对较好
- 多输入 - 同时反对规范输入,文件等
2.2 日志比对
2.2.1 性能比对
参考文档:
- https://www.jianshu.com/p/38a67ab593ee
- https://zhuanlan.zhihu.com/p/141321801
- zerolog:https://zhuanlan.zhihu.com/p/136296821
搜看的许多日志框架,最初剩下两款目前显著性能比拟好的Uber开源的Zap和ZeroLog,参考github中开源我的项目日志援用状况和日志周边框架反对最终选用Zap。
需要点 | go.uber.org/zap(国内一些开源我的项目见得比拟多、性能也不错、举荐) | github.com/rs/zerolog |
---|---|---|
日志写入性能 | 较高 | 高 |
日志级别拆散 | 反对 | 反对 |
可读性 (Json格局或有分隔符,不便后续的日志采集、监控等) | json格局 | json格局 |
易用性:接入不便,书写不便(格式化),可Hook注入trace_id等 | 主动接入工夫、代码信息、日志级别,反对Hook | 可反对接入工夫、代码信息、日志级别等,反对Hook |
文件切割 (可按工夫、文件大小日志拆分) | 不反对,可通过lumberjack实现 | 反对 |
定时删除 | 反对 | 反对 |
多输入 - 同时反对规范输入,文件等 | 反对 | 反对 |
2.2.3 性能数据比对
依据Uber-go Zap的文档,它的性能比相似的结构化日志包更好——也比规范库更快。 以下是Zap公布的基准测试信息
记录一条音讯和10个字段:
记录一个动态字符串,没有任何上下文或printf格调的模板:
下一篇咱们会来讲讲高性能日志框架Zap的应用,以及如何满足咱们对于日志框架丰盛的应用需要,咱们下期见,Peace
我是简凡,一个励志用最简略的语言,形容最简单问题的新时代农民工。求点赞,求关注,如果你对此篇文章有什么纳闷,欢送在我的微信公众号中留言,我还能够为你提供以下帮忙:
- 帮忙建设本人的常识体系
- 互联网实在高并发场景实战解说
- 不定期分享Golang、Java相干业内的经典场景实际
我的博客:https://besthpt.github.io/
我的微信:bestbear666
微信公众号: