Skip to content

Commit 01c4206

Browse files
committed
新增zap日志库的支持,并提供Recovery的中间件
1 parent a468599 commit 01c4206

File tree

6 files changed

+151
-1
lines changed

6 files changed

+151
-1
lines changed

server/config.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,12 @@ log:
6464
prefix: '[GIN-VUE-ADMIN]'
6565
log-file: true
6666
stdout: 'DEBUG'
67-
file: 'DEBUG'
67+
file: 'DEBUG'
68+
69+
# zap logger configuration
70+
zap:
71+
level: "debug"
72+
file: "DEBUG"
73+
max_size: 200
74+
max_age: 30
75+
max_backups: 7

server/config/config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type Server struct {
1010
JWT JWT `mapstructure:"jwt" json:"jwt" yaml:"jwt"`
1111
Captcha Captcha `mapstructure:"captcha" json:"captcha" yaml:"captcha"`
1212
Log Log `mapstructure:"log" json:"log" yaml:"log"`
13+
Zap Zap `mapstructure:"zap" json:"zap" yaml:"zap"`
1314
LocalUpload LocalUpload `mapstructure:"localUpload" json:"localUpload" yaml:"localUpload"`
1415
}
1516

@@ -78,3 +79,11 @@ type Sqlite struct {
7879
Config string `mapstructure:"config" json:"config" yaml:"config"`
7980
LogMode bool `mapstructure:"log-mode" json:"logMode" yaml:"log-mode"`
8081
}
82+
83+
type Zap struct {
84+
Level string `json:"level"`
85+
File string `json:"file"`
86+
MaxSize int `json:"maxsize"`
87+
MaxAge int `json:"max_age"`
88+
MaxBackups int `json:"max_backups"`
89+
}

server/core/zap.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package core
2+
3+
import (
4+
"fmt"
5+
"gin-vue-admin/global"
6+
"gin-vue-admin/utils"
7+
zaprotatelogs "github.com/lestrrat-go/file-rotatelogs"
8+
"go.uber.org/zap"
9+
"go.uber.org/zap/zapcore"
10+
"os"
11+
"time"
12+
)
13+
14+
const (
15+
zapLogDir = "log"
16+
zapLogSoftLink = "latest_log"
17+
zapModule = "gin-vue-admin"
18+
)
19+
20+
func init() {
21+
if global.GVA_CONFIG.Zap.File == "" {
22+
global.GVA_CONFIG.Zap.File = "DEBUG"
23+
}
24+
if ok, _ := utils.PathExists(zapLogDir); !ok {
25+
// directory not exist
26+
fmt.Println("create log directory")
27+
_ = os.Mkdir(zapLogDir, os.ModePerm)
28+
}
29+
var l = new(zapcore.Level)
30+
writeSyncer, err := getWriteSyncer()
31+
if err != nil {
32+
fmt.Printf("Get Write Syncer Failed err:%v", err.Error())
33+
return
34+
}
35+
encoder := getEncoderConfig()
36+
if err := l.UnmarshalText([]byte(global.GVA_CONFIG.Zap.Level)); err != nil {
37+
fmt.Printf("Unmarshal Level Failed err:%v", err.Error())
38+
return
39+
}
40+
core := zapcore.NewCore(encoder, writeSyncer, l)
41+
global.GVA_ZAP = zap.New(core, zap.AddCaller())
42+
}
43+
44+
// getWriteSyncer zap logger中加入file-rotatelogs
45+
func getWriteSyncer() (zapcore.WriteSyncer, error) {
46+
fileWriter, err := zaprotatelogs.New(
47+
zapLogDir + string(os.PathSeparator) + "%Y-%m-%d-%H-%M.log",
48+
zaprotatelogs.WithLinkName(zapLogSoftLink),
49+
zaprotatelogs.WithMaxAge(7*24*time.Hour),
50+
zaprotatelogs.WithRotationTime(24*time.Hour),
51+
)
52+
return zapcore.AddSync(fileWriter), err
53+
}
54+
55+
// getEncoderConfig 获取zapcore.Encoder
56+
func getEncoderConfig() zapcore.Encoder {
57+
encoderConfig := zap.NewProductionEncoderConfig()
58+
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
59+
encoderConfig.TimeKey = "time"
60+
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
61+
encoderConfig.EncodeDuration = zapcore.SecondsDurationEncoder
62+
encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder
63+
return zapcore.NewConsoleEncoder(encoderConfig)
64+
}
65+
66+
67+

