最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語言Zap日志庫使用教程

 更新時(shí)間:2023年02月20日 10:13:14   作者:尋找09之夏  
在項(xiàng)目開發(fā)中,經(jīng)常需要把程序運(yùn)行過程中各種信息記錄下來,有了詳細(xì)的日志有助于問題排查和功能優(yōu)化;但如何選擇和使用性能好功能強(qiáng)大的日志庫,這個(gè)就需要我們從多角度考慮

一、日志庫選型需要和比較

1.日志庫選型需求

  • 日志性能
  • 不同日志級(jí)別
  • 可讀性(包括日志采集、監(jiān)控等)
  • 文件切割(不同維度分割)

2.日志庫比較

記錄一條消息和 10 個(gè)字段:

PackageTimeTime % to zapObjects Allocated
? zap2900 ns/op+0%5 allocs/op
? zap (sugared)3475 ns/op+20%10 allocs/op
zerolog10639 ns/op+267%32 allocs/op
go-kit14434 ns/op+398%59 allocs/op
logrus17104 ns/op+490%81 allocs/op
apex/log32424 ns/op+1018%66 allocs/op
log1533579 ns/op+1058%76 allocs/op

使用已經(jīng)有 10 個(gè)上下文字段的記錄器記錄消息:

PackageTimeTime % to zapObjects Allocated
? zap373 ns/op+0%0 allocs/op
? zap (sugared)452 ns/op+21%1 allocs/op
zerolog288 ns/op-23%0 allocs/op
go-kit11785 ns/op+3060%58 allocs/op
logrus19629 ns/op+5162%70 allocs/op
log1521866 ns/op+5762%72 allocs/op
apex/log30890 ns/op+8182%55 allocs/op

記錄一個(gè)靜態(tài)字符串,沒有任何上下文或 printf 樣式的模板:

PackageTimeTime % to zapObjects Allocated
? zap381 ns/op+0%0 allocs/op
? zap (sugared)410 ns/op+8%1 allocs/op
zerolog369 ns/op-3%0 allocs/op
standard library385 ns/op+1%2 allocs/op
go-kit606 ns/op+59%11 allocs/op
logrus1730 ns/op+354%25 allocs/op
apex/log1998 ns/op+424%7 allocs/op
log154546 ns/op+1093%22 allocs/op

通過上面benchmark測(cè)試可以Zap性能是非常出眾的。主要是大多數(shù)日志庫提供的方式是基于反射的序列化和字符串格式化,這種方式代價(jià)太高,而 Zap 采取不同的方法。

  • 避免 interface{} 使用強(qiáng)類型設(shè)計(jì)
  • 封裝強(qiáng)類型,無反射
  • 使用零分配內(nèi)存的 JSON 編碼器,盡可能避免序列化開銷

二、Zap(Uber-go)

1.安裝

go get -u go.uber.org/zap

2.配置Zap Logger

Zap提供了兩種類型的日志記錄器:Sugared Logger、Logger。在每一微秒和每一次內(nèi)存分配都很重要的上下文中,使用Logger,內(nèi)存分配次數(shù)也更少,但它只支持強(qiáng)類型的結(jié)構(gòu)化日志記錄。對(duì)性能不是要求極致,建議使用SugaredLogger,支持結(jié)構(gòu)化和 printf 風(fēng)格的日志記錄。

2.1.Logger

  • 通過調(diào)用zap.NewProduction() | zap.NewDevelopment() | zap.Example()創(chuàng)建一個(gè) Logger。
  • 上面的每一個(gè)函數(shù)都將創(chuàng)建一個(gè) logger。唯一的區(qū)別在于它將記錄的信息不同。例如 production logger 默認(rèn)記錄調(diào)用函數(shù)信息、日期和時(shí)間等。
  • 通過 Logger 調(diào)用 Info/Error 等。
  • 默認(rèn)情況下日志都會(huì)打印到應(yīng)用程序的 console 界面。
