zoukankan      html  css  js  c++  java
  • golang开发:类库篇(一) Zap高性能日志类库的使用

    为什么要用zap来写日志

    原来是写PHP的,一直用的error_log,第一次写Go项目的时候,还真不知道该怎么写日志,后来就按照PHP的写法自己不成规范的捣鼓写。去了新公司之后,发现用的是zap。后来查询 了解了下zap,前同事反应他们很多大公司都在使用zap写日志,GitHub上star 高达7K多,足以说明它受欢迎的程度。

    1.zap是Uber开源的日志库;
    2.很多大的公司和小的公司都在使用;
    3.跟seelog、logrus等类库相比,高性能是它最突出的优势;
    我想以上几个原因就已经说明了它的广泛性、稳定性,就值得我们去尝试。

    怎么使用zap

    我们说下简单的使用案例
    首相当然是下载
    go get -u go.uber.org/zap
    先贴一个我这边常用的zap的配置

    zap.Config{
    		Level:       zap.NewAtomicLevelAt(zap.DebugLevel),
    		Development: true,
    		Encoding:    "json",
    		EncoderConfig: zapcore.EncoderConfig{
    			TimeKey:        "t",
    			LevelKey:       "level",
    			NameKey:        "log",
    			CallerKey:      "caller",
    			MessageKey:     "msg",
    			StacktraceKey:  "trace",
    			LineEnding:     zapcore.DefaultLineEnding,
    			EncodeLevel:    zapcore.LowercaseLevelEncoder,
    			EncodeTime:     时间格式函数,
    			EncodeDuration: zapcore.SecondsDurationEncoder,
    			EncodeCaller:   zapcore.ShortCallerEncoder,
    		},
    		OutputPaths:      []string{"/tmp/zap.log"},
    		ErrorOutputPaths: []string{"/tmp/zap.log"},
    		InitialFields: map[string]interface{}{
    			"app": "test",
    		},
    	}
    

    基本配置的说明

    Level:日志级别,跟其他语言是一样的。只不过它需要的类型是AtomicLevel。所以需要使用zap.NewAtomicLevelAt做下如下的转化。

    zap.NewAtomicLevelAt(zap.DebugLevel)
    zap.DebugLevel
    zap.InfoLevel
    zap.WarnLevel
    zap.ErrorLevel
    

    Development:bool 是否是开发环境。如果是开发模式,对DPanicLevel进行堆栈跟踪
    DisableCaller:bool 禁止使用调用函数的文件名和行号来注释日志。默认进行注释日志
    DisableStacktrace:bool 是否禁用堆栈跟踪捕获。默认对Warn级别以上和生产error级别以上的进行堆栈跟踪。
    Encoding:编码类型,目前两种json 和 console【按照空格隔开】,常用json
    EncoderConfig:生成格式的一些配置--TODO 后面我们详细看下EncoderConfig配置各个说明
    OutputPaths:[]string 日志写入文件的地址
    ErrorOutputPaths:[]string 将系统内的error记录到文件的地址
    InitialFields:map[string]interface{} 加入一些初始的字段数据,比如项目名
    当然了,如果想控制台输出,OutputPaths和ErrorOutputPaths不能配置为文件地址,而应该改为stdout。

    关于config的配置,具体的可以参考文件里面的注释
    go.uber.org/zap/config.go
    type Config struct

    EncoderConfig配置说明

    MessageKey:输入信息的key名
    LevelKey:输出日志级别的key名
    TimeKey:输出时间的key名
    NameKey CallerKey StacktraceKey跟以上类似,看名字就知道
    LineEnding:每行的分隔符。基本zapcore.DefaultLineEnding 即" "
    EncodeLevel:基本zapcore.LowercaseLevelEncoder。将日志级别字符串转化为小写
    EncodeTime:输出的时间格式
    EncodeDuration:一般zapcore.SecondsDurationEncoder,执行消耗的时间转化成浮点型的秒
    EncodeCaller:一般zapcore.ShortCallerEncoder,以包/文件:行号 格式化调用堆栈
    EncodeName:可选值。

    具体EncoderConfig的说明,可以参考文件里面的注释
    go.uber.org/zapcore/encoder.go
    type EncoderConfig struct

    举个栗子

    你扯这么多配置说明,谁有时间看这玩意,写个常用的让大家照着用就好了嘛。

    package main
    
    import (
    	"fmt"
    	"go.uber.org/zap"
    	"go.uber.org/zap/zapcore"
    	"time"
    )
    
    var logger *zap.Logger
    func formatEncodeTime(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
    	enc.AppendString(fmt.Sprintf("%d%02d%02d_%02d%02d%02d", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second()))
    }
    
    func FormateLog(args []interface{}) *zap.Logger {
    	log := logger.With(ToJsonData(args))
    	return log
    }
    
    func Debug(msg string, args ...interface{}) {
    	FormateLog(args).Sugar().Debugf(msg)
    }
    
    func ToJsonData(args []interface{}) zap.Field {
    	det := make([]string, 0)
    	if len(args) > 0 {
    		for _, v := range args {
    			det = append(det, fmt.Sprintf("%+v", v))
    		}
    	}
    	zap := zap.Any("detail", det)
    	return zap
    }
    
    func InitZapLog() {
    	cfg := zap.Config{
    		Level:       zap.NewAtomicLevelAt(zap.DebugLevel),
    		Development: true,
    		Encoding:    "json",
    		EncoderConfig: zapcore.EncoderConfig{
    			TimeKey:        "t",
    			LevelKey:       "level",
    			NameKey:        "logger",
    			CallerKey:      "caller",
    			MessageKey:     "msg",
    			StacktraceKey:  "trace",
    			LineEnding:     zapcore.DefaultLineEnding,
    			EncodeLevel:    zapcore.LowercaseLevelEncoder,
    			EncodeTime:     formatEncodeTime,
    			EncodeDuration: zapcore.SecondsDurationEncoder,
    			EncodeCaller:   zapcore.ShortCallerEncoder,
    		},
    		OutputPaths:      []string{"/tmp/zap.log"},
    		ErrorOutputPaths: []string{"/tmp/zap.log"},
    		InitialFields: map[string]interface{}{
    			"app": "test",
    		},
    	}
    	var err error
    	logger, err = cfg.Build()
    	if err != nil {
    		panic("log init fail:" + err.Error())
    	}
    }
    
    func main() {
    	InitZapLog()
    	defer logger.Sync()
    	a := []string{"test","hello","world"}
    	Debug("output",a)
    }
    

    执行下,就会在日志文件上输入按照我们配置日志格式。

    tail -f /tmp/zap.log
    {"level":"debug","t":"20190630_044053","caller":"myproject/main.go:21","msg":"output","app":"test","detail":["[test hello world]"]}
    

    然后我们试下控制台输出,修改三个console相关的配置代码
    ···
    OutputPaths: []string{"stdout"},
    ErrorOutputPaths: []string{"stdout"},
    控制台窗口就会输出
    {"level":"debug","t":"20190630_092533","caller":"myproject/main.go:21","msg":"output","app":"test","detail":["[test hello world]"]}
    ···

    当然了,zap最想的使用和文档,看官网嘛
    https://github.com/uber-go/zap
    https://godoc.org/go.uber.org/zap

  • 相关阅读:
    Linux安装python3.6
    Django之Model操作
    Django
    html学习笔记-XML-Javascript
    html学习笔记-XML
    html学习笔记-DOM
    在IDEA中编辑struts国际化properties文件
    Java中的Serializable接口和transient关键字
    关于Kettle的事务和转换内步骤的顺序执行
    Mac、Linux下两个Emacs共享一个配置文件
  • 原文地址:https://www.cnblogs.com/feixiangmanon/p/11109174.html
Copyright © 2011-2022 走看看