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

Go日志管理Zap與Lumberjack實(shí)戰(zhàn)指南

 更新時(shí)間:2026年05月12日 09:15:31   作者:末旅  
本文主要介紹了日志常用功能、Go語(yǔ)言的Logger設(shè)置、Uber-goZap日志庫(kù)以及如何在Gin框架中添加Zap日志,文章指出,Go語(yǔ)言的Logger存在一些不足,而Zap日志庫(kù)則彌補(bǔ)了這些不足,提供了更快、更結(jié)構(gòu)化的日志記錄

日志常用功能

一般來(lái)說(shuō),在我們的項(xiàng)目中,我們都需要利用日志來(lái)提供以下功能:

  • 能夠?qū)⑷罩居涗浽谖募卸侵苯虞敵鲈诳刂婆_(tái)
  • 能夠根據(jù)日志大小,時(shí)間或間隔來(lái)切割日志文件
  • 能夠支持不同的日志級(jí)別,如INFO,DEBUG,ERROR等
  • 能夠打印基本信息,如調(diào)用文件\函數(shù)名\行號(hào)或日志時(shí)間等

因此,我們需要對(duì)Log進(jìn)行一定程度的設(shè)置來(lái)控制它的行為

Go語(yǔ)言的Logger

設(shè)置Logger

我們可以像下面的代碼一樣記錄我們的日志記錄器,一般來(lái)說(shuō)日志會(huì)被輸出在終端上,無(wú)法長(zhǎng)期存儲(chǔ),因此我們可以通過(guò)日志記錄器來(lái)控制日志的輸出

func SetuupLogger() {
    logFilelocation,_ := os.OpenFile("D:\\TryDir", os.O_CREATE|os.O_APPEND|os.RDWR,0744)
    //這里先打開(kāi)指定位置的文件,然后指定為日志輸出位置
    log.SetOutput(logFilelocation )
}

Go Logger的優(yōu)劣

優(yōu)勢(shì):

  • 使用簡(jiǎn)單,我們可以設(shè)置任何的io.writer作為日志記錄輸出并向其發(fā)送要寫(xiě)入的日志

劣勢(shì):

  • 只有基本的日志級(jí)別,只有Print選項(xiàng),不支持INFO\DEBUG等多個(gè)級(jí)別
  • 對(duì)于錯(cuò)誤的日志,它有Fatal和Panic,但缺少ERROR日志級(jí)別(可以在不拋出panic或退出程序的情況下記錄錯(cuò)誤)
  • 缺乏日志格式化的能力,比如記錄調(diào)用者的函數(shù)名或行號(hào),格式化日期或時(shí)間格式等
  • 不提供日志切割的能力

Uber-go Zap

既然Go Logger存在一些使用上的不完美,那就肯定會(huì)有人會(huì)去補(bǔ)充這一部分的缺失,也就是Zap日志庫(kù),Zap是一種非常快的,結(jié)構(gòu)化的,分日志級(jí)別的Go日志庫(kù),通過(guò)Zap官方的性能比較,可以得知,存儲(chǔ)相同的日志,Zap的內(nèi)存分配次數(shù)遠(yuǎn)小于其他的日志庫(kù),這也使得Zao擁有遠(yuǎn)超其他日志庫(kù)的性能

我們可以通過(guò)以下指令來(lái)安裝Zap:

go get -u go.uber.org/zap

Zap的配置以及使用

Zap提供兩種類型的日志記錄器--Sugared LoggerLogger,在性能很好但不是很關(guān)鍵的上下文中,使用SugaredLogger,他會(huì)比其他結(jié)構(gòu)化日志記錄包快4-10倍,且支持結(jié)構(gòu)化和printf風(fēng)格的日志記錄

在每一微秒和每一次內(nèi)存分配都很重要的上下文中,我們可以使用Logger,它甚至比SugaredLogger更快,內(nèi)存分配次數(shù)也更少,但它只支持強(qiáng)類型的結(jié)構(gòu)化日志記錄

Logger