package main
import (
	"errors"
	"go.uber.org/zap"
)
var logger *zap.Logger
func main() {
	InitLogger()
	logger.Debug("這是一條日志", zap.String("name", "zhangSang"), zap.Int("age", 18)) // zap.NewProduction() 默認(rèn)不輸出該級(jí)別日志
	logger.Info("這是一條日志", zap.String("name", "zhangSang"), zap.Int("age", 18))
	logger.Error("這是一條日志", zap.String("name", "zhangSang"), zap.Error(errors.New("錯(cuò)誤信息")))
}
func InitLogger() {
	logger, _ = zap.NewProduction()
	defer logger.Sync()
}

上面代碼執(zhí)行結(jié)果:

{"level":"info","ts":1655165315.1104648,"caller":"test/main.go:13","msg":"這是一條日志","name":"zhangSang","age":18}
{"level":"error","ts":1655165315.1105008,"caller":"test/main.go:14","msg":"這是 一條日志","name":"zhangSang","error":"錯(cuò)誤信息","stacktrace":"main.main\n\tD:/Go/Work/src/test/main.go:14\nruntime.main\n\tD:/Go/src/runtime/proc.go:255"

2.2.Sugared Logger

  • 基本實(shí)現(xiàn)都一樣,使用SugaredLogger支持Printf格式記錄語句
  • 調(diào)用logger的sugar()方法來獲取一個(gè)SugaredLogger
package main
import (
	"errors"
	"go.uber.org/zap"
)
var logger *zap.Logger
var sugar *zap.SugaredLogger
func main() {
	InitLogger()
	sugar.Debug("這是一條日志", zap.String("name", "zhangSang"), zap.Int("age", 18)) // zap.NewProduction() 默認(rèn)不輸出該級(jí)別日志
	sugar.Info("這是一條日志", zap.String("name", "zhangSang"), zap.Int("age", 18))
	sugar.Error("這是一條日志", zap.String("name", "zhangSang"), zap.Error(errors.New("錯(cuò)誤信息")))
}
func InitLogger() {
	logger, _ = zap.NewProduction()
	defer logger.Sync()
	sugar = logger.Sugar()
}

上面代碼執(zhí)行結(jié)果:

{"level":"info","ts":1655165815.3873067,"caller":"test/main.go:14","msg":"這是一條日志{name 15 0 zhangSang <nil>} {age 11 18  <nil>}"}
{"level":"error","ts":1655165815.3880382,"caller":"test/main.go:15","msg":"這是一條日志{name 15 0 zhangSang <nil>} {error 26 0  錯(cuò)誤信息}","stacktrace":"main.main\n\tD:/GoWork/src/test/main.go:15\nruntime.main\n\tD:/Go/src/runtime/proc.go:255"}

2.3. 配置Logger

zap.New()方法來手動(dòng)傳遞所有配置,而不是使用像zap.NewProduction()這樣的預(yù)置方法來創(chuàng)建 logger;zapcore.Core需要三個(gè)配置——Encoder,WriteSyncer,LogLevel。

func New(core zapcore.Core, options ...Option) *Logger

1.Encoder: 編碼器 (配置日志格式)。此處使用NewJSONEncoder() (如果不喜歡JSON格式日志,NewConsoleEncoder()指定普通 Encoder),并使用預(yù)先設(shè)置的ProductionEncoderConfig(),ProductionEncoderConfig()返回一個(gè)自定義的EncoderConfig。

func getEncoder() zapcore.Encoder {
	encoderConfig := zap.NewProductionEncoderConfig()
	return zapcore.NewJSONEncoder(encoderConfig)
}

2.WriterSyncer :指定日志寫到何處。使用zapcore.AddSync()函數(shù)并且將打開的文件句柄傳入。

func getLogWriter() zapcore.WriteSyncer {
	file, _ := os.OpenFile("./test.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666) // 打開文件(不存在創(chuàng)建)
	return zapcore.AddSync(file)
}

3.Log Level-指定日志級(jí)別

func InitLogger() {
	writeSyncer := getLogWriter()
	encoder := getEncoder()
	core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel) // DebugLevel
	logger = zap.New(core)
	defer logger.Sync()
	sugarLogger = logger.Sugar()
}

大家將上面的方法新增測(cè)試代碼中,運(yùn)行結(jié)果:

4.時(shí)間格式化處理

func getEncoder() zapcore.Encoder {
	encoderConfig := zap.NewProductionEncoderConfig()
	encoderConfig.EncodeTime = customTimeEncoder
	return zapcore.NewJSONEncoder(encoderConfig)
}
func customTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
	enc.AppendString(t.Format("2006-01-02 15:04:05.000"))
}

