|
|
package logger
|
|
|
|
|
|
import (
|
|
|
"net"
|
|
|
"net/http"
|
|
|
"net/http/httputil"
|
|
|
"os"
|
|
|
"runtime/debug"
|
|
|
"strings"
|
|
|
"time"
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
"github.com/natefinch/lumberjack"
|
|
|
"github.com/spf13/viper"
|
|
|
"go.uber.org/zap"
|
|
|
"go.uber.org/zap/zapcore"
|
|
|
)
|
|
|
|
|
|
func Init() (err error) {
|
|
|
writerSyncer := getLogWriter(
|
|
|
viper.GetString("logger.name"),
|
|
|
viper.GetInt("logger.max_sizes"),
|
|
|
viper.GetInt("logger.max_age"),
|
|
|
viper.GetInt("logger.max_backups"),
|
|
|
)
|
|
|
encoder := getEncoder()
|
|
|
var l = new(zapcore.Level)
|
|
|
err = l.UnmarshalText([]byte(viper.GetString("logger.level")))
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
core := zapcore.NewCore(encoder, writerSyncer, zapcore.DebugLevel)
|
|
|
|
|
|
lg := zap.New(core, zap.AddCaller())
|
|
|
//用 lg 来代替全局 logger
|
|
|
zap.ReplaceGlobals(lg)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
func getEncoder() zapcore.Encoder {
|
|
|
// return zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
|
|
|
encoder := zapcore.EncoderConfig{
|
|
|
TimeKey: "ts",
|
|
|
LevelKey: "level",
|
|
|
NameKey: "logger",
|
|
|
CallerKey: "caller",
|
|
|
FunctionKey: zapcore.OmitKey,
|
|
|
MessageKey: "msg",
|
|
|
StacktraceKey: "stacktrace",
|
|
|
LineEnding: zapcore.DefaultLineEnding,
|
|
|
EncodeLevel: zapcore.CapitalLevelEncoder,
|
|
|
EncodeTime: zapcore.ISO8601TimeEncoder,
|
|
|
EncodeDuration: zapcore.SecondsDurationEncoder,
|
|
|
EncodeCaller: zapcore.ShortCallerEncoder,
|
|
|
}
|
|
|
// encoder.EncodeTime = zapcore.ISO8601TimeEncoder
|
|
|
// encoder.EncodeLevel = zapcore.CapitalLevelEncoder
|
|
|
return zapcore.NewConsoleEncoder(encoder)
|
|
|
}
|
|
|
|
|
|
func getLogWriter(filename string, maxSize int, maxBackups int, maxAge int) zapcore.WriteSyncer {
|
|
|
lumberjackLogger := &lumberjack.Logger{
|
|
|
Filename: filename,
|
|
|
MaxSize: maxSize, // 最大大小,单位是M
|
|
|
MaxBackups: maxBackups, //最大备份数量,在上个文件达到最大大小时,开始备份文件
|
|
|
MaxAge: maxAge, //最大保持备份天数
|
|
|
Compress: false, //是否压缩
|
|
|
}
|
|
|
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
|
|
|
ip := c.ClientIP()
|
|
|
user_agent := c.Request.UserAgent()
|
|
|
err := c.Errors.ByType(gin.ErrorTypePrivate).String()
|
|
|
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", ip),
|
|
|
zap.String("user-agent", user_agent),
|
|
|
zap.String("errors", err),
|
|
|
zap.Duration("cost", cost),
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
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()
|
|
|
}
|
|
|
}
|