From acc0fc8d8fae9180228e4a5034ab802595c601d6 Mon Sep 17 00:00:00 2001 From: SliverHorn <503551462@qq.com> Date: Wed, 2 Sep 2020 15:13:54 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9Ezap=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E5=BA=93=E7=9A=84=E6=94=AF=E6=8C=81,=E5=B9=B6=E6=8F=90?= =?UTF-8?q?=E4=BE=9BRecovery=E7=9A=84=E4=B8=AD=E9=97=B4=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/config.yaml | 10 +++++- server/config/config.go | 9 +++++ server/core/zap.go | 67 ++++++++++++++++++++++++++++++++++++++ server/global/global.go | 3 ++ server/go.mod | 3 ++ server/middleware/error.go | 60 ++++++++++++++++++++++++++++++++++ 6 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 server/core/zap.go create mode 100644 server/middleware/error.go diff --git a/server/config.yaml b/server/config.yaml index 63ac5e99..c0037af9 100644 --- a/server/config.yaml +++ b/server/config.yaml @@ -64,4 +64,12 @@ log: prefix: '[GIN-VUE-ADMIN]' log-file: true stdout: 'DEBUG' - file: 'DEBUG' \ No newline at end of file + file: 'DEBUG' + +# zap logger configuration +zap: + level: "debug" + file: "DEBUG" + max_size: 200 + max_age: 30 + max_backups: 7 \ No newline at end of file diff --git a/server/config/config.go b/server/config/config.go index a55007cd..40afe12d 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -10,6 +10,7 @@ type Server struct { JWT JWT `mapstructure:"jwt" json:"jwt" yaml:"jwt"` Captcha Captcha `mapstructure:"captcha" json:"captcha" yaml:"captcha"` Log Log `mapstructure:"log" json:"log" yaml:"log"` + Zap Zap `mapstructure:"zap" json:"zap" yaml:"zap"` LocalUpload LocalUpload `mapstructure:"localUpload" json:"localUpload" yaml:"localUpload"` } @@ -78,3 +79,11 @@ type Sqlite struct { Config string `mapstructure:"config" json:"config" yaml:"config"` LogMode bool `mapstructure:"log-mode" json:"logMode" yaml:"log-mode"` } + +type Zap struct { + Level string `json:"level"` + File string `json:"file"` + MaxSize int `json:"maxsize"` + MaxAge int `json:"max_age"` + MaxBackups int `json:"max_backups"` +} diff --git a/server/core/zap.go b/server/core/zap.go new file mode 100644 index 00000000..984edb52 --- /dev/null +++ b/server/core/zap.go @@ -0,0 +1,67 @@ +package core + +import ( + "fmt" + "gin-vue-admin/global" + "gin-vue-admin/utils" + zaprotatelogs "github.com/lestrrat-go/file-rotatelogs" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "os" + "time" +) + +const ( + zapLogDir = "log" + zapLogSoftLink = "latest_log" + zapModule = "gin-vue-admin" +) + +func init() { + if global.GVA_CONFIG.Zap.File == "" { + global.GVA_CONFIG.Zap.File = "DEBUG" + } + if ok, _ := utils.PathExists(zapLogDir); !ok { + // directory not exist + fmt.Println("create log directory") + _ = os.Mkdir(zapLogDir, os.ModePerm) + } + var l = new(zapcore.Level) + writeSyncer, err := getWriteSyncer() + if err != nil { + fmt.Printf("Get Write Syncer Failed err:%v", err.Error()) + return + } + encoder := getEncoderConfig() + if err := l.UnmarshalText([]byte(global.GVA_CONFIG.Zap.Level)); err != nil { + fmt.Printf("Unmarshal Level Failed err:%v", err.Error()) + return + } + core := zapcore.NewCore(encoder, writeSyncer, l) + global.GVA_ZAP = zap.New(core, zap.AddCaller()) +} + +// getWriteSyncer zap logger中加入file-rotatelogs +func getWriteSyncer() (zapcore.WriteSyncer, error) { + fileWriter, err := zaprotatelogs.New( + zapLogDir + string(os.PathSeparator) + "%Y-%m-%d-%H-%M.log", + zaprotatelogs.WithLinkName(zapLogSoftLink), + zaprotatelogs.WithMaxAge(7*24*time.Hour), + zaprotatelogs.WithRotationTime(24*time.Hour), + ) + return zapcore.AddSync(fileWriter), err +} + +// getEncoderConfig 获取zapcore.Encoder +func getEncoderConfig() 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.NewConsoleEncoder(encoderConfig) +} + + + diff --git a/server/global/global.go b/server/global/global.go index 828cabb9..d592bb19 100644 --- a/server/global/global.go +++ b/server/global/global.go @@ -1,6 +1,8 @@ package global import ( + "go.uber.org/zap" + "gin-vue-admin/config" "github.com/go-redis/redis" oplogging "github.com/op/go-logging" @@ -14,4 +16,5 @@ var ( GVA_CONFIG config.Server GVA_VP *viper.Viper GVA_LOG *oplogging.Logger + GVA_ZAP *zap.Logger ) diff --git a/server/go.mod b/server/go.mod index 588472f5..7c413b0d 100644 --- a/server/go.mod +++ b/server/go.mod @@ -20,6 +20,8 @@ require ( github.com/golang/protobuf v1.4.2 // indirect github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect github.com/json-iterator/go v1.1.10 // indirect + github.com/lestrrat-go/file-rotatelogs v2.3.0+incompatible + github.com/lestrrat-go/strftime v1.0.3 // indirect github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 // indirect github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect @@ -43,6 +45,7 @@ require ( github.com/tebeka/strftime v0.1.3 // indirect github.com/unrolled/secure v1.0.7 github.com/urfave/cli v1.22.2 // indirect + go.uber.org/zap v1.10.0 golang.org/x/net v0.0.0-20200320220750-118fecf932d8 // indirect golang.org/x/sys v0.0.0-20200610111108-226ff32320da // indirect golang.org/x/tools v0.0.0-20200324003944-a576cf524670 // indirect diff --git a/server/middleware/error.go b/server/middleware/error.go new file mode 100644 index 00000000..ad9f4962 --- /dev/null +++ b/server/middleware/error.go @@ -0,0 +1,60 @@ +package middleware + +import ( + "gin-vue-admin/global" + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "net" + "net/http" + "net/http/httputil" + "os" + "runtime/debug" + "strings" +) + +// GinRecovery recover掉项目可能出现的panic,并使用zap记录相关日志 +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 { + global.GVA_ZAP.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 { + global.GVA_ZAP.Error("[Recovery from panic]", + zap.Any("error", err), + zap.String("request", string(httpRequest)), + zap.String("stack", string(debug.Stack())), + ) + } else { + global.GVA_ZAP.Error("[Recovery from panic]", + zap.Any("error", err), + zap.String("request", string(httpRequest)), + ) + } + c.AbortWithStatus(http.StatusInternalServerError) + } + }() + c.Next() + } +} -- GitLab