gin + vue3 搭建博客系统(3) zap日志库的封装

120 阅读1分钟

一、安装zap日志库 和lumberjack 库写入日志

go get go.uber.org/zap
go get github.com/natefinch/lumberjack

二、在bootstrap新建log文件

package bootstrap  
  
import (  
"gin-blog/utils"  
"os"  
"time"  
  
"github.com/natefinch/lumberjack"  
"go.uber.org/zap"  
"go.uber.org/zap/zapcore"  
  
"gin-blog/global"  
)  
  
var (  
level zapcore.Level  
options []zap.Option  
)  
  
func InitialLog() *zap.Logger {  
createRootDir()  
setLogLevel()  
if global.Config.Log.ShowLine {  
options = append(options, zap.AddCaller())  
}  
return zap.New(getZapCore(), options...)  
}  
  
func createRootDir() {  
if b, _ := utils.PathExists(global.Config.Log.RootDir); !b {  
os.Mkdir(global.Config.Log.RootDir, os.ModePerm)  
}  
}  
  
func setLogLevel() {  
switch global.Config.Log.Level {  
case "debug":  
level = zap.DebugLevel  
options = append(options, zap.AddStacktrace(level))  
case "info":  
level = zap.InfoLevel  
case "warn":  
level = zap.WarnLevel  
case "error":  
level = zap.ErrorLevel  
options = append(options, zap.AddStacktrace(level))  
case "dpanic":  
level = zap.DPanicLevel  
case "panic":  
level = zap.PanicLevel  
case "fatal":  
level = zap.FatalLevel  
default:  
level = zap.InfoLevel  
}  
  
}  
  
// getZapCore 扩展zap  
func getZapCore() zapcore.Core {  
var encoder zapcore.Encoder  
  
// 调整编码器默认配置  
encoderConfig := zap.NewProductionEncoderConfig()  
encoderConfig.EncodeTime = func(time time.Time, encoder zapcore.PrimitiveArrayEncoder) {  
encoder.AppendString(time.Format("[" + "2006-01-02 15:04:05.000" + "]"))  
}  
encoderConfig.EncodeLevel = func(l zapcore.Level, encoder zapcore.PrimitiveArrayEncoder) {  
encoder.AppendString(global.Config.App.Env + "." + l.String())  
}  
  
// 设置编码器  
if global.Config.Log.Format == "json" {  
encoder = zapcore.NewJSONEncoder(encoderConfig)  
} else {  
encoder = zapcore.NewConsoleEncoder(encoderConfig)  
}  
  
return zapcore.NewCore(encoder, getLogWriter(), level)  
}  
  
// getLogWriter 使用lumberJack 作为日志写入器  
func getLogWriter() zapcore.WriteSyncer {  
file := &lumberjack.Logger{  
Filename: global.Config.Log.RootDir + "/" + global.Config.Log.FileName,  
MaxSize: global.Config.Log.MaxSize,  
MaxBackups: global.Config.Log.MaxBackups,  
MaxAge: global.Config.Log.MaxAge,  
Compress: global.Config.Log.Compress,  
}  
return zapcore.AddSync(file)  
}

三、在global.go文件新增


var (
Config config.Config
Log *zap.Logger
    )

四、在main.go调用

global.Log = bootstrap.InitialLog()

五、在gin中使用

package middleware  
  
import (  
"net"  
"net/http"  
"net/http/httputil"  
"os"  
"runtime/debug"  
"strings"  
"time"  
  
"github.com/gin-gonic/gin"  
"go.uber.org/zap"  
)  
  
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 {  
// 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 {  
logger.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 {  
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()  
}  
}

六、在gin中调用

r.Use(middleware.GinLogger(global.Log), middleware.GinRecovery(global.Log, true))