Go语言系列之日志库zap
2021-01-04 22:30
标签:文件的 问题: locate 应用程序控制 users nat als objects 开箱 在许多Go语言项目中,我们需要一个好的日志记录器能够提供下面这些功能: 它最大的优点是使用非常简单。我们可以设置任何 Zap是非常快的、结构化的,分日志级别的Go日志库。 根据Uber-go Zap的文档,它的性能比类似的结构化日志包更好——也比标准库更快。 以下是Zap发布的基准测试信息 记录一条消息和10个字段: 记录一个静态字符串,没有任何上下文或printf风格的模板: 运行下面的命令安装zap Zap提供了两种类型的日志记录器— 在性能很好但不是很关键的上下文中,使用 在每一微秒和每一次内存分配都很重要的上下文中,使用 在上面的代码中,我们首先创建了一个Logger,然后使用Info/ Error等Logger方法记录消息。 日志记录器方法的语法是这样的: 其中 每个 我们执行上面的代码会得到如下输出结果: 现在让我们使用Sugared Logger来实现相同的功能。 下面是修改过后使用 当你执行上面的代码会得到如下输出: 在本博客的后面部分,我们将更详细地讨论SugaredLogger,并了解如何进一步配置它。 我们要做的第一个更改是把日志写入文件,而不是打印到应用程序控制台。 1.Encoder:编码器(如何写入日志)。我们将使用开箱即用的 2.WriterSyncer :指定日志将写到哪里去。我们使用 3.Log Level:哪种级别的日志将被写入。 我们将修改上述部分中的Logger代码,并重写 当使用这些修改过的logger配置调用上述部分的 现在,我们希望将编码器从JSON Encoder更改为普通Encoder。为此,我们需要将 当使用这些修改过的logger配置调用上述部分的 鉴于我们对配置所做的更改,有下面两个问题: 我们要做的第一件事是覆盖默认的 接下来,我们将修改zap logger代码,添加将调用函数信息记录到日志中的功能。为此,我们将在 当使用这些修改过的logger配置调用上述部分的 这个日志程序中唯一缺少的就是日志切割归档功能。 Zap本身不支持切割归档日志文件 为了添加日志切割归档功能,我们将使用第三方库Lumberjack来实现。 执行下面的命令安装Lumberjack 要在zap中加入Lumberjack支持,我们需要修改 Lumberjack Logger采用以下属性作为输入: 最终,使用Zap/Lumberjack logger的完整示例代码如下: 执行上述代码,下面的内容会输出到文件——test.log中。 同时,可以在 至此,我们总结了如何将Zap日志程序集成到Go应用程序项目中。 Go语言系列之日志库zap 标签:文件的 问题: locate 应用程序控制 users nat als objects 开箱 原文地址:https://www.cnblogs.com/zhangyafei/p/12982839.html
Go自带log库的优势和劣势
优势
io.Writer
作为日志记录输出并向其发送要写入的日志。
劣势
Print
选项。不支持INFO
/DEBUG
等多个级别。Fatal
和Panic
os.Exit(1)
来结束程序Uber-go Zap
为什么选择Uber-go zap
Package
Time
Time % to zap
Objects Allocated
?? zap
862 ns/op
+0%
5 allocs/op
?? zap (sugared)
1250 ns/op
+45%
11 allocs/op
zerolog
4021 ns/op
+366%
76 allocs/op
go-kit
4542 ns/op
+427%
105 allocs/op
apex/log
26785 ns/op
+3007%
115 allocs/op
logrus
29501 ns/op
+3322%
125 allocs/op
log15
29906 ns/op
+3369%
122 allocs/op
Package
Time
Time % to zap
Objects Allocated
?? zap
118 ns/op
+0%
0 allocs/op
?? zap (sugared)
191 ns/op
+62%
2 allocs/op
zerolog
93 ns/op
-21%
0 allocs/op
go-kit
280 ns/op
+137%
11 allocs/op
standard library
499 ns/op
+323%
2 allocs/op
apex/log
1990 ns/op
+1586%
10 allocs/op
logrus
3129 ns/op
+2552%
24 allocs/op
log15
3887 ns/op
+3194%
23 allocs/op
安装
go get -u go.uber.org/zap
配置Zap Logger
Sugared Logger
和Logger
。SugaredLogger
。它比其他结构化日志记录包快4-10倍,并且支持结构化和printf风格的日志记录。Logger
。它甚至比SugaredLogger
更快,内存分配次数也更少,但它只支持强类型的结构化日志记录。Logger
zap.NewProduction()
/zap.NewDevelopment()
或者zap.Example()
创建一个Logger。var logger *zap.Logger
func main() {
InitLogger()
defer logger.Sync()
simpleHttpGet("www.google.com")
simpleHttpGet("http://www.google.com")
}
func InitLogger() {
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()
}
}
func (log *Logger) MethodXXX(msg string, fields ...Field)
MethodXXX
是一个可变参数函数,可以是Info / Error/ Debug / Panic等。每个方法都接受一个消息字符串和任意数量的zapcore.Field
场参数。zapcore.Field
其实就是一组键值对参数。{"level":"error","ts":1590662574.8328245,"caller":"go_Logger/main.go:31","msg":"Error fetching url..","url":"www.google.com","error":"Get www.google.com: unsupported protocol scheme \"\"","stacktrace":"main.simpleHttpGet\n\tE:/go/project/src/go_Logger/main.go:31\nmain.main\n\tE:/go/project/src/go_Logger/main.go:20\nruntime.main\n\tD:/Go/src/runtime/proc.go:203"}
{"level":"error","ts":1590662575.9375718,"caller":"go_Logger/main.go:31","msg":"Error fetching url..","url":"http://www.google.com","error":"Get http://www.google.com: dial tcp 127.0.0.1:80: connectex: No connection could be made because the target machine actively refused it.","stacktrace":"main.simpleHttpGet\n\tE:/go/project/src/go_Logger/main.go:31\nmain.main\n\tE:/go/project/src/go_Logger/main.go:21\nruntime.main\n\tD:/Go/src/runtime/proc.go:203"}
. Sugar()
方法来获取一个SugaredLogger
。SugaredLogger
以printf
格式记录语句SugaredLogger
代替Logger
的代码:var sugarLogger *zap.SugaredLogger
func main() {
InitLogger()
defer sugarLogger.Sync()
simpleHttpGet("www.google.com")
simpleHttpGet("http://www.google.com")
}
func InitLogger() {
logger, _ := zap.NewProduction()
sugarLogger = logger.Sugar()
}
func simpleHttpGet(url string) {
sugarLogger.Debugf("Trying to hit GET request for %s", url)
resp, err := http.Get(url)
if err != nil {
sugarLogger.Errorf("Error fetching URL %s : Error = %s", url, err)
} else {
sugarLogger.Infof("Success! statusCode = %s for URL %s", resp.Status, url)
resp.Body.Close()
}
}
{"level":"error","ts":1572159149.923002,"caller":"logic/temp2.go:27","msg":"Error fetching URL www.sogo.com : Error = Get www.sogo.com: unsupported protocol scheme \"\"","stacktrace":"main.simpleHttpGet\n\t/Users/q1mi/zap_demo/logic/temp2.go:27\nmain.main\n\t/Users/q1mi/zap_demo/logic/temp2.go:14\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:203"}
{"level":"info","ts":1572159150.192585,"caller":"logic/temp2.go:29","msg":"Success! statusCode = 200 OK for URL http://www.sogo.com"}
你应该注意到的了,到目前为止这两个logger都打印输出JSON结构格式。
定制logger
将日志写入文件而不是终端
zap.New(…)
方法来手动传递所有配置,而不是使用像zap.NewProduction()
这样的预置方法来创建logger。func New(core zapcore.Core, options ...Option) *Logger
zapcore.Core
需要三个配置——Encoder
,WriteSyncer
,LogLevel
。NewJSONEncoder()
,并使用预先设置的ProductionEncoderConfig()
。 zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
zapcore.AddSync()
函数并且将打开的文件句柄传进去。 file, _ := os.Create("./test.log")
writeSyncer := zapcore.AddSync(file)
InitLogger()
方法。其余方法—main()
/SimpleHttpGet()
保持不变。func InitLogger() {
writeSyncer := getLogWriter()
encoder := getEncoder()
core := zapcore.NewCore(encoder, writeSyncer, 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("./test.log")
return zapcore.AddSync(file)
}
main()
函数时,以下输出将打印在文件——test.log
中。{"level":"debug","ts":1572160754.994731,"msg":"Trying to hit GET request for www.sogo.com"}
{"level":"error","ts":1572160754.994982,"msg":"Error fetching URL www.sogo.com : Error = Get www.sogo.com: unsupported protocol scheme \"\""}
{"level":"debug","ts":1572160754.994996,"msg":"Trying to hit GET request for http://www.sogo.com"}
{"level":"info","ts":1572160757.3755069,"msg":"Success! statusCode = 200 OK for URL http://www.sogo.com"}
将JSON Encoder更改为普通的Log Encoder
NewJSONEncoder()
更改为NewConsoleEncoder()
。return zapcore.NewConsoleEncoder(zap.NewProductionEncoderConfig())
main()
函数时,以下输出将打印在文件——test.log
中。1.572161051846623e+09 debug Trying to hit GET request for www.sogo.com
1.572161051846828e+09 error Error fetching URL www.sogo.com : Error = Get www.sogo.com: unsupported protocol scheme ""
1.5721610518468401e+09 debug Trying to hit GET request for http://www.sogo.com
1.572161052068744e+09 info Success! statusCode = 200 OK for URL http://www.sogo.com
更改时间编码并添加调用者详细信息
ProductionConfig()
,并进行以下更改:
func getEncoder() zapcore.Encoder {
encoderConfig := zap.NewProductionEncoderConfig()
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
return zapcore.NewConsoleEncoder(encoderConfig)
}
zap.New(..)
函数中添加一个Option
。logger := zap.New(core, zap.AddCaller())
main()
函数时,以下输出将打印在文件——test.log
中。2019-10-27T15:33:29.855+0800 DEBUG logic/temp2.go:47 Trying to hit GET request for www.sogo.com
2019-10-27T15:33:29.855+0800 ERROR logic/temp2.go:50 Error fetching URL www.sogo.com : Error = Get www.sogo.com: unsupported protocol scheme ""
2019-10-27T15:33:29.856+0800 DEBUG logic/temp2.go:47 Trying to hit GET request for http://www.sogo.com
2019-10-27T15:33:30.125+0800 INFO logic/temp2.go:52 Success! statusCode = 200 OK for URL http://www.sogo.com
使用Lumberjack进行日志切割归档
安装
go get -u github.com/natefinch/lumberjack
zap logger中加入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)
}
测试所有功能
package main
import (
"net/http"
"github.com/natefinch/lumberjack"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
var sugarLogger *zap.SugaredLogger
func main() {
InitLogger()
defer sugarLogger.Sync()
simpleHttpGet("www.sogo.com")
simpleHttpGet("http://www.sogo.com")
}
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)
}
func getLogWriter() zapcore.WriteSyncer {
lumberJackLogger := &lumberjack.Logger{
Filename: "./test.log",
MaxSize: 1,
MaxBackups: 5,
MaxAge: 30,
Compress: false,
}
return zapcore.AddSync(lumberJackLogger)
}
func simpleHttpGet(url string) {
sugarLogger.Debugf("Trying to hit GET request for %s", url)
resp, err := http.Get(url)
if err != nil {
sugarLogger.Errorf("Error fetching URL %s : Error = %s", url, err)
} else {
sugarLogger.Infof("Success! statusCode = %s for URL %s", resp.Status, url)
resp.Body.Close()
}
}
2019-10-27T15:50:32.944+0800 DEBUG logic/temp2.go:48 Trying to hit GET request for www.sogo.com
2019-10-27T15:50:32.944+0800 ERROR logic/temp2.go:51 Error fetching URL www.sogo.com : Error = Get www.sogo.com: unsupported protocol scheme ""
2019-10-27T15:50:32.944+0800 DEBUG logic/temp2.go:48 Trying to hit GET request for http://www.sogo.com
2019-10-27T15:50:33.165+0800 INFO logic/temp2.go:53 Success! statusCode = 200 OK for URL http://www.sogo.com
main
函数中循环记录日志,测试日志文件是否会自动切割和归档(日志文件每1MB会切割并且在当前目录下最多保存5个备份)。
下一篇:java可变参数