server/global/global.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package global
22

33
import (
4+
"go.uber.org/zap"
5+
46
"gin-vue-admin/config"
57
"github.com/go-redis/redis"
68
oplogging "github.com/op/go-logging"
@@ -14,4 +16,5 @@ var (
1416
GVA_CONFIG config.Server
1517
GVA_VP *viper.Viper
1618
GVA_LOG *oplogging.Logger
19+
GVA_ZAP *zap.Logger
1720
)

server/go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ require (
2020
github.com/golang/protobuf v1.4.2 // indirect
2121
github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect
2222
github.com/json-iterator/go v1.1.10 // indirect
23+
github.com/lestrrat-go/file-rotatelogs v2.3.0+incompatible
24+
github.com/lestrrat-go/strftime v1.0.3 // indirect
2325
github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 // indirect
2426
github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f
2527
github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect
@@ -43,6 +45,7 @@ require (
4345
github.com/tebeka/strftime v0.1.3 // indirect
4446
github.com/unrolled/secure v1.0.7
4547
github.com/urfave/cli v1.22.2 // indirect
48+
go.uber.org/zap v1.10.0
4649
golang.org/x/net v0.0.0-20200320220750-118fecf932d8 // indirect
4750
golang.org/x/sys v0.0.0-20200610111108-226ff32320da // indirect
4851
golang.org/x/tools v0.0.0-20200324003944-a576cf524670 // indirect

server/middleware/error.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package middleware
2+
3+
import (
4+
"gin-vue-admin/global"
5+
"github.com/gin-gonic/gin"
6+
"go.uber.org/zap"
7+
"net"
8+
"net/http"
9+
"net/http/httputil"
10+
"os"
11+
"runtime/debug"
12+
"strings"
13+
)
14+
15+
// GinRecovery recover掉项目可能出现的panic,并使用zap记录相关日志
16+
func GinRecovery(stack bool) gin.HandlerFunc {
17+
return func(c *gin.Context) {
18+
defer func() {
19+
if err := recover(); err != nil {
20+
// Check for a broken connection, as it is not really a
21+
// condition that warrants a panic stack trace.
22+
var brokenPipe bool
23+
if ne, ok := err.(*net.OpError); ok {
24+
if se, ok := ne.Err.(*os.SyscallError); ok {
25+
if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
26+
brokenPipe = true
27+
}
28+
}
29+
}
30+
31+
httpRequest, _ := httputil.DumpRequest(c.Request, false)
32+
if brokenPipe {
33+
global.GVA_ZAP.Error(c.Request.URL.Path,
34+
zap.Any("error", err),
35+
zap.String("request", string(httpRequest)),
36+
)
37+
// If the connection is dead, we can't write a status to it.
38+
_ = c.Error(err.(error)) // nolint: errcheck
39+
c.Abort()
40+
return
41+
}
42+
43+
if stack {
44+
global.GVA_ZAP.Error("[Recovery from panic]",
45+
zap.Any("error", err),
46+
zap.String("request", string(httpRequest)),
47+
zap.String("stack", string(debug.Stack())),
48+
)
49+
} else {
50+
global.GVA_ZAP.Error("[Recovery from panic]",
51+
zap.Any("error", err),
52+
zap.String("request", string(httpRequest)),
53+
)
54+
}
55+
c.AbortWithStatus(http.StatusInternalServerError)
56+
}
57+
}()
58+
c.Next()
59+
}
60+
}

0 commit comments

Comments
 (0)