運(yùn)行結(jié)果:

5.輸出文件名和行號(hào)

zap.New()中加上zap.AddCaller()。

func InitLogger() {
	writeSyncer := getLogWriter()
	encoder := getEncoder()
	core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel) // DebugLevel
	logger = zap.New(core, zap.AddCaller())
	defer logger.Sync()
	sugarLogger = logger.Sugar()
}

運(yùn)行結(jié)果:

三.使用 Lumberjack 進(jìn)行日志切割歸檔

1. 安裝

go get -u github.com/natefinch/lumberjack

2.Zap logger中使用Lumberjack

func getLogWriter() zapcore.WriteSyncer {
	lumberJackLogger := &lumberjack.Logger{
		Filename:   "./test.log", // 日志文件位置
		MaxSize:    1,            // 進(jìn)行切割之前,日志文件最大值(單位:MB),默認(rèn)100MB
		MaxBackups: 10,           // 保留舊文件的最大個(gè)數(shù)
		MaxAge:     1,            // 保留舊文件的最大天數(shù)
		Compress:   false,        // 是否壓縮/歸檔舊文件
	}
	return zapcore.AddSync(lumberJackLogger)
}

3.完整代碼

package main
import (
	"github.com/natefinch/lumberjack"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"time"
)
var logger *zap.Logger
var sugar *zap.SugaredLogger
func main() {
	InitLogger()
	for i := 0; i < 99999; i++ {
		sugar.Debugf("查詢用戶信息開始 id:%d", 1)
		sugar.Infof("查詢用戶信息成功 name:%s age:%d", "zhangSan", 20)
		sugar.Errorf("查詢用戶信息失敗 error:%v", "未該查詢到該用戶信息")
	}
}
func InitLogger() {
	writeSyncer := getLogWriter()
	encoder := getEncoder()
	core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)
	logger = zap.New(core, zap.AddCaller())
	defer logger.Sync()
	sugar = logger.Sugar()
}
func getEncoder() zapcore.Encoder {
	encoderConfig := zap.NewProductionEncoderConfig()
	encoderConfig.EncodeTime = customTimeEncoder
	return zapcore.NewJSONEncoder(encoderConfig)
}
func getLogWriter() zapcore.WriteSyncer {
	lumberJackLogger := &lumberjack.Logger{
		Filename:   "./test.log", // 日志文件位置
		MaxSize:    1,            // 進(jìn)行切割之前,日志文件最大值(單位:MB),默認(rèn)100MB
		MaxBackups: 5,            // 保留舊文件的最大個(gè)數(shù)
		MaxAge:     1,            // 保留舊文件的最大天數(shù)
		Compress:   false,        // 是否壓縮/歸檔舊文件
	}
	return zapcore.AddSync(lumberJackLogger)
}
func customTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
	enc.AppendString(t.Format("2006-01-02 15:04:05.000"))
}

在main()函數(shù)中循環(huán)9999次輸出日志,運(yùn)行結(jié)果:

總結(jié)

zap日志庫很強(qiáng)大,性能優(yōu)勢(shì)以及絕塵,里面的設(shè)計(jì)和工程實(shí)踐很指的學(xué)習(xí),有興趣的盆友可以看看。

