亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Go語(yǔ)言中配置實(shí)現(xiàn)Logger日志的功能詳解

 更新時(shí)間:2023年05月19日 09:50:56   作者:三杯溫開(kāi)水  
當(dāng)我們正式開(kāi)發(fā)go程序的時(shí)候,就會(huì)發(fā)現(xiàn)記錄程序日志已經(jīng)不是fmt.print這么簡(jiǎn)單了,所以我們需要專(zhuān)門(mén)的去存儲(chǔ)日志文件,這篇文章主要介紹了在Go語(yǔ)言中配置實(shí)現(xiàn)Logger日志的功能,感興趣的同學(xué)可以參考下文

為什么需要Logger

一般在開(kāi)發(fā)項(xiàng)目的時(shí)候我們都是需要一個(gè)存儲(chǔ)日志的文件,因?yàn)樵诓渴痦?xiàng)目以后,我們只能通過(guò)去篩查日志進(jìn)行檢索問(wèn)題,這時(shí)候日志是否可以呈現(xiàn)清晰這個(gè)對(duì)于我們進(jìn)行排查工作是十分重要的,所以Logger能否展示出我們最想要的錯(cuò)誤展示方式是很有必要的!本章節(jié)的案例是基于gin框架和viper進(jìn)行編寫(xiě)一個(gè)Logger的日志文件,使用zap日志庫(kù)進(jìn)行記錄日志,日志會(huì)根據(jù)yaml文件定義的 mode進(jìn)行判斷是否是開(kāi)發(fā)環(huán)境還是線上環(huán)境進(jìn)行寫(xiě)的。

實(shí)現(xiàn)Logger.go

首先看一下yaml文件的配置

在yaml文件中定義了一個(gè)app,app下面有一個(gè)mode,這個(gè)mode就是用來(lái)識(shí)別我們是開(kāi)發(fā)環(huán)境還是線上環(huán)境的。

app:
  name: "web_app"
  mode: "dev"
  port: 8080
  version: "v0.01"
log:
  level: "debug"
  filename: "web_app.log"
  max_size: 200
  max_age: 30
  max_backups: 7

settings的定義

var Conf AppConfig
type AppConfig struct {
	App   App         `mapstructure:"app" yaml:"app"`
	Log   LogConfig   `mapstructure:"log"`
}
type App struct {
	Name      string `mapstructure:"name"`
	Mode      string `mapstructure:"mode"`
	Version   string `mapstructure:"version"`
	Port      int    `mapstructure:"port" yaml:"port"`
}
type LogConfig struct {
	Level      string `mapstructure:"level"`
	Filename   string `mapstructure:"filename"`
	MaxSize    int    `mapstructure:"max_size"`
	MaxAge     int    `mapstructure:"max_age"`
	MaxBackups int    `mapstructure:"max_backups"`
}

Logger.go

這里需要結(jié)合自己的實(shí)際進(jìn)行修改,如果復(fù)制了import中的依賴(lài),需要執(zhí)行一下:go mod tidy

package logger
import(
	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)
