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

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

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

為什么需要Logger

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

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

首先看一下yaml文件的配置

在yaml文件中定義了一個app,app下面有一個mode,這個mode就是用來識別我們是開發(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中的依賴,需要執(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 的兩個參數(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
	// 開發(fā)模式,日志輸出終端
	if mode == "dev" {
		consoleEncoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
		core = zapcore.NewTee(
			zapcore.NewCore(encoder, writeSyncer, l), // 保存在日志中
			// 錯誤信息展示在終端
			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庫中的全局
	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)行注冊方法

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...")
}

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

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

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

相關(guān)文章

  • Go語言crypto包創(chuàng)建自己的密碼加密工具實(shí)現(xiàn)示例

    Go語言crypto包創(chuàng)建自己的密碼加密工具實(shí)現(xiàn)示例

    Go語言借助它的簡單性和強(qiáng)大的標(biāo)準(zhǔn)庫,實(shí)現(xiàn)一個自己的密碼加密工具,本文將會結(jié)合代碼示例深入探討如何使用Go語言的crypto包來實(shí)現(xiàn)自己的加密工具
    2023-11-11
  • Go 實(shí)現(xiàn)HTTP中間人代理的操作

    Go 實(shí)現(xiàn)HTTP中間人代理的操作

    這篇文章主要介紹了Go 實(shí)現(xiàn)HTTP中間人代理的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • 使用go備份StarRocks建表語句方法實(shí)例

    使用go備份StarRocks建表語句方法實(shí)例

    這篇文章主要為大家介紹了使用go備份StarRocks建表語句方法實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • golang實(shí)現(xiàn)圖像驗(yàn)證碼的示例代碼

    golang實(shí)現(xiàn)圖像驗(yàn)證碼的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用golang實(shí)現(xiàn)簡單的圖像驗(yàn)證碼,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-10-10
  • Go語言中一定要知道的切片使用注意事項(xiàng)總結(jié)

    Go語言中一定要知道的切片使用注意事項(xiàng)總結(jié)

    了解和掌握切片的使用注意事項(xiàng),可以避免意外的程序行為,所以本文就來和大家深入探討一下Go語言切片常見的注意事項(xiàng),希望對大家有所幫助
    2023-06-06
  • 詳解Go語言中調(diào)度器的原理與使用

    詳解Go語言中調(diào)度器的原理與使用

    這篇文章主要介紹了Go語言運(yùn)行時調(diào)度器的實(shí)現(xiàn)原理,其中包含調(diào)度器的設(shè)計與實(shí)現(xiàn)原理、演變過程以及與運(yùn)行時調(diào)度相關(guān)的數(shù)據(jù)結(jié)構(gòu),希望對大家有所幫助
    2023-07-07
  • Go單元測試對GORM進(jìn)行Mock測試

    Go單元測試對GORM進(jìn)行Mock測試

    這篇文章主要為大家介紹了Go單元測試對GORM進(jìn)行Mock測試用例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • 詳解Golang中哪些類型可以作為map的key

    詳解Golang中哪些類型可以作為map的key

    在 Go 語言中,map 是一種內(nèi)置的關(guān)聯(lián)數(shù)據(jù)結(jié)構(gòu)類型,由一組無序的鍵值對組成,每個鍵都是唯一的,并與一個對應(yīng)的值相關(guān)聯(lián),本文將詳細(xì)介紹哪些類型的變量可以作為 map 的鍵,并通過實(shí)例進(jìn)行說明,感興趣的朋友可以參考下
    2024-01-01
  • Go語言中http和mysql的實(shí)現(xiàn)代碼

    Go語言中http和mysql的實(shí)現(xiàn)代碼

    本文通過實(shí)例代碼給大家介紹了Go語言中http和mysql的實(shí)現(xiàn)代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-11-11
  • Golang中Interface接口的三個特性

    Golang中Interface接口的三個特性

    本文詳細(xì)講解了Golang中Interface接口的三個特性,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07

最新評論

杭锦后旗| 大宁县| 长顺县| 乌兰浩特市| 枞阳县| 星子县| 新密市| 屯昌县| 贵溪市| 育儿| 诸暨市| 普宁市| 河池市| 新龙县| 河池市| 永靖县| 泌阳县| 喀喇| 碌曲县| 潼南县| 集安市| 宜黄县| 松桃| 浦城县| 行唐县| 塔城市| 南城县| 桂东县| 中牟县| 崇明县| 定南县| 临桂县| 桐梓县| 钦州市| 阳泉市| 嘉善县| 广平县| 锡林郭勒盟| 昭平县| 科技| 兴业县|