我們可以通過(guò)調(diào)用zap.NewProduction()/zap.NewDevelopment()zap.Example()來(lái)創(chuàng)建一個(gè)Logger,這三者的區(qū)別僅在于創(chuàng)建出來(lái)的logger記錄的信息不同

package main
import (
	"net/http"
	"go.uber.org/zap"
)
var logger *zap.Logger
func main() {
	InitLogger()
	defer logger.Sync()
	simpleHttpGet("golang.google.cn/")
	simpleHttpGet("https://golang.google.cn/")
}
func InitLogger() {
	logger, _ = zap.NewProduction()
}
func simpleHttpGet(url string) {
	resp, err := http.Get(url)
	if err != nil {
		logger.Error( //記錄錯(cuò)誤級(jí)別的日志
			"Error fetching url..",
			zap.String("url", url), //添加字符串字段
			zap.Error(err))         //專門(mén)記錄error的類型,會(huì)自動(dòng)提取error信息
	} else {
		logger.Info("Success..", //記錄信息級(jí)別的日志
			zap.String("statusCode", resp.Status),
			zap.String("url", url))
		resp.Body.Close()
	}
}

定制Logger

話又回到最開(kāi)始,我們寫(xiě)日志肯定是為了長(zhǎng)期保存,或者在后期來(lái)查詢?nèi)罩?,因此需要一個(gè)能夠持久存儲(chǔ)的地方來(lái)存儲(chǔ)日志,即文件中,因此我們需要通過(guò)Zap.New()的方法來(lái)手動(dòng)傳遞所有配置而不是直接zap.NewProduction()來(lái)預(yù)制Logger

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

而其中的zapcore.Core則又需要三個(gè)配置:Encoder,WriteSyncer,LogLevel

Encoder[編碼器],該配置大多數(shù)情況下可以使用現(xiàn)成的參數(shù)

zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())  
//NewJSONEncoder開(kāi)箱即用,ProductionEncoderConfig也已經(jīng)預(yù)先設(shè)置好了

不過(guò)我們也可以使用NewConsoleEncoder的編碼器,來(lái)使我們的日志以純文本的形式傳輸而非JSON格式(不過(guò)大多數(shù)情況下還是JSON更常用),我們也可以對(duì)zap.NewProductionEncoderConfig()來(lái)進(jìn)行設(shè)置:

	EncoderConfig := zap.NewProductionEncoderConfig()
	EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
	encoder := zapcore.NewConsoleEncoder(EncoderConfig)
 //使用NewConsoleEncoder編碼器的話,日志會(huì)以純文本的形式寫(xiě)入日志文件,并添加Unix時(shí)間戳

需要注意的是,我們通常會(huì)使用JSON而非Console來(lái)設(shè)置編碼器,這是因?yàn)镃onsole的方式雖然對(duì)人來(lái)說(shuō)極其易懂且舒適,但對(duì)機(jī)器而言就是一串無(wú)意義的字符串,而JSON則全程使用鍵值對(duì)的形式,這樣對(duì)于機(jī)器而言簡(jiǎn)潔的嚇人,查詢信息時(shí)只需要匹配對(duì)應(yīng)的鍵來(lái)找值即可,而不是需要像Console那樣編寫(xiě)復(fù)雜的正則表達(dá)式

writeSyncer[寫(xiě)入同步器]:用來(lái)指定要將日志寫(xiě)到哪里,我們可以用zapcore.AddSync()函數(shù)來(lái)為其賦值

file, _ := os.Open("./Log.log")
writeSyncer := zapcore.AddSync(file)

Log Level:日志級(jí)別

通過(guò)這三個(gè)配置,我們就可以獲得我們自己設(shè)定的Core,并通過(guò)這個(gè)Core來(lái)自己New出一個(gè)自定義的logger

func InitLogger() {
	file, _ := os.OpenFile("D:\\TryDir\\Log.log", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
	writeSyncer := zapcore.AddSync(file)
	encoder := zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
	Core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)
	logger = zap.New(Core)
}

同時(shí)我們可以通過(guò)修改zap.New() 的第二個(gè)參數(shù)option來(lái)添加將調(diào)用函數(shù)信息記錄到日志中的功能

