1. 程式人生 > 程式設計 >golang有用的庫及工具 之 zap.Logger包的使用指南

golang有用的庫及工具 之 zap.Logger包的使用指南

zap.Logger 是go語言中相對日誌庫中效能最高的。那麼如何開始使用?

不多說直接上程式碼:

import (
  "encoding/json"
  "fmt"
  "log"
  "go.uber.org/zap"
  "go.uber.org/zap/zapcore"
)
var Logger *zap.Logger
func InitLogger() {
  // 日誌地址 "out.log" 自定義
  lp := Conf.Common.LogPath
  // 日誌級別 DEBUG,ERROR,INFO
  lv := Conf.Common.LogLevel
  // 是否 DEBUG
  isDebug := true
  if Conf.Common.IsDebug != true {
   isDebug = false
  }
  initLogger(lp,lv,isDebug)
  log.SetFlags(log.Lmicroseconds | log.Lshortfile | log.LstdFlags)
}
func initLogger(lp string,lv string,isDebug bool) {
  var js string
  if isDebug {
   js = fmt.Sprintf(`{
   "level": "%s","encoding": "json","outputPaths": ["stdout"],"errorOutputPaths": ["stdout"]
   }`,lv)
  } else {
   js = fmt.Sprintf(`{
   "level": "%s","outputPaths": ["%s"],"errorOutputPaths": ["%s"]
   }`,lp,lp)
  }
  var cfg zap.Config
  if err := json.Unmarshal([]byte(js),&cfg); err != nil {
   panic(err)
  }
  cfg.EncoderConfig = zap.NewProductionEncoderConfig()
  cfg.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
  var err error
  Logger,err = cfg.Build()
  if err != nil {
   log.Fatal("init logger error: ",err)
  }
}

如何使用:

func TestInitLogger(t *testing.T) {
  InitLogger("out.log","DEBUG",false)
  s := []string{
   "hello info","hello error","hello debug","hello fatal",}
  Log.Info("info:",zap.String("s",s[0]))
  Log.Error("info:",s[1]))
  Log.Debug("info:",s[2]))
  Log.Fatal("info:",s[3]))
}

輸出:

{"level":"info","ts":"2017-10-25 13:45:42.332","caller":"logger/logger_test.go:16","msg":"info:","s":"hello info"}
{"level":"error","ts":"2017-10-25 13:45:42.396","caller":"logger/logger_test.go:17","s":"hello error","stacktrace":"go.uber.org/zap.Stack\n\tD:/gopath/src/go.uber.org/zap/field.go:191\ngo.uber.org/zap.(*Logger).check\n\tD:/gopath/src/go.uber.org/zap/logger.go:301\ngo.uber.org/zap.(*Logger).Error\n\tD:/gopath/src/go.uber.org/zap/logger.go:202\ngithub.com/corego/hermes/logger.TestInitLogger\n\tD:/gopath/src/github.com/corego/hermes/logger/logger_test.go:17\ntesting.tRunner\n\tD:/Program Files (x86)/go/src/testing/testing.go:746"}
{"level":"debug","caller":"logger/logger_test.go:18","s":"hello debug"}
{"level":"fatal","caller":"logger/logger_test.go:19","s":"hello fatal","stacktrace":"go.uber.org/zap.Stack\n\tD:/gopath/src/go.uber.org/zap/field.go:191\ngo.uber.org/zap.(*Logger).check\n\tD:/gopath/src/go.uber.org/zap/logger.go:301\ngo.uber.org/zap.(*Logger).Fatal\n\tD:/gopath/src/go.uber.org/zap/logger.go:235\ngithub.com/corego/hermes/logger.TestInitLogger\n\tD:/gopath/src/github.com/corego/hermes/logger/logger_test.go:19\ntesting.tRunner\n\tD:/Program Files (x86)/go/src/testing/testing.go:746"}

拓展:Golang成長之路:使用Zap來做日誌服務

我們在專案中,經常會記錄一些資料資訊到檔案中,或者日誌檔案。

例如nginx會有nginx訪問請求日誌,使用golang的時候,我也想做一個這樣的訪問日誌,所以我就找到了go的一個開源高效的日誌庫zap。

很多人也使用logrus或者go自帶的Logger(支援的東西太少,效能一般),具體為啥最後選擇了zap,是因為很多人說zap效能更高些,當然我自己沒有測試過。

golang有用的庫及工具 之 zap.Logger包的使用指南

1、安裝zap

go get -u go.uber.org/zap

