You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
3.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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()
}
}