package logger
import ( "net" "net/http" "net/http/httputil" "os" "runtime/debug" "strings" "time"
"github.com/gin-gonic/gin" "github.com/natefinch/lumberjack" "go.uber.org/zap" "go.uber.org/zap/zapcore" )
var lg *zap.Logger
func Init(cfg *setting.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 } var core zapcore.Core 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) }
lg = zap.New(core, zap.AddCaller())
zap.ReplaceGlobals(lg) zap.L().Info("init logger success") return }
func getEncoder() zapcore.Encoder { encoderConfig := zap.NewProductionEncoderConfig() encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder encoderConfig.TimeKey = "time" encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder encoderConfig.EncodeDuration = zapcore.SecondsDurationEncoder encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder return zapcore.NewJSONEncoder(encoderConfig) }
func getLogWriter(filename string, maxSize, maxBackup, maxAge int) zapcore.WriteSyncer { lumberJackLogger := &lumberjack.Logger{ Filename: filename, MaxSize: maxSize, MaxBackups: maxBackup, MaxAge: maxAge, } return zapcore.AddSync(lumberJackLogger) }
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) lg.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(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 { lg.Error(c.Request.URL.Path, zap.Any("error", err), zap.String("request", string(httpRequest)), ) c.Error(err.(error)) c.Abort() return }
if stack { lg.Error("[Recovery from panic]", zap.Any("error", err), zap.String("request", string(httpRequest)), zap.String("stack", string(debug.Stack())), ) } else { lg.Error("[Recovery from panic]", zap.Any("error", err), zap.String("request", string(httpRequest)), ) } c.AbortWithStatus(http.StatusInternalServerError) } }() c.Next() } }
|