go 日志库zap的使用

Goland中使用zap日志库

运行下面的命令安装zap

go get -u go.uber.org/zap
一 简单的logger实例

通过调用zap.NewProduction()/zap.NewDevelopment()或者zap.Example()创建一个Logger

在性能很好但不是很关键的上下文中,使用SugaredLogger。它比其他结构化日志记录包快4-10倍,并且支持结构化和printf风格的日志记录。

在每一微秒和每一次内存分配都很重要的上下文中,使用Logger。它甚至比SugaredLogger更快,内存分配次数也更少,但它只支持强类型的结构化日志记录。

package main

import (
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)
// 两种类型的日志记录器sugarlogger 和logger
var sugarlogger *zap.SugaredLogger
var logger *zap.Logger

func main() {
	InitLogger()
	defer sugarlogger.Sync()
	r := gin.Default()
	r.GET("/sugerlogger", func(c *gin.Context) {
		sugarlogger.Info("sugerlogger:访问了sugerlogger")
		logger.Info("logger:访问了sugerlogger")
	})
	_ = r.Run(":8888")
}
func InitLogger() {
	// zap.NewExample() 用于测试
	//{"level":"info","msg":"sugerlogger:访问了sugerlogger"}
	//zap.NewProduction() 用于生产环境
	//{"level":"info","ts":"2021-09-22T20:17:15.979+0800","caller":"zap_log_demo/SugaredLoggerDemo.go:16","msg":"sugerlogger:访问了sugerlogger"}
	//zap.NewDevelopment() 用户开发环境
	//2021-09-22T20:17:53.011+0800	INFO	zap_log_demo/SugaredLoggerDemo.go:16	sugerlogger:访问了sugerlogger
	logger, _ = zap.NewDevelopment()
	sugarlogger = logger.Sugar()
}
二 、定制logger

将日志写入文件而不是终端

我们将使用 zap.new()方法配置

package main

import (
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"os"
)

var sugarlogger *zap.SugaredLogger
//日志格式
func getEncoder() zapcore.Encoder {
    // 以下两种都是EncoderConfig类型 可以使用源码中封装的 也可以自定义
    // zap.NewProductionEncoderConfig()
    // zap.NewDevelopmentEncoderConfig()
    // return zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
    //自定义 我们可以修改里面的key和value值实现日志的定制
    encodingConfig := zapcore.EncoderConfig{
		TimeKey:        "ts",
		LevelKey:       "level",
		NameKey:        "logger",
		CallerKey:      "caller",
		FunctionKey:    zapcore.OmitKey,
		MessageKey:     "msg",
		StacktraceKey:  "stacktrace",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.LowercaseLevelEncoder,
		EncodeTime:     zapcore.ISO8601TimeEncoder, //时间格式更改
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}
	return  zapcore.NewJSONEncoder(encodingConfig)

}
// 日志写到哪里
func getWriteSyncer() zapcore.WriteSyncer {
	file, _ := os.OpenFile("path", os.O_CREATE|os.O_APPEND, 666)
	return zapcore.AddSync(file)
}
func InitLogger() {
	// zapcore.Core需要三个配置——Encoder,WriteSyncer,LogLevel
	encoder := getEncoder()
	writerSync := getWriteSyncer()
	core := zapcore.NewCore(encoder, writerSync, zapcore.DebugLevel)
	//logger := zap.New(core)
    //添加AddCaller方法可以查看那个文件那一行调用了该日志
    //{"level":"info","ts":"2021-09-22T22:26:03.874+0800","caller":"go_zap_new/zap定制logger.go:55","msg":"Success...状态码200"}

    logger := zap.New(core,zap.AddCaller())
	sugarlogger = logger.Sugar()
}

func main() {
	InitLogger()
	defer sugarlogger.Sync()
	r := gin.Default()
	r.GET("/sugerlogger", func(c *gin.Context) {
		sugarlogger.Info("自定义的log:访问了sugerlogger")
	})
	_ = r.Run(":8888")
}

三、日志切割

目前来说日志全是写在一个文件里的 当所有的日志全在一个文件里的时候 查阅是不友好的

安装

go get -u github.com/natefinch/lumberjack

使用

由于是文件的切割 所以我们只修改getWriteSyncer方法

func getWriteSyncer() zapcore.WriteSyncer {
	lumberJackLogger := &lumberjack.Logger{
		Filename:   "./go_zap_loglib/selflog.log", //文件位置
		MaxSize:    10,//在进行切割之前,日志文件的最大大小(以MB为单位)
		MaxBackups: 5, //保留旧文件的最大个数
		MaxAge:     30, // 保留旧文件的最大天数
		Compress:   false,// 是否压缩/归档旧文件
	}
	return zapcore.AddSync(lumberJackLogger)
}
四、分析源码 logger如何创建的
//默认的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"`
	FunctionKey   string `json:"functionKey" yaml:"functionKey"`
	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"`
	// Configures the field separator used by the console encoder. Defaults
	// to tab.
	ConsoleSeparator string `json:"consoleSeparator" yaml:"consoleSeparator"`
}

//默认的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"`
}

logger 实例创建的源码分析

func NewDevelopment(options ...Option) (*Logger, error) {
    return  NewDevelopmentConfig().Build(options...)
}

func NewDevelopmentConfig() Config {
    return Config{
        Level:            NewAtomicLevelAt(DebugLevel),
        Development:      true,
        Encoding:         "console",
        EncoderConfig:    NewDevelopmentEncoderConfig(),
        OutputPaths:      []string{"stderr"},
        ErrorOutputPaths: []string{"stderr"},
    }
}

//config的build方法
func (cfg Config) Build(opts ...Option) (*Logger, error) { 
	enc, err := cfg.buildEncoder()
	if err != nil {
		return nil, err
	}
	sink, errSink, err := cfg.openSinks()
	if err != nil {
		return nil, err
	}

	if cfg.Level == (AtomicLevel{}) {
		return nil, fmt.Errorf("missing Level")
	}
    //关键之方法new()以及里面的zapcore.NewCore(enc, sink, cfg.Level)方法中的三个参数
    // enc -> zapcore.Encoder 意思以什么格式写入日志
    // sink -> zapcore.WriteSyncer  日志写到什么地方 
    // 日志等级cfg.Level 那种级别的日志将别写入
	log := New(
		zapcore.NewCore(enc, sink, cfg.Level),
		cfg.buildOptions(errSink)...,
	)
	if len(opts) > 0 {
		log = log.WithOptions(opts...)
	}
	return log, nil
}
	
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值