参考文档: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 日志选型需要整顿

  1. 日志写入性能
  2. 日志级别拆散,并且可拆散成多个日志文件
  3. 可读性与结构化,Json格局或有分隔符,不便后续的日志采集、监控等
  4. 可能打印根本信息,如调用文件 / 函数名和行号,日志工夫等
  5. 日志书写敌对,反对通过context主动log trace等
  6. 文件切割,可按小时、天进行日志拆分,或者按文件大小
  7. 文件定时删除
  8. 开源性,与其余开源框架反对较好
  9. 多输入 - 同时反对规范输入,文件等

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
微信公众号: