This commit is contained in:
fallen-angle
2022-01-17 17:38:08 +08:00
parent 0a5379c8f3
commit 2280679053
19 changed files with 283 additions and 19 deletions

1
.gitignore vendored
View File

@@ -0,0 +1 @@
*.log

View File

@@ -11,7 +11,7 @@ type ServerConfig struct {
type MySQLConfig struct { type MySQLConfig struct {
Host string `yaml:"host"` Host string `yaml:"host"`
Port string `yaml:"port"` Port int `yaml:"port"`
Username string `yaml:"username"` Username string `yaml:"username"`
Password string `yaml:"password"` Password string `yaml:"password"`
Database string `yaml:"database"` Database string `yaml:"database"`

View File

@@ -1,12 +1,21 @@
package global package global
import ( import (
"fmt"
"nCovTrack-Backend/config" "nCovTrack-Backend/config"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"gorm.io/gorm" "gorm.io/gorm"
) )
var ( var (
ServerSettings config.ServerConfig ServerSettings config.ServerConfig
Db *gorm.DB Db *gorm.DB
RootRouter *gin.RouterGroup
Logger *zap.SugaredLogger
) )
func GetListenOn() string {
return fmt.Sprintf("%s:%d", ServerSettings.Listen, ServerSettings.Port)
}

2
go.mod
View File

@@ -3,6 +3,7 @@ module nCovTrack-Backend
go 1.18 go 1.18
require ( require (
github.com/fatih/color v1.13.0 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.7.7 // indirect github.com/gin-gonic/gin v1.7.7 // indirect
@@ -17,6 +18,7 @@ require (
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/leodido/go-urn v1.2.1 // indirect github.com/leodido/go-urn v1.2.1 // indirect
github.com/magiconair/properties v1.8.5 // indirect github.com/magiconair/properties v1.8.5 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect

6
go.sum
View File

@@ -56,6 +56,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
@@ -165,6 +167,9 @@ github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
@@ -367,6 +372,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=

View File

@@ -5,6 +5,7 @@ import (
"nCovTrack-Backend/config" "nCovTrack-Backend/config"
"nCovTrack-Backend/global" "nCovTrack-Backend/global"
"github.com/fatih/color"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@@ -20,4 +21,5 @@ func initConfig() {
panic(err) panic(err)
} }
global.ServerSettings = serverConfig global.ServerSettings = serverConfig
color.Blue("Already read config from %s", v.ConfigFileUsed())
} }

View File

@@ -1,6 +1,10 @@
package initialize package initialize
func Initialize() { import "github.com/gin-gonic/gin"
func Initialize() *gin.Engine {
initConfig() initConfig()
initLogger()
initMySQL() initMySQL()
return initRouter()
} }

25
initialize/logger.go Normal file
View File

@@ -0,0 +1,25 @@
package initialize
import (
"fmt"
"nCovTrack-Backend/global"
"nCovTrack-Backend/utils"
"time"
"go.uber.org/zap"
)
func initLogger() {
zapConfig := zap.NewProductionConfig()
zapConfig.OutputPaths = []string{
fmt.Sprintf("%slog_%s.log", global.ServerSettings.LogPath, utils.FormateDate(time.Now())),
"stdout",
}
logger, err := zapConfig.Build()
if err != nil {
panic(err)
}
sLogger := logger.Sugar()
zap.ReplaceGlobals(sLogger.Desugar())
global.Logger = sLogger
}

View File

@@ -10,7 +10,7 @@ import (
func initMySQL() { func initMySQL() {
mysqlConf := global.ServerSettings.MySQL mysqlConf := global.ServerSettings.MySQL
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%scharset=utf8mb4&parseTime=True&loc=Local", mysqlConf.Username, mysqlConf.Password, mysqlConf.Host, mysqlConf.Port, mysqlConf.Database) dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", mysqlConf.Username, mysqlConf.Password, mysqlConf.Host, mysqlConf.Port, mysqlConf.Database)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil { if err != nil {
panic(err) panic(err)

17
initialize/router.go Normal file
View File

@@ -0,0 +1,17 @@
package initialize
import (
"nCovTrack-Backend/global"
"nCovTrack-Backend/middleware"
"nCovTrack-Backend/router"
"github.com/gin-gonic/gin"
)
func initRouter() *gin.Engine {
r := gin.New()
r.Use(middleware.Cors(), middleware.RequestLog(), middleware.GinRecovery(false))
global.RootRouter = r.Group(global.ServerSettings.UrlPrefix)
router.BusiRouter()
return r
}

11
main.go Normal file
View File

@@ -0,0 +1,11 @@
package main
import (
"nCovTrack-Backend/global"
"nCovTrack-Backend/initialize"
)
func main() {
gin := initialize.Initialize()
gin.Run(global.GetListenOn())
}

View File

@@ -1,9 +0,0 @@
package main
import (
"nCovTrack-Backend/initialize"
)
func main() {
initialize.Initialize()
}

24
middleware/cors.go Normal file
View File

@@ -0,0 +1,24 @@
package middleware
import (
"net/http"
"github.com/gin-gonic/gin"
)
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
origin := c.Request.Header.Get("Origin")
c.Header("Access-Control-Allow-Origin", origin)
c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id")
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS,DELETE,PUT")
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
c.Header("Access-Control-Allow-Credentials", "true")
if method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
}
c.Next()
}
}

View File

@@ -0,0 +1,55 @@
package middleware
import (
"nCovTrack-Backend/utils"
"net"
"net/http"
"net/http/httputil"
"os"
"runtime/debug"
"strings"
"github.com/gin-gonic/gin"
)
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, true)
var logParams []interface{}
logParams = append(logParams,
"uri", c.Request.RequestURI,
"method", c.Request.Method,
"request", string(httpRequest),
"error", interface{}(err),
)
if brokenPipe {
utils.RequestLogPanic(logParams...)
c.Error(err.(error))
c.Abort()
return
}
logParams = append(logParams,
"status", "recovery from panic",
)
if stack {
logParams = append(logParams,
"stack", string(debug.Stack()),
)
}
utils.RequestLogPanic(logParams...)
c.AbortWithStatus(http.StatusInternalServerError)
}
}()
c.Next()
}
}