logger = zap.New(core,zap.AddCaller())

Lumberjack

由于Zap本身不支持切割歸檔日志文件,所以我們還需要另一個(gè)第三方庫(kù)來(lái)添加日志切割功能

go get gopkg.in/natefinch/lumberjack.v2

我們可以將原本構(gòu)成Core的三部分之一:writeSyncer的file文件改成適應(yīng)Lumberjack的形式:

	lumberjackLogger := &lumberjack.Logger{
		Filename:   "./Log.log", //日志文件路徑
		MaxSize:    5,           //日志文件最大尺寸 單位:MB
		MaxBackups: 5,           //日志文件最大保存份數(shù),即備份數(shù)量
		MaxAge:     30,          //日志文件最大備份保存天數(shù)
		Compress:   false,       //是否壓縮
	}
	writeSyncer := zapcore.AddSync(lumberjackLogger)

Gin框架添加Zap日志

我們可以通過(guò)gin.Default()來(lái)添加一個(gè)默認(rèn)的路由作為連接,這個(gè)路由會(huì)默認(rèn)使用Logger()Recovery()這兩個(gè)中間件,其中Logger()是把gin框架本身的日志輸出到標(biāo)準(zhǔn)輸出,而Recovery()則會(huì)在程序出現(xiàn)panic時(shí)恢復(fù)現(xiàn)場(chǎng)并寫(xiě)入500響應(yīng)。而我們想要用Zap來(lái)代替gin框架本身的日志輸出的話,就需要自己改寫(xiě)這兩個(gè)中間件,并使用gin.New()來(lái)創(chuàng)建路由而非gin.Default()。

func GinLogger(logger *zap.Logger) gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()
		path := c.Request.URL.Path
		query := c.Request.URL.RawQuery
		c.Next()
		cost := time.Since(start)
		logger.Info(path,
			zap.Int("status", c.Writer.Status()),
			zap.String("method", c.Request.Method),
			zap.String("path", path),
			zap.String("query", query),
			zap.String("ip", c.ClientIP()),
			zap.String("user-agent", c.Request.UserAgent()),
			zap.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()),
			zap.Duration("cost", cost),
		)
	}
}
func GinRecovery(logger *zap.Logger, stack bool) gin.HandlerFunc {
	return func(c *gin.Context) {
		defer func() {
			if err := recover(); err != nil {
				var brokenPipe bool
				if ne, ok := err.(*net.OpError); ok {
					if se, ok := ne.Err.(*os.SyscallError); ok {
						if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
							brokenPipe = true
						}
					}
				}
				httpRequest, _ := httputil.DumpRequest(c.Request, false)
				if brokenPipe {
					logger.Error(c.Request.URL.Path,
						zap.Any("error", err),
						zap.String("request", string(httpRequest)),
					)
					c.Error(err.(error))
					c.Abort()
					return
				}
				if stack {
					logger.Error("[Recovery from panic]",
						zap.Any("error", err),
						zap.String("request", string(httpRequest)),
						zap.String("stack", string(debug.Stack())),
					)
				} else {
					logger.Error("[Recovery from panic]",
						zap.Any("error", err),
						zap.String("request", string(httpRequest)),
					)
				}
				c.AbortWithStatus(http.StatusInternalServerError)
			}
		}()
		c.Next()
	}
}