如果沒反應,可能需要配置下代理,

go env -w GOPROXY=https://goproxy.cn

然後在執行安裝的命令。

2、簡單例項(預設配置)

Zap提供了兩種型別的日誌記錄器—Sugared Logger和Logger。

package main 
import (
  "go.uber.org/zap"
  "time"
)
 
func main() {
  // zap.NewDevelopment 格式化輸出
  logger,_ := zap.NewDevelopment()
  defer logger.Sync()
  logger.Info("測試",zap.String("url","http://www.baidu.com"),zap.Int("attempt",3),zap.Duration("backoff",time.Second),)
 
  // zap.NewProduction json序列化輸出
  logger,_ := zap.NewProduction()
  defer logger.Sync()
  logger.Info("測試",)
}

3、自定義配置

封裝好一個logger包

package logger 
import (
  "go.uber.org/zap"
  "go.uber.org/zap/zapcore"
  "time"
  "fmt"
)
 
var sugarLogger *zap.SugaredLogger
 
//格式化日期
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 InitConfig() *zap.SugaredLogger {
  encoderConfig := zapcore.EncoderConfig{
    TimeKey:    "ts",LevelKey:    "level",NameKey:    "logger",CallerKey:   "caller",MessageKey:   "msg",StacktraceKey: "stacktrace",LineEnding:   zapcore.DefaultLineEnding,EncodeLevel:  zapcore.LowercaseLevelEncoder,// 小寫編碼器
    EncodeTime:   formatEncodeTime,//時間格式
    EncodeDuration: zapcore.SecondsDurationEncoder,EncodeCaller:  zapcore.FullCallerEncoder,// 全路徑編碼器
  }
 
  // 設定日誌級別(預設info級別,可以根據需要設定級別)
  atom := zap.NewAtomicLevelAt(zap.InfoLevel)
 
  config := zap.Config{
    Level:      atom,// 日誌級別
    Development:   true,// 開發模式,堆疊跟蹤
    Encoding:     "json",// 輸出格式 console 或 json
    EncoderConfig:  encoderConfig,// 編碼器配置
    OutputPaths:   []string{"stdout",'需要寫入檔案的路徑'},// 日誌寫入檔案的地址
    ErrorOutputPaths: []string{"stderr",// 將系統內的error記錄到檔案的地址
  }
 
  // 構建日誌
  logger,_ := config.Build()
  sugarLogger = logger.Sugar()
  return sugarLogger 
}
 
func Debug(args ...interface{}) {
 sugarLogger.Debug(args...)
}
 
func Debugf(template string,args ...interface{}) {
 sugarLogger.Debugf(template,args...)
}
 
func Info(args ...interface{}) {
 sugarLogger.Info(args...)
}
 
func Infof(template string,args ...interface{}) {
 sugarLogger.Infof(template,args...)
}
 
func Infow(template string,args ...interface{}) {
 sugarLogger.Infow(template,args...)
}
 
func Warn(args ...interface{}) {
 sugarLogger.Warn(args...)
}
 
func Warnf(template string,args ...interface{}) {
 sugarLogger.Warnf(template,args...)
}
 
func Error(args ...interface{}) {
 sugarLogger.Error(args...)
}
 
func Errorf(template string,args ...interface{}) {
 sugarLogger.Errorf(template,args...)
}
 
func DPanic(args ...interface{}) {
 sugarLogger.DPanic(args...)
}
 
func DPanicf(template string,args ...interface{}) {
 sugarLogger.DPanicf(template,args...)
}
 
func Panic(args ...interface{}) {
 sugarLogger.Panic(args...)
}
 
func Panicf(template string,args ...interface{}) {
 sugarLogger.Panicf(template,args...)
}
 
func Fatal(args ...interface{}) {
 sugarLogger.Fatal(args...)
}
 
func Fatalf(template string,args ...interface{}) {
 sugarLogger.Fatalf(template,args...)
}

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:可選值。

使用案例

package main 
import (
 "logger"//匯入寫好的包(具體需要改為自己寫的路徑)
)
 
func main() {
 //初始化日誌配置
 logger.InitConfig()
 
 //寫入檔案
 logger.Infow("access_log","code",200,"ip",192.168.1.1,"Method","POST","url","www.baidu.com","latencyTime(ms)",1000,)
}

好了,這就是自己搗鼓的zap使用方法,希望能給大家一個參考,也希望大家多多支援我們。如有錯誤或未考慮完全的地方,望不吝賜教。