54
middleware/request_log.go Normal file
View File

@@ -0,0 +1,54 @@
package middleware
import (
"nCovTrack-Backend/utils"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func RequestLog() gin.HandlerFunc {
return func(c *gin.Context) {
var logParams []interface{}
// All requests' log;
logParams = append(logParams,
"uri", c.Request.RequestURI,
"mothod", c.Request.Method,
)
startTime := time.Now()
c.Next()
cost := time.Since(startTime)
logParams = append(logParams, "cost", cost.String())
// Log while request is allright;
if c.Writer.Status() == http.StatusOK && cost.Milliseconds() < 800 {
utils.RequestLogInfo(logParams...)
return
}
// Log while request cost an unexpected time;
if cost >= 800 {
logParams = append(logParams,
"status", c.Writer.Status(),
"query", c.Request.URL.Query(),
"header", c.Request.Header,
"body", c.Request.Body,
"ip", c.ClientIP(),
)
utils.RequestLogWarn(logParams...)
return
}
// Log while response occurred some error;
if c.Writer.Status() != http.StatusOK {
logParams = append(logParams,
"error", c.Errors.ByType(gin.ErrorTypePrivate).String(),
)
utils.RequestLogError(logParams...)
}
}
}

View File

@@ -2,13 +2,22 @@ package router
import ( import (
"nCovTrack-Backend/global" "nCovTrack-Backend/global"
"net/http"
"time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
func initRouter() { func BusiRouter() {
r := gin.Default() userRouter := global.RootRouter.Group("/user")
r.Use() {
apiGroup := r.Group(global.ServerSettings.UrlPrefix) userRouter.GET("/count", func(c *gin.Context) {
router.UserRouter(apiGroup) panic("count err")
time.Sleep(800 * time.Millisecond)
c.String(http.StatusOK, "OK")
})
userRouter.GET("/test", func(c *gin.Context) {
c.String(http.StatusOK, "OK")
})
}
} }

View File

@@ -1,5 +1,5 @@
name: nConvTrack name: nConvTrack
port: 8080 port: 8081
host: 0.0.0.0 host: 0.0.0.0
urlPrefix: /v1/ urlPrefix: /v1/
logPath: ./logs/ logPath: ./logs/
@@ -9,4 +9,4 @@ mysql:
port: 3306 port: 3306
username: root username: root
password: 13291004986@lm password: 13291004986@lm
database: nConvTrack database: nCovTrack

45
utils/log.go Normal file
View File

@@ -0,0 +1,45 @@
package utils
import "nCovTrack-Backend/global"
func RequestLogInfo(args ...interface{}) {
logInfo("request", args...)
}
func RequestLogError(args ...interface{}) {
logError("request", args...)
}
func RequestLogWarn(args ...interface{}) {
logWarn("request", args...)
}
func RequestLogPanic(args ...interface{}) {
logPanic("request", args...)
}
func InitLogPanic(component string, args ...interface{}) {
args = append(args, "component", component)
logPanic("initialize", args...)
}
func InitLogInfo(component string, args ...interface{}) {
args = append(args, "component", component)
logInfo("initialize", args...)
}
func logInfo(msg string, args ...interface{}) {
global.Logger.Infow(msg, args...)
}
func logError(msg string, args ...interface{}) {
global.Logger.Errorw(msg, args...)
}
func logWarn(msg string, args ...interface{}) {
global.Logger.Warnw(msg, args...)
}
func logPanic(msg string, args ...interface{}) {
global.Logger.Panicw("", args...)
}

9
utils/time.go Normal file
View File

@@ -0,0 +1,9 @@
package utils
import (
"time"
)
func FormateDate(date time.Time) string {
return date.Format("06-01-02")
}