var logger *zap.Logger
// Init 的兩個(gè)參數(shù): cfg 和 mode
func Init(cfg *settings.LogConfig, mode string) (err error) {
	writeSyncer := getLogWriter(cfg.Filename, cfg.MaxSize, cfg.MaxBackups, cfg.MaxAge)
	encoder := getEncoder()
	var l = new(zapcore.Level)
	err = l.UnmarshalText([]byte(cfg.Level))
	if err != nil {
		return err
	}
	var core zapcore.Core
	// 開(kāi)發(fā)模式,日志輸出終端
	if mode == "dev" {
		consoleEncoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
		core = zapcore.NewTee(
			zapcore.NewCore(encoder, writeSyncer, l), // 保存在日志中
			// 錯(cuò)誤信息展示在終端
			zapcore.NewCore(consoleEncoder, zapcore.Lock(os.Stdout), zapcore.DebugLevel), 
		)
	} else {
		core = zapcore.NewCore(encoder, writeSyncer, l)
	}
	logger = zap.New(core, zap.AddCaller())
	lg := zap.New(core, zap.AddCaller())
	// 替換zap庫(kù)中的全局
	zap.ReplaceGlobals(lg)
	return err
}
func getEncoder() zapcore.Encoder {
	//return zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
	encodeConfig := zapcore.EncoderConfig{
		LevelKey:       "level",
		TimeKey:        "ts",
		NameKey:        "logger",
		CallerKey:      "caller",
		StacktraceKey:  "stacktrace",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.LowercaseLevelEncoder,
		EncodeTime:     zapcore.ISO8601TimeEncoder,
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}
	//return zapcore.NewConsoleEncoder(zap.NewProductionEncoderConfig())
	return zapcore.NewConsoleEncoder(encodeConfig)
}
// GinLogger 接收gin框架默認(rèn)的日志
func GinLogger() 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)
		zap.L().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 getLogWriter(string, int, int, int) zapcore.WriteSyncer {
	lumberJackLogger := &lumberjack.Logger{
		Filename:   viper.GetString("log.filename"),
		MaxSize:    viper.GetInt("log.max_size"),    // 單位是M
		MaxBackups: viper.GetInt("log.max_backups"), // 備份數(shù)量
		MaxAge:     viper.GetInt("log.max_age"),     // 最大備份天數(shù)
		Compress:   false,                           // 是否壓縮
	}
	return zapcore.AddSync(lumberJackLogger)
}
func GinRecovery(stack bool) gin.HandlerFunc {
	return func(c *gin.Context) {
		defer func() {
			if err := recover(); err != nil {
				// Check for a broken connection, as it is not really a
				// condition that warrants a panic stack trace.
				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 {
					zap.L().Error(c.Request.URL.Path,
						zap.Any("error", err),
						zap.String("request", string(httpRequest)),
					)
					// If the connection is dead, we can't write a status to it.
					c.Error(err.(error)) // nolint: errcheck
					c.Abort()
					return
				}
				if stack {
					zap.L().Error("[Recovery from panic]",
						zap.Any("error", err),
						zap.String("request", string(httpRequest)),
						zap.String("stack", string(debug.Stack())),
					)
				} else {
					zap.L().Error("[Recovery from panic]",
						zap.Any("error", err),
						zap.String("request", string(httpRequest)),
					)
				}
				c.AbortWithStatus(http.StatusInternalServerError)
			}
		}()
		c.Next()
	}
}

最后在main.go中進(jìn)行注冊(cè)方法

func main() {
	//	1、加載配置文件
	if err := settings.Init(); err != nil {
		fmt.Println("init setting failed", err)
		return
	}
	//  2、初始化日志
	if err := logger.Init(&settings.Conf.Log, settings.Conf.App.Mode); err != nil {
		fmt.Printf("init logger failed, err:%v\n", err)
	}
	defer zap.L().Sync()
	zap.L().Debug("logger init success...")
}

在開(kāi)發(fā)環(huán)境(dev)中的測(cè)試結(jié)果

與自己想要的結(jié)果是一致的:

