一文帶你入門golang中zap日誌基本應用

關於golang中其他各種日誌插件對比,這裏不再贅述,直奔zap主題,理論小結+實戰

目錄

前言

使用小結

動手實戰

基於zap+file-rotatelogs實現按天分隔日誌

基於zap+lumberjack實現按天分隔日誌 

寫在最後


前言

爲什麼選擇zap:

  • zap是非常快的、結構化的,分日誌級別的Go日誌庫
  • 它同時提供了結構化日誌記錄和printf風格的日誌記錄

以下是Zap發佈的基準測試信息

記錄一條消息和10個字段:

Package Time Time % to zap Objects Allocated
⚡️ zap 862 ns/op +0% 5 allocs/op
⚡️ zap (sugared) 1250 ns/op +45% 11 allocs/op
zerolog 4021 ns/op +366% 76 allocs/op
go-kit 4542 ns/op +427% 105 allocs/op
apex/log 26785 ns/op +3007% 115 allocs/op
logrus 29501 ns/op +3322% 125 allocs/op
log15 29906 ns/op +3369% 122 allocs/op

使用小結

哎,之前思考的少,都是拿來主義,就知道用別人寫好的,自己搞,才發現不少細節。分享個小結:

  • 日誌按大小切割和備份個數、文件有效期,一般選zap+lumberjack
  • 日誌按天或者小時切割,一般選zap+file-rotatelogs

zap中Logger和SugaredLogger的區別:

  • Zap提供了兩種類型的日誌記錄器—SugaredLogger和Logger
  • 在性能很好但不是很關鍵的上下文中,使用SugaredLogger。它比其他結構化日誌記錄包快4-10倍,並且支持結構化和printf風格的日誌記錄
  • 在每一微秒和每一次內存分配都很重要的上下文中,使用Logger。它甚至比SugaredLogger更快,內存分配次數也更少,但它只支持強類型的結構化日誌記錄
  • SugaredLogger是在Logger的基礎上,提供了額外參數的格式化方式,提供更大的便利性以格式化具體的msg,在可能帶來風險的同時,還會造成額外的內存分配

動手實戰

基於zap+file-rotatelogs實現按天分隔日誌

實現功能點:

  • 按照不同級別日誌獨立文件記錄(可以參考info級別自己動手擴展下)
  • 日誌按天分割
  • 只保留近30天的日誌

 編碼:

package main

import (
	rotatelogs "github.com/lestrrat-go/file-rotatelogs"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"io"
	"strings"
	"time"
)

var errorLogger *zap.SugaredLogger

func init() {
	encoder := zapcore.NewJSONEncoder(zapcore.EncoderConfig{
		MessageKey:  "msg",
		LevelKey:    "level",
		EncodeLevel: zapcore.CapitalLevelEncoder,
		TimeKey:     "ts",
		EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
			enc.AppendString(t.Format("2006-01-02 15:04:05"))
		},
		CallerKey:    "call",
		EncodeCaller: zapcore.ShortCallerEncoder,
		EncodeDuration: func(d time.Duration, enc zapcore.PrimitiveArrayEncoder) {
			enc.AppendInt64(int64(d) / 1000000)
		},
	})

	infoLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
		return lvl >= zapcore.InfoLevel
	})

	infoWriter := getWriter("console_info.log")

	core := zapcore.NewTee(
		zapcore.NewCore(encoder, zapcore.AddSync(infoWriter), infoLevel),
	)

	//AddCallerSkip增加了調用者註釋跳過的調用者數量
	//大白話:就是顯示調用打印日誌的是哪一行的code行數,你可以改爲0看看效果,哈哈
	log := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1))
	errorLogger = log.Sugar()
}

func getWriter(filename string) io.Writer {
	hook, err := rotatelogs.New(
		strings.Replace(filename, ".log", "", -1) + "-%Y-%m-%d.log",
		//文件最大壽命30天
		rotatelogs.WithMaxAge(time.Hour*24*30),
		//每隔1天進行文件分割
		rotatelogs.WithRotationTime(time.Hour*24),
	)
	if err != nil {
		panic(err)
	}
	return hook
}
func Debug(args ...interface{}) {
	errorLogger.Debug(args...)
}

func Debugf(template string, args ...interface{}) {
	errorLogger.Debugf(template, args...)
}

func Info(args ...interface{}) {
	errorLogger.Info(args...)
}

