golang使用Zap日志库

1. 为什么使用zap

因为它很快,而且我写不出比他更快的日志库😭

当然他还有其他优点,比如:它同时提供了结构化日志记录和printf风格的日志记录

2. 安装zap

go get -u go.uber.org/zap

3. 配置zap

zap提供两种日志记录器,如下表

名称 优点 缺点
Sugared Logger 支持结构化和printf风格的日志记录 较Logger慢
Logger 较Sugared Logger快 只支持强类型的结构化日志记录

Logger

  • 创建Logger
    • zap.NewProduction()
    • zap.NewDevelopment()
    • zap.Example()
  • 上述函数均可创建Logger只是输出信息不同
  • 默认情况下日志会打印到控制台

举个例子

package main

import "go.uber.org/zap"

var logger *zap.Logger

func ProductionLogger(){
	logger,_ = zap.NewProduction()
	logger.Info("log info")
}

func DevelopmentLogger(){
	logger,_ = zap.NewDevelopment()
	logger.Info("log info")
}

func ExampleLogger(){
	logger = zap.NewExample()
	logger.Info("log info")
}

func main() {
	ProductionLogger()
	DevelopmentLogger()
	ExampleLogger()
}

运行结果

{"level":"info","ts":1594976812.8990078,"caller":"go_zap/main.go:9","msg":"log info"}
2020-07-17T17:06:52.899+0800	INFO	go_zap/main.go:14	log info
{"level":"info","msg":"log info"}

除DevelopmentLogger之外其余都是json格式输出

Sugared Logger

  • 创建Sugared Logger
    • 由Logger调用Sugar()方法获得
  • 支持printf风格输出日志

举个例子

package main

import "go.uber.org/zap"

var sugarLogger *zap.SugaredLogger

func ProductionLogger(){
	logger,_ := zap.NewProduction()
	sugarLogger = logger.Sugar()
	sugarLogger.Infof("sugar loger %s", "yes!")
}

func DevelopmentLogger(){
	logger,_ := zap.NewDevelopment()
	sugarLogger = logger.Sugar()
	sugarLogger.Infof("sugar loger %s", "yes!")
}

func ExampleLogger(){
	logger := zap.NewExample()
	sugarLogger = logger.Sugar()
	sugarLogger.Infof("sugar loger %s", "yes!")
}

func main() {
	ProductionLogger()
	DevelopmentLogger()
	ExampleLogger()
}

运行结果

{"level":"info","ts":1594977351.4368348,"caller":"go_zap/main.go:10","msg":"sugar loger yes!"}
2020-07-17T17:15:51.436+0800	INFO	go_zap/main.go:16	sugar loger yes!
{"level":"info","msg":"sugar loger yes!"}

输出结果和Logger类似,但是sugarLogger支持printf

4. 定制Logger

上面所介绍到的三个创建Logger的方法包含了一些预置的配置,如果我们想要完全自定义,那我们就需要自己写好自己需要的配置。

这些配置将被赋值给zap.Config结构体,然后这个结构体对象调用Build方法构造Logger,大概就像这样

config := zap.Config{
    ...
}

log, err := config.Build()

zap.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"`
}

我们需要特别注意的是EncoderConfig这个字段,它定义了我们输出的格式,根据他的提示我们来看看zapcore.EncoderConfig结构体

zapcore.EncoderConfig

// An EncoderConfig allows users to configure the concrete encoders supplied by
// zapcore.
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"`
}

这些字段都不难理解,让我们来写一个例子吧

一个简单的样例

一般情况下我们都是用SugaredLogger因为它的速度足够快,而其功能更加强大,如果呢不知道该怎么选择不如就把两个都选上吧,就像这样

package main

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

var Logger *zap.Logger
var SugarLogger *zap.SugaredLogger

func Init() error{
	var err error
	// 构造EncoderConfig
	encoderConfig := zapcore.EncoderConfig{
		TimeKey: "timestamp",
		LevelKey: "severity",
		NameKey: "logger",
		CallerKey: "caller",
		MessageKey: "message",
		StacktraceKey: "stacktrace",
		LineEnding: "\n",
		EncodeLevel: zapcore.LowercaseLevelEncoder,
		EncodeTime: zapcore.ISO8601TimeEncoder,
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.FullCallerEncoder,
	}

	// 构造 Config
	config := zap.Config{
		Level: zap.NewAtomicLevelAt(zapcore.DebugLevel),
		Development: true,
		Encoding: "json",
		EncoderConfig: encoderConfig,
		InitialFields: map[string]interface{}{"MyName": "kainhuck"},
		OutputPaths: []string{"stdout"},
		ErrorOutputPaths: []string{"stdout"},
	}

	// 可以构造Logger了
	Logger, err = config.Build()
	if err != nil {
		return err
	}

	// 然后是SugarLogger
	SugarLogger = Logger.Sugar()
	return nil
}

func main(){
	err := Init()
	if err != nil {
		panic(err)
	}

	SugarLogger.Debugf("ohhhhhhh err:%s", "horika")
}

运行结果

{"severity":"debug","timestamp":"2020-07-17T17:58:56.626+0800","caller":"D:/Coding/go_module/go_zap/main.go:56","message":"ohhhhhhh err:horika","MyName":"kainhuck"}
posted @ 2020-07-17 21:57  KainHuck  阅读(2726)  评论(0编辑  收藏  举报