zap日志库
一、默认版log库
1.配置日志输出文件
func SetupLogger() {
logFileLocation, _ := os.OpenFile("/Users/q1mi/test.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0744)
log.SetOutput(logFileLocation)
}
2.使用logger
func simpleHttpGet(url string) {
resp, err := http.Get(url)
if err != nil {
log.Printf("Error fetching url %s : %s", url, err.Error())
} else {
log.Printf("Status Code for %s : %s", url, resp.Status)
resp.Body.Close()
}
}
- 三个打印函数Print 、Panic 、Fatal
- 对每一类接口其提供了3中调用方式,分别是 "Xxxx 、 Xxxxln 、Xxxxf",基本和fmt中的相关函数类似
- log.Fatal 接口,打印输出后,接着调用系统的 os.exit(1) 接口
- log.Panic接口,该函数把日志内容刷到标准错误后,调用 panic 函数
log包存在的劣势
- 仅限基本的日志级别
- 但是它缺少一个ERROR日志级别,这个级别可以在不抛出panic或退出程序的情况下记录错误
- 但是它缺少一个ERROR日志级别,这个级别可以在不抛出panic或退出程序的情况下记录错误
- 不提供日志切割的能力,如日志文件大小,存储管理
二、go.uber.org/zap 又快又好用的日志包
安装 go get -u go.uber.org/zap
1)配置Zap Logger
Zap提供了两种类型的日志记录器 SugaredLogger 和 Logger
相对来说,SugaredLogger比 Logger封装更高级,支持结构化和printf风格,
但是Logger,适用于每一微秒和每一次内存分配都很重要的上下文中,因为只支持强类型的结构化日志记录,比SugaredLogger更快,内存分配次数也更少,
2)简单调用
- zap.NewProduction()、zap.NewDevelopment()、zap.Example()创建一个Logger
- 上面每一个函数都将创建一个logger。唯一的区别在于它将记录的信息不同。例如production logger默认记录调用函数信息、日期和时间等
- Logger调用Info/Error等,默认日志打印到console
var logger *zap.Logger
func main() {
InitLogger()
defer logger.Sync() //zap底层设置了缓存,sync将缓存同步到文件中
simpleHttpGet("www.google.com")
simpleHttpGet("http://www.google.com")
}
func InitLogger() {
logger, _ = zap.NewProduction()
sugarLogger = logger.Sugar() //升级为sugar
}
func simpleHttpGet(url string) {
resp, err := http.Get(url)
if err != nil {
logger.Error(
"Error fetching url..",
zap.String("url", url), // 输出 url: XXXX,
zap.Error(err))
} else {
logger.Info("Success..",
zap.String("statusCode", resp.Status), //zap.type() 强类型,写入日志,zap.StringP,输出记录指针,zap.StringL 输出记录字符串数组
zap.String("url", url))
resp.Body.Close()
}
}
输出结果 默认有caller
{"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"}
3)定制化调用
func New(core zapcore.Core, options ...Option) *Logger
其中zapcore.Core需要三个配置——Encoder,WriteSyncer,LogLevel
-
Encoder 编码器(如何写入日志),使用json编码NewsJSONEncoder(),再使用预先设置的ProductionEncoderConfig()。
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
-
WriterSyncer :指定日志将写到哪里去。我们使用zapcore.AddSync()函数并且将打开的文件句柄传进去
file, _ := os.Create("./test.log")
writeSyncer := zapcore.AddSync(file)
- Log Level:哪种级别的日志将被写入
func InitLogger() {
file, _ := os.Create("./test.log")
writeSyncer := zapcore.AddSync(file)
encoder := zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()) //json输出格式
core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)
logger := zap.New(core)
sugarLogger = logger.Sugar()
}
输出结果,无caller,需额外配置
{"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"}
添加调用详细信息,即那行代码出错
logger := zap.New(core, zap.AddCaller())
修改时间格式
大写记录日志级别
通过修改core
encoderConfig := zap.NewProductionEncoderConfig()
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
encoder := zapcore.NewConsoleEncoder(encoderConfig)
019-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
- 使用lumberjack 修改WriterSyncer
lumberJackLogger := &lumberjack.Logger{
Filename: "./test.log",
MaxSize: 10, //日志文件最大存储大小(MB)
MaxBackups: 5, //保留旧文件最大个数
MaxAge: 30, //保留旧文件最大天数
Compress: false, //是否压缩
}
WriterSyncer := zapcore.AddSync(lumberJackLogger)
最终完整zap/lumberjack代码示例如下:
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()
}
}