Go语言使用zap日志库

安装Zap日志库

go get -u go.uber.org/zap

配置Zap Logger

Zap提供了两种类型的日志记录器—Sugared LoggerLogger

在性能很好但不是很关键的上下文中,使用SugaredLogger。它比其他结构化日志记录包快4-10倍,并且支持结构化和 printf 风格的日志记录。

在每一微秒和每一次内存分配都很重要的上下文中,使用Logger。它甚至比SugaredLogger更快,内存分配次数也更少,但它只支持强类型的结构化日志记录。

Logger

  • 通过调用zap.NewProduction()/zap.NewDevelopment()或者zap.Example()创建一个Logger。
  • 上面的每一个函数都将创建一个logger。唯一的区别在于它将记录的信息不同。例如production logger默认记录调用函数信息、日期和时间等。
  • 通过Logger调用Info/Error等。
  • 默认情况下日志都会打印到应用程序的终端界面。
package main

import (
	"go.uber.org/zap"
	"net/http"
)

var logger *zap.Logger

func main() {
	InitLogger()
	// Sync 调用底层Core的 Sync 方法,刷新所有缓冲的日志条目。应用程序应注意在退出之前调用 Sync。
	defer logger.Sync()

	// 向指定 URL 发送 GET 请求,根据成功或出错结果打印日志信息
	simpleHttpGet("www.baidu.com")
	simpleHttpGet("http://www.baidu.com")
}

func InitLogger() {
	// 通过 zap.NewProduction() 创建一个 logger
	logger, _ = zap.NewProduction()
}

func simpleHttpGet(url string) {
	resp, err := http.Get(url)
	if err != nil {
		logger.Error(
			"Error fetching url..",  // 输出自定义错误提示
			zap.String("url", url),  // 有关该错误的关键信息
			zap.Error(err))			// 有关该错误的关键信息
	} else {
		logger.Info("Success..",
			zap.String("statusCode", resp.Status),
			zap.String("url", url))
		resp.Body.Close()
	}
}

image-20220604020158088

可以看到打印了该日志的级别,花费时间,调用位置,以及我们自定义输出的错误信息。

日志记录器方法的语法:

func (log *Logger) MethodXXX(msg string, fields ...Field) 

其中MethodXXX是一个可变参数函数,可以是Info / Error/ Debug / Panic等。每个方法都接受一个消息字符串和任意数量的zapcore.Field 参数。

每个zapcore.Field其实就是一组键值对参数。

Sugared Logger

Sugar 包装了 Logger 以提供更符合人们使用习惯但速度稍慢的 API。对 Logger 进行加糖非常便宜,因此单个应用程序同时使用 Loggers 和 SugaredLoggers 是合理的,在性能敏感代码的边界上在它们之间进行转换。

package main

import (
	"go.uber.org/zap""net/http"
)

var sugarLogger *zap.SugaredLogger

func main() {
	InitLogger()
	// Sync 调用底层Core的 Sync 方法,刷新所有缓冲的日志条目。应用程序应注意在退出之前调用 Sync。
	defer sugarLogger.Sync()

	// 向指定 URL 发送 GET 请求,根据成功或出错结果打印日志信息
	simpleHttpGet("www.baidu.com")
	simpleHttpGet("http://www.baidu.com")
}

func InitLogger() {
	logger, _ := zap.NewProduction()
	sugarLogger = logger.Sugar()
}

func simpleHttpGet(url string) {
	resp, err := http.Get(url)
	if err != nil {
		sugarLogger.Errorf(
			"Error fetching url..",
			zap.String("url", url),
			zap.Error(err))
	} else {
		sugarLogger.Infof("Success..",
			zap.String("statusCode", resp.Status),
			zap.String("url", url))
		resp.Body.Close()
	}
}

image-20220604020857692

定制logger

接下来我们将不使用默认的 zap 配置,而是使用自定义的配置。这主要靠0

func New(core zapcore.Core, options ...Option) *Logger 方法来实现。

New 从提供的 zapcore 构造一个新的 Logger 。如果传递的 zapcore.Core 为 nil,则回退到使用无操作实现。

logger := zap.New(core)

我们现在要替换掉之前的 InitLogger 函数

func InitLogger() {
	writeSyncer := getLogWriter()
	encoder := getEncoder()
	// 需传入Encoder、WriterSyncer、Log Level
	core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)
	// 使用zap.New(…)方法来手动传递所有配置
	logger := zap.New(core)
	sugarLogger = logger.Sugar()
}
// 使用JSON格式写入日志
func getEncoder() zapcore.Encoder {
	return zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
}

// 将日志写到 test.log 文件中
func getLogWriter() zapcore.WriteSyncer {
	file, _ := os.Create("./test.log")
	return zapcore.AddSync(file)
}

image-20220604144518586

更换写入日志的格式

将 JSON Encoder 更改为普通的 Log Encoder

// 使用不同格式写入日志
func getEncoder() zapcore.Encoder {
	//return zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
	return zapcore.NewConsoleEncoder(zap.NewProductionEncoderConfig())
}

