golang框架gin的日志处理和zap lumberjack日志使用
生活随笔
收集整理的這篇文章主要介紹了
golang框架gin的日志处理和zap lumberjack日志使用
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
目錄
gin自帶日志
新建logger.go
mian.go 引用
zap?lumberjack接管gin日志
新建logger.go
main.go 調(diào)用
gin框架好用,輪子也多,我也來豐富下內(nèi)容,golang框架gin的日志處理和zap lumberjack日志使用
gin自帶日志
新建logger.go
package logsimport ("fmt""github.com/gin-gonic/gin"rotatelogs "github.com/lestrrat-go/file-rotatelogs""github.com/rifflock/lfshook""github.com/sirupsen/logrus""os""runtime""time""upload/config" )var ostype = runtime.GOOS// 日志記錄到文件 func LoggerToFile() gin.HandlerFunc {logFileName := config.LOG_FILE_NAMEfileName := config.LOG_FILE_PATH_LINUX + "/" + logFileNameif ostype == "windows" {fileName = config.LOG_FILE_PATH_WIN + "\\" + logFileName} else if ostype == "linux" {fileName = config.LOG_FILE_PATH_LINUX + "/" + logFileName}日志文件//fileName := path.Join(logFilePath, logFileName)// 寫入文件src, err := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY, os.ModeAppend)if err != nil {fmt.Println("loggerToFile err==>", err)}// 實(shí)例化logger := logrus.New()// 設(shè)置輸出logger.Out = src// 設(shè)置日志級(jí)別logger.SetLevel(logrus.DebugLevel)// 設(shè)置 rotatelogslogWriter, err := rotatelogs.New(// 分割后的文件名稱fileName+".%Y%m%d.log",// 生成軟鏈,指向最新日志文件rotatelogs.WithLinkName(fileName),// 設(shè)置最大保存時(shí)間(7天)rotatelogs.WithMaxAge(7*24*time.Hour),// 設(shè)置日志切割時(shí)間間隔(1天)rotatelogs.WithRotationTime(24*time.Hour),)writeMap := lfshook.WriterMap{logrus.InfoLevel: logWriter,logrus.FatalLevel: logWriter,logrus.DebugLevel: logWriter,logrus.WarnLevel: logWriter,logrus.ErrorLevel: logWriter,logrus.PanicLevel: logWriter,}lfHook := lfshook.NewHook(writeMap, &logrus.JSONFormatter{TimestampFormat: "2006-01-02 15:04:05",})// 新增鉤子logger.AddHook(lfHook)return func(c *gin.Context) {// 開始時(shí)間startTime := time.Now()// 處理請(qǐng)求c.Next()// 結(jié)束時(shí)間endTime := time.Now()// 執(zhí)行時(shí)間latencyTime := endTime.Sub(startTime)// 請(qǐng)求方式reqMethod := c.Request.Method// 請(qǐng)求路由reqUri := c.Request.RequestURI// 狀態(tài)碼statusCode := c.Writer.Status()// 請(qǐng)求IPclientIP := c.ClientIP()// 日志格式logger.WithFields(logrus.Fields{"status_code": statusCode,"latency_time": latencyTime,"client_ip": clientIP,"req_method": reqMethod,"req_uri": reqUri,}).Info()} }// 日志記錄到 MongoDB func LoggerToMongo() gin.HandlerFunc {return func(c *gin.Context) {} }// 日志記錄到 ES func LoggerToES() gin.HandlerFunc {return func(c *gin.Context) {} }// 日志記錄到 MQ func LoggerToMQ() gin.HandlerFunc {return func(c *gin.Context) {} }mian.go 引用
engine.Use(middleware.LoggerToFile())配置config/config.go
package config const (//[log]LOG_FILE_PATH_LINUX = "/home/data/logs/upload/logs"LOG_FILE_PATH_WIN = "\\home\\data\\logs\\upload\\logs\\"LOG_FILE_NAME = "system.log" )var config = new(Config)func Get() Config {return *config }zap?lumberjack接管gin日志
新建logger.go
package logsimport ("github.com/gin-gonic/gin""github.com/natefinch/lumberjack""go.uber.org/zap""go.uber.org/zap/zapcore""net""net/http/httputil""os""runtime/debug""strings""time" )// 1 定義一下logger使用的常量 const (mode = "dev" //開發(fā)模式filename = "logs/logs.log" // 日志存放路徑//level = "debug" // 日志級(jí)別level = zapcore.DebugLevel // 日志級(jí)別max_size = 200 //最大存儲(chǔ)大小max_age = 30 //最大存儲(chǔ)時(shí)間max_backups = 7 //#備份數(shù)量 )// 2 初始化Logger對(duì)象 func InitLogger() (err error) {// 創(chuàng)建Core三大件,進(jìn)行初始化writeSyncer := getLogWriter(filename, max_size, max_backups, max_age)encoder := getEncoder()// 創(chuàng)建核心-->如果是dev模式,就在控制臺(tái)和文件都打印,否則就只寫到文件中var core zapcore.Coreif mode == "dev" {// 開發(fā)模式,日志輸出到終端consoleEncoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())// NewTee創(chuàng)建一個(gè)核心,將日志條目復(fù)制到兩個(gè)或多個(gè)底層核心中。core = zapcore.NewTee(zapcore.NewCore(encoder, writeSyncer, level),zapcore.NewCore(consoleEncoder, zapcore.Lock(os.Stdout), level),)} else {core = zapcore.NewCore(encoder, writeSyncer, level)}//core := zapcore.NewCore(encoder, writeSyncer, level)// 創(chuàng)建 logger 對(duì)象log := zap.New(core, zap.AddCaller())// 替換全局的 logger, 后續(xù)在其他包中只需使用zap.L()調(diào)用即可zap.ReplaceGlobals(log)return }// 獲取Encoder,給初始化logger使用的 func getEncoder() zapcore.Encoder {// 使用zap提供的 NewProductionEncoderConfigencoderConfig := zap.NewProductionEncoderConfig()// 設(shè)置時(shí)間格式encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder// 時(shí)間的keyencoderConfig.TimeKey = "time"// 級(jí)別encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder// 顯示調(diào)用者信息encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder// 返回json 格式的 日志編輯器return zapcore.NewJSONEncoder(encoderConfig) }// 獲取切割的問題,給初始化logger使用的 func getLogWriter(filename string, maxSize, maxBackup, maxAge int) zapcore.WriteSyncer {// 使用 lumberjack 歸檔切片日志lumberJackLogger := &lumberjack.Logger{Filename: filename,MaxSize: maxSize,MaxBackups: maxBackup,MaxAge: maxAge,}return zapcore.AddSync(lumberJackLogger) }// GinLogger 用于替換gin框架的Logger中間件,不傳參數(shù),直接這樣寫 func GinLogger(c *gin.Context) {logger := zap.L()start := time.Now()path := c.Request.URL.Pathquery := c.Request.URL.RawQueryc.Next() // 執(zhí)行視圖函數(shù)// 視圖函數(shù)執(zhí)行完成,統(tǒng)計(jì)時(shí)間,記錄日志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),)}// GinRecovery 用于替換gin框架的Recovery中間件,因?yàn)閭魅雲(yún)?shù),再包一層 func GinRecovery(stack bool) gin.HandlerFunc {logger := zap.L()return func(c *gin.Context) {defer func() {// defer 延遲調(diào)用,出了異常,處理并恢復(fù)異常,記錄日志if err := recover(); err != nil {// 這個(gè)不必須,檢查是否存在斷開的連接(broken pipe或者connection reset by peer)---------開始--------var brokenPipe boolif 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}}}//httputil包預(yù)先準(zhǔn)備好的DumpRequest方法httpRequest, _ := httputil.DumpRequest(c.Request, false)if brokenPipe {logger.Error(c.Request.URL.Path,zap.Any("error", err),zap.String("request", string(httpRequest)),)// 如果連接已斷開,我們無法向其寫入狀態(tài)c.Error(err.(error))c.Abort()return}// 這個(gè)不必須,檢查是否存在斷開的連接(broken pipe或者connection reset by peer)---------結(jié)束--------// 是否打印堆棧信息,使用的是debug.Stack(),傳入false,在日志中就沒有堆棧信息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)),)}// 有錯(cuò)誤,直接返回給前端錯(cuò)誤,前端直接報(bào)錯(cuò)//c.AbortWithStatus(http.StatusInternalServerError)// 該方式前端不報(bào)錯(cuò)c.String(200, "訪問出錯(cuò)了")}}()c.Next()} }main.go 調(diào)用
r := gin.New()// 初始化loggermiddleware.InitLogger()// 兩個(gè)中間件加入gin中r.Use(middleware.GinLogger, middleware.GinRecovery(true))就可以看到日志了
2022-10-20T14:56:04.998+0800 INFO middleware/logger.go:92 /ping {"appid": "", "status": 200, "method": "GET", "path": "/ping", "query": "aa=1", "ip": "127.0.0.1", "user-agent": "PostmanRuntime/7.29.2", "errors": "", "cost": "0s"}總結(jié)
以上是生活随笔為你收集整理的golang框架gin的日志处理和zap lumberjack日志使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 移动开发(IOS) – iOS系统架构
- 下一篇: 路由器AP、中继、桥接等模式区别