Go日志
一、log包
log日志包会默认为输出带上时间,我们也可以自定义我们的日志抬头信息
1 | // 定义抬头信息为:时间+文件名+源代码所在行号 |
log包提供的可定义的选项常量
1 | const ( |
也可以设置前缀
1 | func init(){ |
log包除了 Print 系列的函数,还有Fatal、Panic 系列的函数。
Fatal 系列函数表示程序遇到了致命的错误,需要退出,这时候使用 Fatal 记录日志后,然后程序退出
Panic 系列函数表示先记录日志,然后调用 panic 函数抛出一个 panic,这时候除了使用 recover 函数,否则程序就会打印错误堆栈信息,然后程序终止。
设置输出位置,实现一个 io.Writer 接口的类型即可
定制自己的日志
1 | var ( |
io.MultiWriter 函数可以包装多个 io.Writer 为一个 io.Writer,这样就可以达到同时对多个 io.Writer 输出日志的目的
logger使用起来非常简单,但是不支持 INFO/DEBUG等多个级别;没有切割日志的功能等等。
二、zap包
zap 是非常快、结构化、分日志级别的Go日志库
安装:go get -u go.uber.org/zap
配置 zap Logger
Zap提供了两种类型的日志记录器—Sugared Logger
和Logger
。
在性能很好但不是很关键的上下文中,使用SugaredLogger
。它比其他结构化日志记录包快4-10倍,并且支持结构化和printf风格的日志记录。
在每一微秒和每一次内存分配都很重要的上下文中,使用Logger
。它甚至比SugaredLogger
更快,内存分配次数也更少,但它只支持强类型的结构化日志记录。
- Logger
- 通过调用
zap.NewProduction()
/zap.NewDevelopment()
或者zap.Example()
创建一个Logger。 - 上面的每一个函数都将创建一个logger。唯一的区别在于它将记录的信息不同。例如production logger默认记录调用函数信息、日期和时间等。
- 通过Logger调用Info/Error等。
- 默认情况下日志都会打印到应用程序的console界面。
1 | var logger *zap.Logger |
- Sugared Logger
现在让我们使用Sugared Logger来实现相同的功能。
- 大部分的实现基本都相同。
- 惟一的区别是,我们通过调用主logger的
. Sugar()
方法来获取一个SugaredLogger
。 - 然后使用
SugaredLogger
以printf
格式记录语句
下面是修改过后使用SugaredLogger
代替Logger
的代码:
1 | var sugarLogger *zap.SugaredLogger |
定制 Logger
将日志写入文件而不是终端
使用 zap.New(…) 方法来手动传递所有配置。
1
func New(core zapcore.Core, options ...Option) *Logger
zapcore.Core 需要三个配置— Encoder、WriteSyncer、LogLevel
Encoder:编码器 (如何写入日志),使用 NewJSONEncoder() ,并使用预先设置的 ProductionEncoderConfig()。
1
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
WriterSyncer:指定日志将写到哪里去,使用 zapcore.AddSync() 函数并且将新打开的文件句柄传进去
1
2file,_ := os.Create("./test.log")
writeSyncer := zapcore.AddSync(file)Log Level:那种级别的日志将被写入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20var sugarLogger *zap.SugaredLogger
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())
// 将JSON Encoder 更改为普通 Encoder
return zapcore.NewConsoleEncoder(zap.NewProductionEncoderConfig())
}
func getLogWriter() zapcore.WriteSyncer {
file, _ := os.Create("./test.log")
return zapcore.AddSync(file)
}- 接下来修改时间编码器
- 在日志文件中使用大写字母记录日志级别
1
2
3
4
5
6func getEncoder() zapcore.Encoder {
encoderConfig := zap.NewProductionEncoderConfig()
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
return zapcore.NewConsoleEncoder(encoderConfig)
}- 添加将调用函数信息记录到日志中的功能
1
logger := zap.New(core,zap.AddCaller())
最终
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43var sugarLogger *zap.SugaredLogger
func InitLogger2(){
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{
file,_ := os.Create("./log/zap/test.log")
return zapcore.AddSync(file)
}
func simpleHttpGet2(url string) {
resp, err := http.Get(url)
if err != nil {
sugarLogger.Error(
"Error fetching url..",
zap.String("url", url),
zap.Error(err))
} else {
sugarLogger.Info(
"Success..",
zap.String("statusCode", resp.Status),
zap.String("url", url))
resp.Body.Close()
}
}
func main(){
InitLogger2()
defer sugarLogger.Sync()
simpleHttpGet2("http://www.google.com")
}使用 Lumberjack 进行日志切割归档
zap本书不提供日志切割,可以使用 Lumberjack
安装:go get -u github.com/natefinch/lumberjack
修改 getLogWriter() 函数
1
2
3
4
5
6
7
8
9
10func 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:是否压缩/归档旧文件
测试最终结果
1 | package main |