
我们都知道哈,项目在开发阶段,出现问题,我们一般会存日志来进行分析问题,这是非常有效的,上线后更需要依赖日志了,所以查看日志是非常重要的。
那么我们需要怎么样的日志呢?
其实在我们的go语言里面的提供了很多的日志库,但是我们需要一个好的日志能够提供以下几个条件:
能打印最基本的信息,例如调用的文件,函数名称,行号,日志时间等等。支持不同的日志级别,例如: info 、 debug 、 error 等等能够将记录的日志保存在文件里面,并且可以根据时间或者文件大小来切割日志文件
而zap就完全满足了,他非常的高效,并且是结构化的,分级的go日志库。
为什么选择zap日志这个问题好哈!两个点:
结构化日志记录并且是printf风格的日志记录真的 非常的快 ,非常的高效,啊哈哈根据Uber-go Zap的文档,它的性能比类似的结构化日志包更好——也比标准库更快。 以下是Zap发布的基准测试信息
记录一条消息和10个字段: 记录一个静态字符串,没有任何上下文或printf风格的模板: 完虐呀家人们!!! zap的安装 直接用工具导入,或者doc命令导入都可以哦!go get -u go.uber.org/zap
zap的基本配置
Zap提供了两种类型的日志记录器—Sugared Logger 和 Logger 。
在性能很好但不是很关键的上下文中,使用 SugaredLogger 。它比其他结构化日志记录包快4-10倍,并且支持结构化和printf风格的日志记录。
在每一微秒和每一次内存分配都很重要的上下文中,使用 Logger 。它甚至比 SugaredLogger 更快,内存分配次数也更少,但它只支持强类型的结构化日志记录。
Logger
可以通过调用zap.NewProduction() / zap.NewDevelopment() 来创建又给Logger
两种方式都可以,区别就是打印出来的格式不一样
NewDevelopment 是以 空格分开 的形式展示
NewProduction 使用的是 json格式 ,键值对的形式 展示出来
SugaredLogger
这个就直接使用logger.Sugar()即可,啥使用都管用他们基本上相同,唯一的不同的就是SugaredLogger可以用printf格式记录语句例如:
sugarLogger.Infof("Success! statusCode = %s for URL %s", resp.Status, url)
自定义logger
那么不想打印在终端怎么办呢,那我们只有自定义配置了
那我们只能使用zap.New(…) 方法来手动传递所有配置
我们可以看到需要一个zapcore.Core的参数,所以我们再进去看看
我们可以看到这个是一个接口,里面有个newCore的方法可以创建一个core。源码里面可以明显的看到哈,只要我们给三个参数,就可以得到一个logger了,那么这三个参数分别表示上面呢?
Encoder : 编码器(如何写入日志)。我们将使用开箱即用的NewJSONEncoder(),并使用预先设置的ProductionEncoderConfig()。
// core 三个参数之 编码
func getEncoder() zapcore.Encoder {
return zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
}
WriteSyncer : 指定日志将写到哪里去。但是打开的类型不一样,文件打开的是io.writer类型,而我们需要的是WriteSyncer,所以我们使用zapcore.AddSync()函数来进行一个转换。
// core 三个参数之 路径
func getLogWriter() zapcore.WriteSyncer {
file,_ := os.Create("E:/test.log")
return zapcore.AddSync(file)
}
LevelEnabler: 这个就是我们所需要打印的日志等级设置了,通过它来动态的保存日志,比如上线后我们error以下的日志就不打印了!
var logger *zap.Logger
var sugarLogger *zap.SugaredLogger
func InitLogger() {
encoder := getEncoder()
writerSyncer := getLogWriter()
core := zapcore.NewCore(encoder,writerSyncer,zapcore.DebugLevel)
logger = zap.New(core)
sugarLogger = logger.Sugar()
}
func getEncoder() zapcore.Encoder {
return zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
}
func getLogWriter() zapcore.WriteSyncer {
file,_ := os.Create("E:/test.log")
return zapcore.AddSync(file)
}
我们来跑一个例子:
好用!!!只有存在文件里面才方便我们往后的查看呢!!!
将JSON Encoder更改为普通的Log Encoder
我们采用编码格式的时候,采用的json格式满,可以有的人习惯看空格呀,怎么办,那就换一个呗,人家zap也是提供了的
// core 三个参数之 编码
func getEncoder() zapcore.Encoder {
return zapcore.NewConsoleEncoder(zap.NewProductionEncoderConfig())
}
非常的ok哈!!!但是这个时间,,,还是有点不敬人意哈,所以我们好需要调整以下
编码配置优化
那么我们就需要对 encoderConfig 进行一个自定义配置了
func getEncoder() zapcore.Encoder {
encoderConfig := zap.NewProductionEncoderConfig()
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
return zapcore.NewConsoleEncoder(encoderConfig)
}
修改时间编码器在日志文件中使用大写字母记录日志级别
是不是感觉又好很多了!那么我们怎么来获取 调用的文件,函数名称,行号呢?也很简单哈,我们再new一个zap 的时候加个 zap.AddCaller() 即可!
logger := zap.New(core, zap.AddCaller())
来看看效果吧!
这样子,我们基本上就可以进行一个很好的使用体验了哈!!!你以为没了? 不,还有最重要的一点,文件的切割,但是很可惜,zap没有这玩意,所以我们只有采用第三方库来实现拉!
使用Lumberjack进行日志切割归档
为了实现切割功能呢,我们采用第三方库注意:Zap本身不支持切割归档日志文件
Lumberjack
Lumberjack的安装
老规矩哈,要是有依赖漏了就 go mod tidy 一下哈!!!
go get -u github.com/natefinch/lumberjack
zap logger中加入Lumberjack
要在zap中加入Lumberjack支持,我们需要修改WriteSyncer代码。我们将按照下面的代码修改getLogWriter()函数:
func getLogWriter() zapcore.WriteSyncer {
lumberJackLogger := &lumberjack.Logger{
Filename: "./test.log",
MaxSize: 10,
MaxBackups: 5,
MaxAge: 30,
Compress: false,
}
return zapcore.AddSync(lumberJackLogger)
}
分别表示上面意思呢?
Lumberjack Logger采用以下属性作为输入:
| 属性 | 含义 |
|---|---|
| Filename | 日志文件的位置,也就是路径 |
| MaxSize | 在进行切割之前,日志文件的最大大小(以MB为单位) |
| MaxBackups | 保留旧文件的最大个数 |
| MaxAges | 保留旧文件的最大天数 |
| Compress | 是否压缩/归档旧文件 |
到这里我们的代码就完成了!!!
来看看总代码:
package main
import (
"github.com/natefinch/lumberjack"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"net/http"
)
var logger *zap.Logger
var sugarLogger *zap.SugaredLogger
func InitLogger() {
encoder := getEncoder()
writerSyncer := getLogWriter()
core := zapcore.NewCore(encoder,writerSyncer,zapcore.DebugLevel)
logger = zap.New(core,zap.AddCaller())
sugarLogger = logger.Sugar()
}
// core 三个参数之 编码
func getEncoder() zapcore.Encoder {
encoderConfig := zap.NewProductionEncoderConfig()
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
return zapcore.NewConsoleEncoder(encoderConfig)
}
// core 三大核心之 路径
func getLogWriter() zapcore.WriteSyncer {
lumberJackLogger := &lumberjack.Logger{
Filename: "E:/test.log",
MaxSize: 10,
MaxBackups: 5,
MaxAge: 30,
Compress: false,
}
return zapcore.AddSync(lumberJackLogger)
}
func main() {
InitLogger()
defer logger.Sync()
simpleHttpGet("www.baidu.com")
simpleHttpGet("http://www.baidu.com")
}
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()
}
}
这里我们设置的是 日志文件每 5MB 会切割并且在当前目录下最多保存 5 个备份,并且会将旧文档保存30天。
到这里,我们就完成了zap日志程序集成到项目中了,还是很方便简单的哈!
至于测试数据,大家可以跑几个 goroutine来试试,把MaxSize调小一点,即可看到切分的效果哦!!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)