到此這篇關(guān)于Go日志管理Zap與Lumberjack實(shí)戰(zhàn)指南的文章就介紹到這了,更多相關(guān)go zap與Lumberjack日志內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • golang中如何使用kafka方法實(shí)例探究

    golang中如何使用kafka方法實(shí)例探究

    Kafka是一種備受歡迎的流處理平臺(tái),具備分布式、可擴(kuò)展、高性能和可靠的特點(diǎn),在處理Kafka數(shù)據(jù)時(shí),有多種最佳實(shí)踐可用來(lái)確保高效和可靠的處理,這篇文章將介紹golang中如何使用kafka方法
    2024-01-01
  • 詳解Go語(yǔ)言中的內(nèi)存對(duì)齊

    詳解Go語(yǔ)言中的內(nèi)存對(duì)齊

    前面我們學(xué)習(xí)了Go語(yǔ)言空結(jié)構(gòu)體詳解,最近又在看unsafe包的知識(shí),在查閱相關(guān)資料時(shí)不免會(huì)看到內(nèi)存對(duì)齊相關(guān)的內(nèi)容。雖然不會(huì),但可以學(xué)呀,那么這篇文章,我們就一起來(lái)看下什么是內(nèi)存對(duì)齊吧
    2022-10-10
  • golang變量uint、int大小溢出后的結(jié)果方式

    golang變量uint、int大小溢出后的結(jié)果方式

    在Go語(yǔ)言中,變量的大小溢出后,`uint`類型會(huì)回繞到最小值,而`int`類型會(huì)回繞到最大值的相反數(shù),例如,`uint8`溢出后會(huì)變成0,`int64`溢出后會(huì)變成最小的負(fù)數(shù)
    2024-12-12
  • Golang?sync.Map底層實(shí)現(xiàn)場(chǎng)景示例詳解

    Golang?sync.Map底層實(shí)現(xiàn)場(chǎng)景示例詳解

    這篇文章主要為大家介紹了Golang?sync.Map底層實(shí)現(xiàn)及使用場(chǎng)景示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • Go語(yǔ)言使用GORM操作數(shù)據(jù)庫(kù)使用指南

    Go語(yǔ)言使用GORM操作數(shù)據(jù)庫(kù)使用指南

    GORM(全稱為Go?Object?Relational?Mapping)是一個(gè)在Go語(yǔ)言中使用的輕量級(jí)的對(duì)象關(guān)系映射(ORM)庫(kù),本文主要為大家介紹了GORM操作數(shù)據(jù)庫(kù)具體方法,需要的可以參考一下
    2023-05-05
  • Golang實(shí)現(xiàn)自己的Redis(TCP篇)實(shí)例探究

    Golang實(shí)現(xiàn)自己的Redis(TCP篇)實(shí)例探究

    這篇文章主要介紹了Golang實(shí)現(xiàn)自己的Redis(TCP篇)實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • 用Go快速上手Protocol Buffers詳解

    用Go快速上手Protocol Buffers詳解

    Protobuf是一種高效的跨語(yǔ)言序列化協(xié)議,適用于Go語(yǔ)言,本文介紹了如何安裝和使用Protobuf,包括定義協(xié)議、生成Go代碼、序列化和反序列化,以及版本演進(jìn)和兼容性,通過(guò)一個(gè)完整的示例,展示了如何在Go項(xiàng)目中使用Protobuf
    2025-11-11
  • 一文帶你了解Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)math和rand的常用函數(shù)

    一文帶你了解Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)math和rand的常用函數(shù)

    這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)math和rand中的常用函數(shù),文中的示例代碼講解詳細(xì), 對(duì)我們學(xué)習(xí)Go語(yǔ)言有一定的幫助,感興趣的小伙伴可以了解一下
    2022-12-12
  • golang原生http包實(shí)現(xiàn)各種情況的get請(qǐng)求方式

    golang原生http包實(shí)現(xiàn)各種情況的get請(qǐng)求方式

    這篇文章主要介紹了golang原生http包實(shí)現(xiàn)各種情況的get請(qǐng)求方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • 詳解Go中Set的實(shí)現(xiàn)方式

    詳解Go中Set的實(shí)現(xiàn)方式

    這篇文章主要介紹了詳解Go中Set的實(shí)現(xiàn)方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09

最新評(píng)論

三都| 南京市| 四子王旗| 台中县| 涡阳县| 牟定县| 朝阳市| 休宁县| 福安市| 舞阳县| 广东省| 无为县| 军事| 石林| 绩溪县| 安顺市| 安阳县| 丹阳市| 马公市| 营山县| 绥宁县| 离岛区| 平谷区| 乐业县| 英超| 岱山县| 文化| 上蔡县| 贵阳市| 通化市| 剑阁县| 凤山市| 瓦房店市| 建始县| 芦山县| 定日县| 抚州市| 南宁市| 浦北县| 郧西县| 安溪县|