到此這篇關(guān)于Go語言Zap日志庫使用教程的文章就介紹到這了,更多相關(guān)Go Zap日志庫內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語言實(shí)現(xiàn)切片增刪改查的示例代碼

    Go語言實(shí)現(xiàn)切片增刪改查的示例代碼

    這篇文章主要為大家詳細(xì)介紹了Go語言中切片的使用(增刪改查),文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Go語言有一定的幫助,需要的可以參考一下
    2022-04-04
  • Go中過濾范型集合性能示例詳解

    Go中過濾范型集合性能示例詳解

    這篇文章主要為大家介紹了Go中過濾范型集合性能示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 深入了解Golang中的Slice底層實(shí)現(xiàn)

    深入了解Golang中的Slice底層實(shí)現(xiàn)

    本文主要為大家詳細(xì)介紹了Golang中slice的底層實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2023-02-02
  • Go web入門Go pongo2模板引擎

    Go web入門Go pongo2模板引擎

    這篇文章主要為大家介紹了Go web編程入門Go pongo2模板引擎使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • 詳解Go語言如何檢查系統(tǒng)命令是否可用

    詳解Go語言如何檢查系統(tǒng)命令是否可用

    這篇文章主要為大家詳細(xì)介紹了Go語言通過編寫一個(gè)函數(shù),利用Go語言標(biāo)準(zhǔn)庫中的功能來檢查系統(tǒng)命令是否可用,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01
  • Go語言中的package和go modules的實(shí)現(xiàn)

    Go語言中的package和go modules的實(shí)現(xiàn)

    本文主要介紹了Go語言中的package和go modules的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-07-07
  • go語言用八百行代碼實(shí)現(xiàn)一個(gè)JSON解析器

    go語言用八百行代碼實(shí)現(xiàn)一個(gè)JSON解析器

    這篇文章主要為大家介紹了go語言用八百行代碼實(shí)現(xiàn)一個(gè)JSON解析器實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • Go語言中如何進(jìn)行包管理

    Go語言中如何進(jìn)行包管理

    在Go語言中,包(package)是函數(shù)和數(shù)據(jù)的集合,用于組織代碼,實(shí)現(xiàn)模塊化開發(fā),本文將結(jié)合實(shí)際案例,詳細(xì)講解Go語言包管理的用法,有需要的可以參考下
    2024-10-10
  • Golang對(duì)struct字段重新排序優(yōu)化數(shù)據(jù)結(jié)構(gòu)性能實(shí)踐

    Golang對(duì)struct字段重新排序優(yōu)化數(shù)據(jù)結(jié)構(gòu)性能實(shí)踐

    這篇文章主要為大家介紹了Golang對(duì)struct字段重新排序優(yōu)化數(shù)據(jù)結(jié)構(gòu)性能實(shí)踐,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • Go語言實(shí)現(xiàn)圖片快遞信息識(shí)別的簡(jiǎn)易方法

    Go語言實(shí)現(xiàn)圖片快遞信息識(shí)別的簡(jiǎn)易方法

    這篇文章主要為大家介紹了Go語言實(shí)現(xiàn)圖片快遞信息識(shí)別的簡(jiǎn)易方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10

最新評(píng)論

沁水县| 千阳县| 大庆市| 南丰县| 红安县| 梓潼县| 菏泽市| 阿城市| 阆中市| 重庆市| 易门县| 察隅县| 昌黎县| 喀什市| 遵义县| 衡南县| 五指山市| 特克斯县| 二连浩特市| 噶尔县| 南溪县| 敦煌市| 抚松县| 开平市| 新疆| 南投县| 东明县| 兴安县| 罗城| 上杭县| 县级市| 日土县| 黄大仙区| 荣成市| 彭山县| 白河县| 浦城县| 广德县| 巴南区| 成武县| 蛟河市|