image-20220604154119114

可以看到日志文件中的格式发生了改变,不再是之前的 JSON 格式了

更加详细的配置

我们将要增添如下的配置

  • 将时间编码成人能看懂的形式
  • 在日志文件中记录日志级别
// 自定义日志格式
func getEncoder() zapcore.Encoder {
	encoderConfig := zap.NewProductionEncoderConfig()
	// ISO8601TimeEncoder 序列化时间。以毫秒为精度的 ISO8601 格式字符串的时间。
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
	// CapitalLevelEncoder 将Level序列化为全大写字符串。例如, InfoLevel被序列化为“INFO”。
	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
	return zapcore.NewConsoleEncoder(encoderConfig)
}

日志增添调用函数的信息

// 添加将调用函数信息记录到日志中的功能。
logger := zap.New(core, zap.AddCaller())

image-20220604155218681

完整代码

package main

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"net/http"
	"os"
)

var sugarLogger *zap.SugaredLogger

func main() {
	InitLogger()
	// Sync 调用底层Core的 Sync 方法,刷新所有缓冲的日志条目。应用程序应注意在退出之前调用 Sync。
	defer sugarLogger.Sync()

	// 向指定 URL 发送 GET 请求,根据成功或出错结果打印日志信息
	simpleHttpGet("www.baidu.com")
	simpleHttpGet("http://www.baidu.com")
}

func InitLogger() {
	// 写入位置
	writeSyncer := getLogWriter()
	// 编码格式
	encoder := getEncoder()
	// 需传入Encoder、WriterSyncer、Log Level
	core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)
	// 使用zap.New(…)方法来手动传递所有配置
	// 增加 Caller 信息
	logger := zap.New(core, zap.AddCaller())
	sugarLogger = logger.Sugar()
}

// 自定义日志格式
func getEncoder() zapcore.Encoder {
	encoderConfig := zap.NewProductionEncoderConfig()
	// ISO8601TimeEncoder 序列化时间。以毫秒为精度的 ISO8601 格式字符串的时间。
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
	// CapitalLevelEncoder 将Level序列化为全大写字符串。例如, InfoLevel被序列化为“INFO”。
	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
	return zapcore.NewConsoleEncoder(encoderConfig)
}

// 将日志写到 test.log 文件中
func getLogWriter() zapcore.WriteSyncer {
	file, _ := os.Create("./test.log")
	return zapcore.AddSync(file)
}

func simpleHttpGet(url string) {
	resp, err := http.Get(url)
	if err != nil {
		sugarLogger.Errorf(
			"Error fetching url..",
			zap.String("url", url),
			zap.Error(err))
	} else {
		sugarLogger.Infof("Success..",
			zap.String("statusCode", resp.Status),
			zap.String("url", url))
		resp.Body.Close()
	}
}

切割日志

执行下面的命令安装Lumberjack

go get -u github.com/natefinch/lumberjack

如果只用一个文件记录日志,那么这个文件会越来越大,最后也不方便定位错误。所以我们需要分割日志,比如按照时间来分割,一个日志文件记录一天的信息。

// 在zap中加入Lumberjack支持
func getLogWriter() zapcore.WriteSyncer {
	lumberJackLogger := &lumberjack.Logger{
		Filename:   "./test.log", 	// 日志文件的位置
		MaxSize:    1,     			// 以 MB 为单位
		MaxBackups: 5,     			// 在进行切割之前,日志文件的最大大小(以MB为单位)
		MaxAge:     30,    			// 保留旧文件的最大天数
		Compress:   false, 			// 是否压缩/归档旧文件
	}
	return zapcore.AddSync(lumberJackLogger)
}

完整代码

package main

import (
	"github.com/natefinch/lumberjack"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"net/http"
)

var (
	sugarLogger *zap.SugaredLogger
)

func main() {
	InitLogger()
	defer sugarLogger.Sync() // 刷新流,写日志到文件中
    // 循环写入日志,这里为了达到切割要求循环记录了 100000 次
	for i := 0; i < 100000; i++ {
		sugarLogger.Infof("this is a test")
	}

}

func InitLogger() {
	writeSyncer := getLogWriter()
	encoder := getEncoder()
	core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)
	logger := zap.New(core, zap.AddCaller())
	sugarLogger = logger.Sugar()
}

func getEncoder() zapcore.Encoder {
	encoderConfig := zap.NewProductionEncoderConfig()
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
	return zapcore.NewConsoleEncoder(encoderConfig)
}

// 在zap中加入Lumberjack支持
func getLogWriter() zapcore.WriteSyncer {
	lumberJackLogger := &lumberjack.Logger{
		Filename:   "./test.log",
		MaxSize:    1,     // 以 MB 为单位
		MaxBackups: 5,     // 在进行切割之前,日志文件的最大大小(以MB为单位)
		MaxAge:     30,    // 保留旧文件的最大天数
		Compress:   false, // 是否压缩/归档旧文件
	}
	return zapcore.AddSync(lumberJackLogger)
}

image-20220604165330033

参考

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值