到此這篇關(guān)于Go語(yǔ)言中配置實(shí)現(xiàn)Logger日志的功能詳解的文章就介紹到這了,更多相關(guān)Go配置Logger日志內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang操作DuckDB實(shí)戰(zhàn)案例分享

    Golang操作DuckDB實(shí)戰(zhàn)案例分享

    DuckDB是一個(gè)嵌入式SQL數(shù)據(jù)庫(kù)引擎,它與眾所周知的SQLite非常相似,但它是為olap風(fēng)格的工作負(fù)載設(shè)計(jì)的,DuckDB支持各種數(shù)據(jù)類(lèi)型和SQL特性,憑借其在以?xún)?nèi)存為中心的環(huán)境中處理高速分析的能力,它迅速受到數(shù)據(jù)科學(xué)家和分析師的歡迎,在這篇博文中,我們將探索在Go中使用DuckDB
    2025-01-01
  • 詳解go-zero如何實(shí)現(xiàn)計(jì)數(shù)器限流

    詳解go-zero如何實(shí)現(xiàn)計(jì)數(shù)器限流

    這篇文章主要來(lái)和大家說(shuō)說(shuō)限流,主要包括計(jì)數(shù)器限流算法以及具體的代碼實(shí)現(xiàn),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-08-08
  • golang套接字的實(shí)現(xiàn)

    golang套接字的實(shí)現(xiàn)

    Go語(yǔ)言中通過(guò)標(biāo)準(zhǔn)庫(kù)net實(shí)現(xiàn)套接字編程,涵蓋了TCP和UDP兩種網(wǎng)絡(luò)類(lèi)型,通過(guò)這些基本概念和實(shí)際代碼示例,可以幫助理解和掌握Go語(yǔ)言中的套接字編程
    2024-10-10
  • GoLang使goroutine停止的五種方法實(shí)例

    GoLang使goroutine停止的五種方法實(shí)例

    goroutine是Go并行設(shè)計(jì)的核心,下面這篇文章主要給大家介紹了關(guān)于GoLang使goroutine停止的五種方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07
  • 如何利用Golang寫(xiě)出高并發(fā)代碼詳解

    如何利用Golang寫(xiě)出高并發(fā)代碼詳解

    今天領(lǐng)導(dǎo)問(wèn)起為什么用Golang,同事回答語(yǔ)法簡(jiǎn)單,語(yǔ)言新,支持高并發(fā)。那高并發(fā)到底如何實(shí)現(xiàn),下面這篇文章主要給大家介紹了關(guān)于如何利用Golang寫(xiě)出高并發(fā)代碼的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-09-09
  • Golang?內(nèi)存模型The?Go?Memory?Model

    Golang?內(nèi)存模型The?Go?Memory?Model

    這篇文章主要為大家介紹了Golang?內(nèi)存模型The?Go?Memory?Model實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • Go語(yǔ)言利用ffmpeg轉(zhuǎn)hls實(shí)現(xiàn)簡(jiǎn)單視頻直播

    Go語(yǔ)言利用ffmpeg轉(zhuǎn)hls實(shí)現(xiàn)簡(jiǎn)單視頻直播

    這篇文章主要為大家介紹了Go語(yǔ)言利用ffmpeg轉(zhuǎn)hls實(shí)現(xiàn)簡(jiǎn)單視頻直播,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-04-04
  • GO的基礎(chǔ)知識(shí)掃盲注意事項(xiàng)

    GO的基礎(chǔ)知識(shí)掃盲注意事項(xiàng)

    這篇文章主要介紹了GO的基礎(chǔ)知識(shí)注意事項(xiàng),本文是GO語(yǔ)言小白的掃盲文,主要講解了go語(yǔ)言的基本知識(shí),GO程序目錄結(jié)構(gòu),GO程序包的導(dǎo)入與別名運(yùn)用,GO內(nèi)置關(guān)鍵字,GO注釋方法需要的朋友可以參考下
    2022-12-12
  • Go語(yǔ)言實(shí)現(xiàn)類(lèi)似c++中的多態(tài)功能實(shí)例

    Go語(yǔ)言實(shí)現(xiàn)類(lèi)似c++中的多態(tài)功能實(shí)例

    Go本身不具有多態(tài)的特性,不能夠像Java、C++那樣編寫(xiě)多態(tài)類(lèi)、多態(tài)方法。但是,使用Go可以編寫(xiě)具有多態(tài)功能的類(lèi)綁定的方法。下面來(lái)一起看看吧
    2016-09-09
  • Go 實(shí)現(xiàn)基于Token 的登錄流程深度分析

    Go 實(shí)現(xiàn)基于Token 的登錄流程深度分析

    Token 認(rèn)證機(jī)制的核心思想是,服務(wù)端在用戶(hù)登錄時(shí)生成一個(gè) Token,客戶(hù)端在后續(xù)的請(qǐng)求中攜帶這個(gè) Token,服務(wù)端通過(guò)驗(yàn)證 Token 的有效性來(lái)確認(rèn)用戶(hù)的身份,本文將帶你深入探索基于 Token 的登錄流程,這是一種更為靈活且適用于現(xiàn)代應(yīng)用架構(gòu)的認(rèn)證方式
    2024-03-03

最新評(píng)論