func Infof(template string, args ...interface{}) {
	errorLogger.Infof(template, args...)
}

func Warn(args ...interface{}) {
	errorLogger.Warn(args...)
}

func Warnf(template string, args ...interface{}) {
	errorLogger.Warnf(template, args...)
}

func Error(args ...interface{}) {
	errorLogger.Error(args...)
}

func Errorf(template string, args ...interface{}) {
	errorLogger.Errorf(template, args...)
}

func DPanic(args ...interface{}) {
	errorLogger.DPanic(args...)
}

func DPanicf(template string, args ...interface{}) {
	errorLogger.DPanicf(template, args...)
}

func Panic(args ...interface{}) {
	errorLogger.Panic(args...)
}

func Panicf(template string, args ...interface{}) {
	errorLogger.Panicf(template, args...)
}

func Fatal(args ...interface{}) {
	errorLogger.Fatal(args...)
}

func Fatalf(template string, args ...interface{}) {
	errorLogger.Fatalf(template, args...)
}

func main() {
	Infof("Hello World")
}

效果如下:

基於zap+lumberjack實現按天分隔日誌 

實現功能點:

  • 按照500M文件大小切割文件
  • 最多保留200個文件
  • 最多保留30天
  • 支持文件壓縮

編碼:

package main

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

// error logger
var errorLogger *zap.SugaredLogger

var levelMap = map[string]zapcore.Level{
	"debug":  zapcore.DebugLevel,
	"info":   zapcore.InfoLevel,
	"warn":   zapcore.WarnLevel,
	"error":  zapcore.ErrorLevel,
	"dpanic": zapcore.DPanicLevel,
	"panic":  zapcore.PanicLevel,
	"fatal":  zapcore.FatalLevel,
}

func getLoggerLevel(lvl string) zapcore.Level {
	if level, ok := levelMap[lvl]; ok {
		return level
	}
	return zapcore.InfoLevel
}

//Filename: 日誌文件的位置
//MaxSize:在進行切割之前,日誌文件的最大大小(以MB爲單位)
//MaxBackups:保留舊文件的最大個數
//MaxAges:保留舊文件的最大天數
//Compress:是否壓縮/歸檔舊文件
func init() {
	fileName := "console.log"
	level := getLoggerLevel("debug")
	syncWriter := zapcore.AddSync(&lumberjack.Logger{
		Filename:   fileName,
		MaxSize:    500,
		MaxBackups: 200,
		MaxAge:     30,
		LocalTime:  true,
		Compress:   true,
	})
	encoder := zap.NewProductionEncoderConfig()
	encoder.EncodeTime = zapcore.ISO8601TimeEncoder
	core := zapcore.NewCore(zapcore.NewJSONEncoder(encoder), syncWriter, zap.NewAtomicLevelAt(level))
	logger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1))
	errorLogger = logger.Sugar()
}

func Debug(args ...interface{}) {
	errorLogger.Debug(args...)
}

func Debugf(template string, args ...interface{}) {
	errorLogger.Debugf(template, args...)
}

func Info(args ...interface{}) {
	errorLogger.Info(args...)
}

func Infof(template string, args ...interface{}) {
	errorLogger.Infof(template, args...)
}

func Warn(args ...interface{}) {
	errorLogger.Warn(args...)
}

func Warnf(template string, args ...interface{}) {
	errorLogger.Warnf(template, args...)
}

func Error(args ...interface{}) {
	errorLogger.Error(args...)
}

func Errorf(template string, args ...interface{}) {
	errorLogger.Errorf(template, args...)
}

func DPanic(args ...interface{}) {
	errorLogger.DPanic(args...)
}

func DPanicf(template string, args ...interface{}) {
	errorLogger.DPanicf(template, args...)
}

func Panic(args ...interface{}) {
	errorLogger.Panic(args...)
}

func Panicf(template string, args ...interface{}) {
	errorLogger.Panicf(template, args...)
}

func Fatal(args ...interface{}) {
	errorLogger.Fatal(args...)
}

func Fatalf(template string, args ...interface{}) {
	errorLogger.Fatalf(template, args...)
}

func main() {
	Infof("Hello World")
}

效果如下:

寫在最後

上面的僅僅是zap的基本應用,想玩的更加順手、深入,自己入門後多動手,遇到問題看看源碼。 

參考鏈接:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章