在许多Go语言项目中,我们需要一个好的日志记录器能够提供下面这些功能:
- 能够将事件记录到文件中,而不是应用程序控制台。
- 日志切割-能够根据文件大小、时间或间隔等来切割日志文件。
- 支持不同的日志级别。例如INFO,DEBUG,ERROR等。
- 能够打印基本信息,如调用文件/函数名和行号,日志时间等。
系统自带的log模块
自带log库的优势和劣势
优势
它最大的优点是使用非常简单。
我们可以设置任何io.Writer作为日志记录输出并向其发送要写入的日志。
劣势
- 仅限基本的日志级别
- 只有一个Print选项。不支持INFO/DEBUG等多个级别。
- 对于错误日志,它有Fatal和Panic
- Fatal日志通过调用os.Exit(1)来结束程序
- Panic日志在写入日志消息之后抛出一个panic
- 但是它缺少一个ERROR日志级别,这个级别可以在不抛出panic或退出程序的情况下记录错误
- 缺乏日志格式化的能力——例如记录调用者的函数名和行号,格式化日期和时间格式。等等。
- 不提供日志切割的能力。
默认的log输出到控制台。
log.Printf("%d+%d=%d\n", 3, 4, 3+4)
log.Println("Hello Golang")
log.Fatalln("Bye, the world") //日志输出后会执行os.Exit(1)
指定日志输出到文件
格式
log.New(out io.Writer, prefix string, flag int) *Logger
- out 是打开的文件,用
os.OpenFile()
打开的一个可写文件 - prefix 每条日志的前缀
- flag 设置日志的格式
log.Ldate
日期格式的 2009/01/23log.Lmicroseconds
精确到微秒的时间 01:23:23.123123log.Ltime
精确到秒 01:23:23log.Llongfile
完整文件名和行号 /a/b/c/d.go:23log.Lshortfile
文件名和行号 d.go:23log.LUTC
如果设置了Ldate或Ltime,则使用UTC而不是本地时区log.Lmsgprefix
将“前缀”从行首移到消息之前log.LstdFlags
相当于Ldate | Ltime
logWriter := log.New(fout, "[BIZ_PREFIX]", log.Ldate|log.Lmicroseconds) //通过flag参数定义日志的格式
logWriter.Println("Hello Golang")
例子
package main
import (
"fmt"
"log"
"os"
"time"
)
var file, err = os.OpenFile("1.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
func logs() {
logger := log.New(file, "[abc]", log.Ldate|log.Lmicroseconds)
logger.Println("第一行")
logger.Println("第二行")
logger.Println("第三行")
}
//关闭文件
func onexit() {
if file != nil {
fmt.Println("退出了")
file.Close()
}
}
func main() {
defer func() {
//异常退出的时候关闭文件
if err := recover(); err != nil {
onexit()
}
}()
n := 0
//循环打印日志
for i := 0; i < 10; i++ {
logs()
time.Sleep(3 * time.Second)
//模拟故障
if i == 5 {
_ = 1 / n
}
}
//正常退出的时候关闭文件
onexit()
}
第三方日志库zap
zap是非常快的、结构化的,分日志级别的Go日志库。
为什么选择Uber-go zap
- 它同时提供了结构化日志记录和printf风格的日志记录
- 它非常的快
根据Uber-go Zap的文档,它的性能比类似的结构化日志包更好——也比标准库更快。
以下是Zap发布的基准测试信息
记录一条消息和10个字段:
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 |
记录一个静态字符串,没有任何上下文或printf风格的模板:
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提供了两种类型的日志记录器—Sugared Logger和Logger。
-
SugaredLogger
在性能很好但不是很关键的上下文中,使用SugaredLogger。它比其他结构化日志记录包快4-10倍,并且支持结构化和printf风格的日志记录。
-
Logger
在每一微秒和每一次内存分配都很重要的上下文中,使用Logger。它甚至比SugaredLogger更快,内存分配次数也更少,但它只支持强类型的结构化日志记录。
Logger
- 通过调用zap.NewProduction()/zap.NewDevelopment()或者zap.Example()创建一个Logger。
- 上面的每一个函数都将创建一个logger。唯一的区别在于它将记录的信息不同。例如production logger默认记录调用函数信息、日期和时间等。
- 通过Logger调用Info/Error等。
- 默认情况下日志都会打印到应用程序的console界面。
例子
package main
import (
"errors"
"fmt"
"go.uber.org/zap"
)
func main() {
logger, err := zap.NewProduction()//初始化一个生产环境的logger
if err != nil {
fmt.Println(err)
return
}
defer logger.Sync()
logger.Error("error这条", zap.Error(errors.New("错误信息")), zap.String("abc", "这是abc的value"))
logger.Info("info这条", zap.Error(errors.New("错误信息")), zap.String("abc", "这是abc的value"))
}
/*
{"level":"error","ts":1667451149.3754392,"caller":"week13/1.go:17","msg":"error这条","error":"错误信息","abc":"这是abc的value","stacktrace":"main.main\n\tE:/Codes/GO/week13/1.go:17\nruntime.main\n\tD:/GO/Go/src/runtime/proc.go:250"}
{"level":"info","ts":1667451149.3761096,"caller":"week13/1.go:18","msg":"info这条","error":"错误信息","abc":"这是abc的value"}
*/
可以看到:
生产环境下的logger默认的日志输出格式是json
时间是时间戳
再来个开发环境的
使用zap.NewDevelopment()
生成logger
package main
import (
"errors"
"fmt"
"go.uber.org/zap"
)
func main() {
logger, err := zap.NewDevelopment()//初始化一个开发环境的logger
if err != nil {
fmt.Println(err)
return
}
defer logger.Sync()
logger.Error("error这条", zap.Error(errors.New("错误信息")), zap.String("abc", "这是abc的value"))
logger.Info("info这条", zap.Error(errors.New("错误信息")), zap.String("abc", "这是abc的value"))
}
/*
2022-11-03T14:06:07.225+0800 ERROR week13/1.go:43 error这条 {"error": "错误信息", "abc": "这是abc的value"}
main.main
E:/Codes/GO/week13/1.go:43
runtime.main
D:/GO/Go/src/runtime/proc.go:250
2022-11-03T14:06:07.233+0800 INFO week13/1.go:44 info这条 {"error": "错误信息", "abc": "这是abc的value"}
*/
可以看到:
日志的输出格式是以Console格式输出的
时间是方便阅读的格式
通过zap.Error(errors.New("错误信息"))
类型,可以给日志信息添加字段,都是以key-value的形式存储
还有其他类型
zap.Int()
zap.Duration()
zap.String()
zap.Error()
SugaredLogger
使用Sugared Logger来实现相同的功能。
- 大部分的实现基本都相同。
- 惟一的区别是,我们通过调用主logger的
. Sugar()
方法来获取一个SugaredLogger
。 - 然后使用
SugaredLogger
以printf
格式记录语句
例子
package main
import (
"errors"
"fmt"
"go.uber.org/zap"
)
func main() {
logger, err := zap.NewProduction() //初始化一个生产环境的logger
if err != nil {
fmt.Println(err)
return
}
sugarLogger := logger.Sugar()
defer sugarLogger.Sync()
info1 := "err信息"
sugarLogger.Errorf("这里是 %s", info1)
info2 := "info信息"
sugarLogger.Infof("这里是 %s", info2)
}
/*
{"level":"error","ts":1667456422.2656977,"caller":"week13/1.go:44","msg":"这里是 err信息","stacktrace":"main.main\n\tE:/Codes/GO/week13/1.go:44\nruntime.main\n\tD:/GO/Go/src/runtime/proc.go:250"}
{"level":"info","ts":1667456422.2656977,"caller":"week13/1.go:46","msg":"这里是 info信息"}
*/
定制logger
将日志写入文件而不是终端
我们要做的第一个更改是把日志写入文件,而不是打印到应用程序控制台。
- 我们将使用
zap.New(…)
方法来手动传递所有配置,而不是使用像zap.NewProduction()
这样的预置方法来创建logger。
func New(core zapcore.Core, options ...Option) *Logger
zapcore.Core
需要三个配置——Encoder
,WriteSyncer
,LogLevel
。
Encoder
编码器(如何写入日志)。
有两种开箱即用的编码器
- Console格式
func NewConsoleEncoder(cfg EncoderConfig) Encoder
- Json格式
func NewJSONEncoder(cfg EncoderConfig) Encoder
Console格式
类似
2022-11-03T14:04:37.330+0800 INFO week13/1.go:44 info这条 {"error": "错误信息", "abc": "这是abc的value"}
两种使用方法
1、使用预制的配置ProductionEncoderConfig()
或者DevelopmentEncoderConfig()
使用方法 这里以
encoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
//或者
encoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
//带入到core
core := zapcore.NewCore(encoder, writer, zap.InfoLevel)
两个的区别
#ProductionEncoderConfig()的日志格式
1.6674517658521087e+09 error error这条 {"error": "错误信息", "abc": "这是abc的value"}
#DevelopmentEncoderConfig()的日志格式
2022-11-03T13:03:40.884+0800 ERROR error这条 {"error": "错误信息", "abc": "这是abc的value"}
2、自定义时间格式以及在日志文件中使用大写字母记录日志级别
encoderConfig := zap.NewProductionEncoderConfig()//创建一个编码器配置
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder //设置时间格式 这种2022-11-03T13:47:57.782+0800
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder //设置大写字符的日志级别 这种ERROR
// encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder //设置带颜色的日志级别 建议控制台打印的时候使用,写入文本不建议使用,很影响读取
encoderConfig.EncodeCaller = zapcore.FullCallerEncoder //完整路径的显示日志打印的位置 例如E:/Codes/GO/week13/1.go:33
//encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder //短路径显示 例如 week13/1.go:33
encoder := zapcore.NewConsoleEncoder(encoderConfig) //用配置创建一个Console格式的编码器
2022-11-03T13:47:57.458+0800 ERROR E:/Codes/GO/week13/1.go:33 error这条 {"error": "错误信息", "abc": "这是abc的value"}
2022-11-03T13:47:57.458+0800 INFO E:/Codes/GO/week13/1.go:34 info这条 {"error": "错误信息", "abc": "这是abc的value"}
2022-11-03T13:47:57.458+0800 DEBUG E:/Codes/GO/week13/1.go:35 debug这条
Json格式
json格式的与Console格式的使用相同,只是记录的日志格式不同
只需要把zapcore.NewConsoleEncoder()
更换成zapcore.NewJSONEncoder()
用预制配置
encoder := zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
自定义配置
encoderConfig := zap.NewProductionEncoderConfig()//创建一个编码器配置
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder //设置时间格式 这种2022-11-03T13:47:57.782+0800
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder //设置大写字符的日志级别 这种ERROR
// encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder //设置带颜色的日志级别 建议控制台打印的时候使用,写入文本不建议使用,很影响读取
encoderConfig.EncodeCaller = zapcore.FullCallerEncoder //完整路径的显示日志打印的位置 例如E:/Codes/GO/week13/1.go:33
//encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder //短路径显示 例如 week13/1.go:33
encoder := zapcore.NewJSONEncoder(encoderConfig) //用配置创建一个Json格式的编码器
{"level":"ERROR","ts":"2022-11-03T14:44:10.133+0800","caller":"E:/Codes/GO/week13/1.go:34","msg":"error这条","error":"错误信息","abc":"这是abc的value"}
{"level":"INFO","ts":"2022-11-03T14:44:10.133+0800","caller":"E:/Codes/GO/week13/1.go:35","msg":"info这条","error":"错误信息","abc":"这是abc的value"}
{"level":"DEBUG","ts":"2022-11-03T14:44:10.133+0800","caller":"E:/Codes/GO/week13/1.go:36","msg":"debug这条"}
WriterSyncer
指定日志将写到哪里去。
单个输出
直接使用zapcore.AddSync()
函数并且将打开的文件句柄传进去
//现创建文件
file, _ := os.Create("1.txt")
//打开已有文件
file, _ := os.OpenFile("1.txt", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0755)
//控制台输出
file := os.Stdout
//新建writer
writer := zapcore.AddSync(file)
//带入创建core
core := zapcore.NewCore(encoder, writer, zap.InfoLevel)
多个输出
使用zapcore.NewMultiWriteSyncer()
函数将多个writer包装到一起,就可以同时写道多个地方
//写入一个文件
file1, _ := os.Create("1.txt")
//写入另一个文件
file2, _ := os.OpenFile("2.txt", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0755)
//同时控制台输出
file3 := os.Stdout
//新建writer
writer1 := zapcore.AddSync(file1)
writer2 := zapcore.AddSync(file2)
writer3 := zapcore.AddSync(file3)
//将多个writer传入
core := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(writer1, writer2, writer3), zap.InfoLevel)
以上同时在两个文件中输出还在控制台输出
LogLevel
哪种级别的日志将被写入
日志级别的实质就是数字常量
const (
// DebugLevel logs are typically voluminous, and are usually disabled in
// production.
DebugLevel Level = iota - 1
// InfoLevel is the default logging priority.
InfoLevel
// WarnLevel logs are more important than Info, but don't need individual
// human review.
WarnLevel
// ErrorLevel logs are high-priority. If an application is running smoothly,
// it shouldn't generate any error-level logs.
ErrorLevel
// DPanicLevel logs are particularly important errors. In development the
// logger panics after writing the message.
DPanicLevel
// PanicLevel logs a message, then panics.
PanicLevel
// FatalLevel logs a message, then calls os.Exit(1).
FatalLevel
_minLevel = DebugLevel
_maxLevel = FatalLevel
// InvalidLevel is an invalid value for Level.
//
// Core implementations may panic if they see messages of this level.
InvalidLevel = _maxLevel + 1
)
const (
// DebugLevel logs are typically voluminous, and are usually disabled in
// production.
DebugLevel = zapcore.DebugLevel
// InfoLevel is the default logging priority.
InfoLevel = zapcore.InfoLevel
// WarnLevel logs are more important than Info, but don't need individual
// human review.
WarnLevel = zapcore.WarnLevel
// ErrorLevel logs are high-priority. If an application is running smoothly,
// it shouldn't generate any error-level logs.
ErrorLevel = zapcore.ErrorLevel
// DPanicLevel logs are particularly important errors. In development the
// logger panics after writing the message.
DPanicLevel = zapcore.DPanicLevel
// PanicLevel logs a message, then panics.
PanicLevel = zapcore.PanicLevel
// FatalLevel logs a message, then calls os.Exit(1).
FatalLevel = zapcore.FatalLevel
)
日志的级别
最低的是DebugLevel 是-1
最高的是FatalLevel 是 6
从上到下依次递减
DebugLevel
InfoLevel
WarnLevel
ErrorLevel
DPanicLeve
PanicLevel
FatalLevel`
两种处理方式
1、设置下限
core := zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), zap.WarnLevel)
只有大于等于warn级别的日志会被记录
2、设置区间
highPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool { //error级别
return lev >= zap.ErrorLevel
})
lowPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool { //info和debug级别,debug级别是最低的
return lev < zap.ErrorLevel && lev >= zap.DebugLevel
})
core := zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), highPriority)
//或者
core := zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), lowPriority)
以上是将不同界别的区别出来
应用场景 将普通信息日志与错误日志分开记录
多个core
当需要将不同日志分开写的时候,就需要多个core配合使用
使用zapcore.NewTee()
方法
例子
file, _ := os.OpenFile("2.txt", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0755)
//创建多个core
infoFileCore := zapcore.NewCore(encoder, zapcore.AddSync(file), zap.ErrorLevel)
errorFileCore := zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), zap.DebugLevel)
//将infocore 和 errcore 加入core切片
var core []zapcore.Core
core = append(core, infoFileCore)
core = append(core, errorFileCore)
logger := zap.New(zapcore.NewTee(core...))
添加其他配置
添加记录日志的文件以及行
logger := zap.New(core, zap.AddCaller())
如果没添加zap.AddCaller()
2022-11-03T13:08:33.669+0800 ERROR error这条 {"error": "错误信息", "abc": "这是abc的value"}
添加了zap.AddCaller()
2022-11-03T13:08:33.669+0800 ERROR week13/1.go:65 error这条 {"error": "错误信息", "abc": "这是abc的value"}
使用Lumberjack进行日志切割归档
这个日志程序中唯一缺少的就是日志切割归档功能。
Zap本身不支持切割归档日志文件
为了添加日志切割归档功能,我们将使用第三方库Lumberjack来实现。
安装
执行下面的命令安装Lumberjack
$ go get -u github.com/natefinch/lumberjack
zap logger中加入Lumberjack
infoLumberIO := &lumberjack.Logger{
Filename: "./server/info.log",
MaxSize: 10, // megabytes
MaxBackups: 10,
MaxAge: 28, // days
Compress: false, //Compress确定是否应该使用gzip压缩已旋转的日志文件。默认值是不执行压缩。
}
writer := zapcore.AddSync(infoLumberIO)
Lumberjack Logger采用以下属性作为输入:
- Filename: 日志文件的位置 如果文件目录不存在,会自动创建
- MaxSize:最大文件大小,日志文件达到多少的时候切割(以MB为单位)
- MaxBackups:保留旧文件的最大个数
- MaxAges:保留旧文件的最大天数
- Compress:是否压缩/归档旧文件
存档的状态
例子
简单通用的logger
package main
import (
"errors"
"os"
"github.com/natefinch/lumberjack"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
func main() {
encoderConfig := zap.NewProductionEncoderConfig()
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder
encoder := zapcore.NewConsoleEncoder(encoderConfig)
infoLumberIO := &lumberjack.Logger{
Filename: "./log/info.log",
MaxSize: 1, // megabytes
MaxBackups: 10,
MaxAge: 28, // days
Compress: false, //Compress确定是否应该使用gzip压缩已旋转的日志文件。默认值是不执行压缩。
}
writer := zapcore.AddSync(infoLumberIO)
core := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(writer, zapcore.AddSync(os.Stdout)), zap.DebugLevel)
// core := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(writer, zapcore.AddSync(os.Stdout)), lowPriority)
logger := zap.New(core, zap.AddCaller())
sugar := logger.Sugar()
defer sugar.Sync()
sugar.Errorw("error这条", zap.Error(errors.New("错误信息")), zap.String("abc", "这是abc的value"))
sugar.Infow("info这条", zap.Error(errors.New("错误信息")), zap.String("abc", "这是abc的value"))
sugar.Debugw("debug这条")
}
错误日志与普通日志分开的logger
package main
import (
"errors"
"os"
"github.com/natefinch/lumberjack"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
//生成普通信息的Writer
func getInfoWriterSyncer() zapcore.WriteSyncer {
//引入第三方库 Lumberjack 加入日志切割功能
infoLumberIO := &lumberjack.Logger{
Filename: "./server/zaplog/info.log",
MaxSize: 10, // megabytes
MaxBackups: 100,
MaxAge: 28, // days
Compress: false, //Compress确定是否应该使用gzip压缩已旋转的日志文件。默认值是不执行压缩。
}
return zapcore.AddSync(infoLumberIO)
}
//生成故障信息的Writer
func getErrorWriterSyncer() zapcore.WriteSyncer {
//引入第三方库 Lumberjack 加入日志切割功能
lumberWriteSyncer := &lumberjack.Logger{
Filename: "./server/zaplog/error.log",
MaxSize: 10, // megabytes
MaxBackups: 100,
MaxAge: 28, // days
Compress: false, //Compress确定是否应该使用gzip压缩已旋转的日志文件。默认值是不执行压缩。
}
return zapcore.AddSync(lumberWriteSyncer)
}
func main() {
//创建编码器配置
encoderConfig := zap.NewProductionEncoderConfig()
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder
//创建编码器
encoder := zapcore.NewConsoleEncoder(encoderConfig)
//info文件WriteSyncer
infoFileWriteSyncer := getInfoWriterSyncer()
//error文件WriteSyncer
errorFileWriteSyncer := getErrorWriterSyncer()
//区分日志级别
highPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool { //error级别
return lev >= zap.ErrorLevel
})
lowPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool { //info和debug级别,debug级别是最低的
return lev < zap.ErrorLevel && lev >= zap.DebugLevel
})
//根据不同日志级别创建不用的core
infoFileCore := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(infoFileWriteSyncer, zapcore.AddSync(os.Stdout)), lowPriority)
errorFileCore := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(errorFileWriteSyncer, zapcore.AddSync(os.Stdout)), highPriority)
//将infocore 和 errcore 加入core切片
var core []zapcore.Core
core = append(core, infoFileCore)
core = append(core, errorFileCore)
//用多个core创建logger
logger := zap.New(zapcore.NewTee(core...), zap.AddCaller()) //zap.AddCaller() 添加将调用函数信息记录到日志中的功能
sugar := logger.Sugar()
defer sugar.Sync()
//写入日志
sugar.Errorw("error这条", zap.Error(errors.New("错误信息")), zap.String("abc", "这是abc的value"))
sugar.Infow("info这条", zap.Error(errors.New("错误信息")), zap.String("abc", "这是abc的value"))
sugar.Debugw("debug这条")
}
结果
生成两个文件
error.log中
2022-11-03T15:29:07.419+0800 ERROR week13/1.go:65 error这条 {"error": "错误信息", "abc": "这是abc的value"}
info.log中
2022-11-03T15:29:07.427+0800 INFO week13/1.go:66 info这条 {"error": "错误信息", "abc": "这是abc的value"}
2022-11-03T15:29:07.428+0800 DEBUG week13/1.go:67 debug这条
在控制台中
2022-11-03T15:29:07.419+0800 ERROR week13/1.go:65 error这条 {"error": "错误信息", "abc": "这是abc的value"}
2022-11-03T15:29:07.427+0800 INFO week13/1.go:66 info这条 {"error": "错误信息", "abc": "这是abc的value"}
2022-11-03T15:29:07.428+0800 DEBUG week13/1.go:67 debug这条
日志分类记录文件同时打印有颜色的控制台日志
package common
import (
"os"
"github.com/natefinch/lumberjack"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// 正常日志编码器
func GetFileEnCoder() zapcore.Encoder {
config := zap.NewProductionEncoderConfig()
config.EncodeTime = zapcore.ISO8601TimeEncoder
config.EncodeLevel = zapcore.CapitalLevelEncoder
config.EncodeDuration = zapcore.NanosDurationEncoder
config.EncodeCaller = zapcore.ShortCallerEncoder
config.EncodeName = zapcore.FullNameEncoder
return zapcore.NewConsoleEncoder(config)
}
// 带颜色的日志编码器
func GetConsoleEnCoder() zapcore.Encoder {
config := zap.NewProductionEncoderConfig()
config.EncodeTime = zapcore.ISO8601TimeEncoder
config.EncodeLevel = zapcore.CapitalColorLevelEncoder
config.EncodeCaller = zapcore.ShortCallerEncoder
return zapcore.NewConsoleEncoder(config)
}
// 生成普通信息的Writer
func GetInfoWriterSyncer() zapcore.WriteSyncer {
//引入第三方库 Lumberjack 加入日志切割功能
infoLumberIO := &lumberjack.Logger{
Filename: "./log/info.log",
MaxSize: 10, // megabytes
MaxBackups: 100,
MaxAge: 28, // days
Compress: false, //Compress确定是否应该使用gzip压缩已旋转的日志文件。默认值是不执行压缩。
}
return zapcore.AddSync(infoLumberIO)
}
// 生成故障信息的Writer
func GetErrorWriterSyncer() zapcore.WriteSyncer {
//引入第三方库 Lumberjack 加入日志切割功能
lumberWriteSyncer := &lumberjack.Logger{
Filename: "./log/error.log",
MaxSize: 10, // megabytes
MaxBackups: 100,
MaxAge: 28, // days
Compress: false, //Compress确定是否应该使用gzip压缩已旋转的日志文件。默认值是不执行压缩。
}
return zapcore.AddSync(lumberWriteSyncer)
}
/*
例子:
logger := Logger()
defer logger.Sync()
logger.Debugw("调试信息", zap.String("k1", "v1"), zap.Error(errors.New("这是错误信息")))
logger.Debugf("调试信息%d", 1111)
logger.Infow("INFO信息", zap.String("k2", "v2"), zap.Error(errors.New("这是错误信息")))
logger.Errorw("error信息", zap.String("k3", "v3"), zap.Error(errors.New("这是错误信息")))
*/
func Logger() *zap.SugaredLogger {
encoderfile := GetFileEnCoder()
encoderconsole := GetConsoleEnCoder()
infowriter := GetInfoWriterSyncer()
errwriter := GetErrorWriterSyncer()
infolevel := zap.LevelEnablerFunc(func(l zapcore.Level) bool {
return l < zap.ErrorLevel && l >= zap.DebugLevel
})
errlevel := zap.LevelEnablerFunc(func(l zapcore.Level) bool {
return l >= zap.ErrorLevel
})
infocore := zapcore.NewCore(encoderfile, infowriter, infolevel)
errcore := zapcore.NewCore(encoderfile, errwriter, errlevel)
consolecore := zapcore.NewCore(encoderconsole, zapcore.AddSync(os.Stdout), zap.DebugLevel)
core := []zapcore.Core{infocore, errcore, consolecore}
logger := zap.New(zapcore.NewTee(core...), zap.AddCaller())
return logger.Sugar()
}
标签:zapcore,abc,go,日志,logger,zap
From: https://www.cnblogs.com/hexug/p/16906212.html