Golang日志包zap的使用
/一、缘由
最近在尝试用golang写简单的项目,但是之前一直忽略了一个重要的问题:==golang的日志包常用的是哪个?==
网上找了一些资料也问了一些目前做golang开发的朋友,目前使用最多的就是uber开源的一个日志模块:https://github.com/uber-go/zap start数量已经高达7k多,这篇文章主要就是整理如何使用这个包
二、安装
go get go.uber.org/zap
三、基础知识
关于Logger
zap 包中有两种类型的logger:
SugaredLogger:在性能要求不是很严格的情况下,可以使用SugaredLogger。它比其他结构化日志记录包快4-10倍,并支持结构化和printf样式的日志记录。
Logger:如果对性能要求非常高的话,可以用Logger,它比SugaredLogger更快,更节省资源
提示:默认情况下Logger是无缓冲的。 但是,由于zap的低级API允许缓冲,所以最好在退出进程之前调用Sync
内置的三种构建Logger的方法:NewExample,NewProduction和NewDevelopment。 通过这三种方法我们可以很方便的就构建一个logger,如下面例子:
logger,err := zap.NewProduction()
if err != nil {
log.Fatalf("can't initialize zap logger:%v\n",err)
}
defer logger.Sync()
logger.Info("hello golang")
Config
Config 的结构体如下:
type Config struct {
// Level is the minimum enabled logging level. Note that this is a dynamic
// level, so calling Config.Level.SetLevel will atomically change the log
// level of all loggers descended from this config.
Level AtomicLevel `json:"level" yaml:"level"`
// Development puts the logger in development mode, which changes the
// behavior of DPanicLevel and takes stacktraces more liberally.
Development bool `json:"development" yaml:"development"`
// DisableCaller stops annotating logs with the calling function's file
// name and line number. By default, all logs are annotated.
DisableCaller bool `json:"disableCaller" yaml:"disableCaller"`
// DisableStacktrace completely disables automatic stacktrace capturing. By
// default, stacktraces are captured for WarnLevel and above logs in
// development and ErrorLevel and above in production.
DisableStacktrace bool `json:"disableStacktrace" yaml:"disableStacktrace"`
// Sampling sets a sampling policy. A nil SamplingConfig disables sampling.
Sampling *SamplingConfig `json:"sampling" yaml:"sampling"`
// Encoding sets the logger's encoding. Valid values are "json" and
// "console", as well as any third-party encodings registered via
// RegisterEncoder.
Encoding string `json:"encoding" yaml:"encoding"`
// EncoderConfig sets options for the chosen encoder. See
// zapcore.EncoderConfig for details.
EncoderConfig zapcore.EncoderConfig `json:"encoderConfig" yaml:"encoderConfig"`
// OutputPaths is a list of URLs or file paths to write logging output to.
// See Open for details.
OutputPaths []string `json:"outputPaths" yaml:"outputPaths"`
// ErrorOutputPaths is a list of URLs to write internal logger errors to.
// The default is standard error.
//
// Note that this setting only affects internal errors; for sample code that
// sends error-level logs to a different location from info- and debug-level
// logs, see the package-level AdvancedConfiguration example.
ErrorOutputPaths []string `json:"errorOutputPaths" yaml:"errorOutputPaths"`
// InitialFields is a collection of fields to add to the root logger.
InitialFields map[string]interface{} `json:"initialFields" yaml:"initialFields"`
}
Config 提供了非常方便的方式让我们构造一个Logger,关于该结构体的说明:
Level: 这是一个AtomicLevel类型的数据,AtomicLevel 是原子可动态更改日志级别,这里需要注意:必须使用NewAtomicLevel构造函数创建AtomicLevels才能分配其内部原子指针。常用的方法有: NewAtomicLevel 和 NewAtomicLevelAt , NewAtomicLevel创建一个启用了InfoLevel及更高级别日志记录的AtomicLevel。NewAtomicLevelAt 是可以创建一个我们指定的日志级别。
Development: 用于设置logger是否是开发模式
DisableCaller:是否显示调用函数的文件名和行号。 默认情况下是显示的,即默认值是false
DisableStacktrace: 是否禁用堆栈跟踪捕获,默认情况下,将为development中的Warn Level,和更高的日志以及production中的Error Level捕获堆栈信息
Encoding: 设置logger的编码,这里有可以设置的参数有:“json” 和 “console” 以及通过RegisterEncoder注册的任何第三方编码。
EncoderConfig: 在下面会详细整理,主要是用于更灵活的做一些自定义配置
OutputPaths: 是一个要写日志的urls或者文件路径的列表
ErrorOutputPaths: 和OutputPaths类似,不过只影响内部错误
InitialFields: 初始字典设置,可以为日志输出的内容中添加一些初始字段
关于Config配置的一个简单例子:
atom := zap.NewAtomicLevelAt(zap.DebugLevel)
config := zap.Config{
Level:atom,
Development:false,
DisableCaller:true,
Encoding: "json",
EncoderConfig: encoderConfig,
InitialFields:map[string]interface{}{"service":"BlogService"},
OutputPaths:[]string{"stdout","./logs/blog.log"},
ErrorOutputPaths: []string{"stdout","./logs/blog.log"},
}
EncoderConfig
EncoderConfig的结构体如下:
type EncoderConfig struct {
// Set the keys used for each log entry. If any key is empty, that portion
// of the entry is omitted.
MessageKey string `json:"messageKey" yaml:"messageKey"`
LevelKey string `json:"levelKey" yaml:"levelKey"`
TimeKey string `json:"timeKey" yaml:"timeKey"`
NameKey string `json:"nameKey" yaml:"nameKey"`
CallerKey string `json:"callerKey" yaml:"callerKey"`
StacktraceKey string `json:"stacktraceKey" yaml:"stacktraceKey"`
LineEnding string `json:"lineEnding" yaml:"lineEnding"`
// Configure the primitive representations of common complex types. For
// example, some users may want all time.Times serialized as floating-point
// seconds since epoch, while others may prefer ISO8601 strings.
EncodeLevel LevelEncoder `json:"levelEncoder" yaml:"levelEncoder"`
EncodeTime TimeEncoder `json:"timeEncoder" yaml:"timeEncoder"`
EncodeDuration DurationEncoder `json:"durationEncoder" yaml:"durationEncoder"`
EncodeCaller CallerEncoder `json:"callerEncoder" yaml:"callerEncoder"`
// Unlike the other primitive type encoders, EncodeName is optional. The
// zero value falls back to FullNameEncoder.
EncodeName NameEncoder `json:"nameEncoder" yaml:"nameEncoder"`
}
通过 EncoderConfig 我们可以更灵活的做一些自定义配置,可以设置日志输出是对应字段的名字以及格式,下面对一些重要字段的进行说明:
LineEnding: 默认的参数是DefaultLineEnding 也就是”\n”,即默认以换行符为一行日志的结束
EncodeLevel: 通常会设置为: LowercaseLevelEncoder ,将Level序列化为小写字符串。 例如,InfoLevel被序列化为”info”。
EncodeTime: 设置时间格式,通常设置为zapcore.ISO8601TimeEncoder
EncodeCaller: 设置caller的显示的内容,有两个参数可以设置:ShortCallerEncoder和 FullCallerEncoder,FullCallerEncoder显示完成的调用路径,ShortCallerEncoder显示的是包级别调用路径
一个使用例子如下:
encoderConfig := zapcore.EncoderConfig{
TimeKey:"Time",
LevelKey:"Level",
NameKey: "Logger",
CallerKey: "Caller",
MessageKey:"Msg",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.FullCallerEncoder,
}
完整例子
package main
import (
"fmt"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
func main() {
encoderConfig := zapcore.EncoderConfig{
TimeKey:"Time",
LevelKey:"Level",
NameKey: "Logger",
CallerKey: "Caller",
MessageKey:"Msg",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.FullCallerEncoder,
}
atom := zap.NewAtomicLevelAt(zap.DebugLevel)
config := zap.Config{
Level:atom,
Development:false,
DisableCaller:false,
Encoding: "json",
EncoderConfig: encoderConfig,
InitialFields:map[string]interface{}{"service":"BlogService"},
OutputPaths:[]string{"stdout","./logs/blog.log"},
ErrorOutputPaths: []string{"stdout","./logs/blog.log"},
}
logger, err := config.Build()
if err != nil {
panic(fmt.Sprintf("logger init failed,error:%v",err))
}
logger.Info("logger init success")
logger.Error("connect db failed",
zap.String("dbAddress","127.0.0.1"),
zap.Int("dbPort",10021,
))
}
四、日志切割
gopkg.in/natefinch/lumberjack.v2 可以对zap写日志进行更好的控制,包括了日志的切割,历史日志的压缩,保留日期等
下面是一个完整的和zap包结合使用的例子:
package main
import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
"os"
)
func main() {
hook := lumberjack.Logger{
Filename:"./logs/test.log", //日志文件路径
MaxSize: 20,// 每个日志的大小,单位是M
MaxAge: 7, // 文件被保存的天数
Compress:true, // 是否压缩
MaxBackups:10, // 保存多少个文件备份
}
encoderConfig := zapcore.EncoderConfig{
TimeKey:"Time",
LevelKey:"Level",
NameKey: "Logger",
CallerKey: "Caller",
MessageKey:"Msg",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
atomicLevel := zap.NewAtomicLevel()
atomicLevel.SetLevel(zap.InfoLevel)
core := zapcore.NewCore(
zapcore.NewJSONEncoder(encoderConfig),
zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout),zapcore.AddSync(&hook)),
atomicLevel,
)
caller := zap.AddCaller()
development := zap.Development()
filed := zap.Fields(zap.String("service","blog"))
logger := zap.New(core,caller, development,filed)
logger.Info("logger init success")
logger.Info("connect db success")
logger.Error("connect redis error")
}
五、相关链接
https://godoc.org/go.uber.org/zap