欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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測試可以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()
}

大家將上面的方法新增測試代碼中,運(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è)計(jì)和工程實(shí)踐很指的學(xué)習(xí),有興趣的盆友可以看看。

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

相關(guān)文章

  • go語言發(fā)送smtp郵件的實(shí)現(xiàn)示例

    go語言發(fā)送smtp郵件的實(shí)現(xiàn)示例

    這篇文章主要介紹了go發(fā)送smtp郵件的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Golang日志庫logrus的介紹與使用示例代碼

    Golang日志庫logrus的介紹與使用示例代碼

    Logrus是Go語言的一個(gè)功能豐富的日志庫,支持結(jié)構(gòu)化日志和多級(jí)別日志記錄,它兼容標(biāo)準(zhǔn)log庫,并可通過自定義Hooks和Formatter進(jìn)行高度定制化,支持集成如syslog等系統(tǒng),便于管理和分析,Logrus還支持自定義日志顏色和格式,以及根據(jù)日志級(jí)別進(jìn)行不同處理,如panic和exit
    2024-10-10
  • GO語言實(shí)現(xiàn)的http抓包分析工具pproxy介紹

    GO語言實(shí)現(xiàn)的http抓包分析工具pproxy介紹

    這篇文章主要介紹了GO語言實(shí)現(xiàn)的http抓包分析工具pproxy介紹,本文同時(shí)對(duì)比了Fiddler、Charles等抓包軟件,需要的朋友可以參考下
    2015-03-03
  • golang文件內(nèi)容覆蓋問題的分析及解決

    golang文件內(nèi)容覆蓋問題的分析及解決

    通過golang讀取數(shù)據(jù)庫站點(diǎn)映射配置,生成nginx conf文件,并檢查和重啟nginx服務(wù),已達(dá)到站點(diǎn)自動(dòng)化部署目的,當(dāng)目標(biāo)文件中內(nèi)容很長,而寫入的內(nèi)容很短時(shí),目標(biāo)文件內(nèi)容無法完全覆蓋,本文給大家介紹了解決方法,需要的朋友可以參考下
    2024-01-01
  • 詳解使用Go添加Nginx代理的方法示例

    詳解使用Go添加Nginx代理的方法示例

    這篇文章主要介紹了詳解使用Go添加Nginx代理的方法示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • 詳解如何在Go語言中生成隨機(jī)種子

    詳解如何在Go語言中生成隨機(jī)種子

    這篇文章主要為大家詳細(xì)介紹了如何在Go語言中生成隨機(jī)種子,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考一下
    2024-04-04
  • Go中的條件語句Switch示例詳解

    Go中的條件語句Switch示例詳解

    Go的switch的基本功能和C、Java類似,switch 語句用于基于不同條件執(zhí)行不同動(dòng)作,每一個(gè) case 分支都是唯一的,從上至下逐一測試,直到匹配為止,對(duì)Go條件語句Switch相關(guān)知識(shí)感興趣的朋友一起看看吧
    2021-08-08
  • Go語言中的延遲函數(shù)defer示例詳解

    Go語言中的延遲函數(shù)defer示例詳解

    眾所周知golang的defer優(yōu)雅又簡潔, 是golang的亮點(diǎn)之一。所以下面這篇文章主要給大家介紹了關(guān)于Go語言中延遲函數(shù)defer的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-10-10
  • Golang中的強(qiáng)大Web框架Fiber詳解

    Golang中的強(qiáng)大Web框架Fiber詳解

    在不斷發(fā)展的Web開發(fā)領(lǐng)域中,選擇正確的框架可以極大地影響項(xiàng)目的效率和成功,介紹一下Fiber,這是一款令人印象深刻的Golang(Go語言)Web框架,在本文中,我們將深入了解Fiber的世界,探討其獨(dú)特的特性,并理解為什么它在Go生態(tài)系統(tǒng)中引起了如此大的關(guān)注
    2023-10-10
  • golang限流庫兩個(gè)大bug(半年之久無人提起)

    golang限流庫兩個(gè)大bug(半年之久無人提起)

    最近我的同事在使用uber-go/ratelimit[1]這個(gè)限流庫的時(shí)候,遇到了兩個(gè)大?bug,這兩個(gè)?bug?都是在這個(gè)庫的最新版本(v0.3.0)中存在的,而這個(gè)版本從?7?月初發(fā)布都已經(jīng)過半年了,都沒人提?bug,難道大家都沒遇到過么
    2023-12-12

最新評(píng)論