天天看點

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 即"\n"

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

zap