✨ init project
This commit is contained in:
9
core/internal/constant.go
Normal file
9
core/internal/constant.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package internal
|
||||
|
||||
const (
|
||||
ConfigEnv = "GVA_CONFIG"
|
||||
ConfigDefaultFile = "config.yaml"
|
||||
ConfigTestFile = "config.test.yaml"
|
||||
ConfigDebugFile = "config.debug.yaml"
|
||||
ConfigReleaseFile = "config.release.yaml"
|
||||
)
|
121
core/internal/cutter.go
Normal file
121
core/internal/cutter.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Cutter 实现 io.Writer 接口
|
||||
// 用于日志切割, strings.Join([]string{director,layout, formats..., level+".log"}, os.PathSeparator)
|
||||
type Cutter struct {
|
||||
level string // 日志级别(debug, info, warn, error, dpanic, panic, fatal)
|
||||
layout string // 时间格式 2006-01-02 15:04:05
|
||||
formats []string // 自定义参数([]string{Director,"2006-01-02", "business"(此参数可不写), level+".log"}
|
||||
director string // 日志文件夹
|
||||
retentionDay int //日志保留天数
|
||||
file *os.File // 文件句柄
|
||||
mutex *sync.RWMutex // 读写锁
|
||||
}
|
||||
|
||||
type CutterOption func(*Cutter)
|
||||
|
||||
// CutterWithLayout 时间格式
|
||||
func CutterWithLayout(layout string) CutterOption {
|
||||
return func(c *Cutter) {
|
||||
c.layout = layout
|
||||
}
|
||||
}
|
||||
|
||||
// CutterWithFormats 格式化参数
|
||||
func CutterWithFormats(format ...string) CutterOption {
|
||||
return func(c *Cutter) {
|
||||
if len(format) > 0 {
|
||||
c.formats = format
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewCutter(director string, level string, retentionDay int, options ...CutterOption) *Cutter {
|
||||
rotate := &Cutter{
|
||||
level: level,
|
||||
director: director,
|
||||
retentionDay: retentionDay,
|
||||
mutex: new(sync.RWMutex),
|
||||
}
|
||||
for i := 0; i < len(options); i++ {
|
||||
options[i](rotate)
|
||||
}
|
||||
return rotate
|
||||
}
|
||||
|
||||
// Write satisfies the io.Writer interface. It writes to the
|
||||
// appropriate file handle that is currently being used.
|
||||
// If we have reached rotation time, the target file gets
|
||||
// automatically rotated, and also purged if necessary.
|
||||
func (c *Cutter) Write(bytes []byte) (n int, err error) {
|
||||
c.mutex.Lock()
|
||||
defer func() {
|
||||
if c.file != nil {
|
||||
_ = c.file.Close()
|
||||
c.file = nil
|
||||
}
|
||||
c.mutex.Unlock()
|
||||
}()
|
||||
length := len(c.formats)
|
||||
values := make([]string, 0, 3+length)
|
||||
values = append(values, c.director)
|
||||
if c.layout != "" {
|
||||
values = append(values, time.Now().Format(c.layout))
|
||||
}
|
||||
for i := 0; i < length; i++ {
|
||||
values = append(values, c.formats[i])
|
||||
}
|
||||
values = append(values, c.level+".log")
|
||||
filename := filepath.Join(values...)
|
||||
director := filepath.Dir(filename)
|
||||
err = os.MkdirAll(director, os.ModePerm)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
err = removeNDaysFolders(c.director, c.retentionDay)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
c.file, err = os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return c.file.Write(bytes)
|
||||
}
|
||||
|
||||
func (c *Cutter) Sync() error {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
if c.file != nil {
|
||||
return c.file.Sync()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 增加日志目录文件清理 小于等于零的值默认忽略不再处理
|
||||
func removeNDaysFolders(dir string, days int) error {
|
||||
if days <= 0 {
|
||||
return nil
|
||||
}
|
||||
cutoff := time.Now().AddDate(0, 0, -days)
|
||||
return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() && info.ModTime().Before(cutoff) && path != dir {
|
||||
err = os.RemoveAll(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
68
core/internal/zap_core.go
Normal file
68
core/internal/zap_core.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"git.echol.cn/loser/xiecheng_server/global"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ZapCore struct {
|
||||
level zapcore.Level
|
||||
zapcore.Core
|
||||
}
|
||||
|
||||
func NewZapCore(level zapcore.Level) *ZapCore {
|
||||
entity := &ZapCore{level: level}
|
||||
syncer := entity.WriteSyncer()
|
||||
levelEnabler := zap.LevelEnablerFunc(func(l zapcore.Level) bool {
|
||||
return l == level
|
||||
})
|
||||
entity.Core = zapcore.NewCore(global.GVA_CONFIG.Zap.Encoder(), syncer, levelEnabler)
|
||||
return entity
|
||||
}
|
||||
|
||||
func (z *ZapCore) WriteSyncer(formats ...string) zapcore.WriteSyncer {
|
||||
cutter := NewCutter(
|
||||
global.GVA_CONFIG.Zap.Director,
|
||||
z.level.String(),
|
||||
global.GVA_CONFIG.Zap.RetentionDay,
|
||||
CutterWithLayout(time.DateOnly),
|
||||
CutterWithFormats(formats...),
|
||||
)
|
||||
if global.GVA_CONFIG.Zap.LogInConsole {
|
||||
multiSyncer := zapcore.NewMultiWriteSyncer(os.Stdout, cutter)
|
||||
return zapcore.AddSync(multiSyncer)
|
||||
}
|
||||
return zapcore.AddSync(cutter)
|
||||
}
|
||||
|
||||
func (z *ZapCore) Enabled(level zapcore.Level) bool {
|
||||
return z.level == level
|
||||
}
|
||||
|
||||
func (z *ZapCore) With(fields []zapcore.Field) zapcore.Core {
|
||||
return z.Core.With(fields)
|
||||
}
|
||||
|
||||
func (z *ZapCore) Check(entry zapcore.Entry, check *zapcore.CheckedEntry) *zapcore.CheckedEntry {
|
||||
if z.Enabled(entry.Level) {
|
||||
return check.AddCore(entry, z)
|
||||
}
|
||||
return check
|
||||
}
|
||||
|
||||
func (z *ZapCore) Write(entry zapcore.Entry, fields []zapcore.Field) error {
|
||||
for i := 0; i < len(fields); i++ {
|
||||
if fields[i].Key == "business" || fields[i].Key == "folder" || fields[i].Key == "directory" {
|
||||
syncer := z.WriteSyncer(fields[i].String)
|
||||
z.Core = zapcore.NewCore(global.GVA_CONFIG.Zap.Encoder(), syncer, z.level)
|
||||
}
|
||||
}
|
||||
return z.Core.Write(entry, fields)
|
||||
}
|
||||
|
||||
func (z *ZapCore) Sync() error {
|
||||
return z.Core.Sync()
|
||||
}
|
55
core/server.go
Normal file
55
core/server.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.echol.cn/loser/xiecheng_server/global"
|
||||
"git.echol.cn/loser/xiecheng_server/initialize"
|
||||
"git.echol.cn/loser/xiecheng_server/service/system"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type server interface {
|
||||
ListenAndServe() error
|
||||
}
|
||||
|
||||
func RunWindowsServer() {
|
||||
if global.GVA_CONFIG.System.UseMultipoint || global.GVA_CONFIG.System.UseRedis {
|
||||
// 初始化redis服务
|
||||
initialize.Redis()
|
||||
initialize.RedisList()
|
||||
}
|
||||
|
||||
if global.GVA_CONFIG.System.UseMongo {
|
||||
err := initialize.Mongo.Initialization()
|
||||
if err != nil {
|
||||
zap.L().Error(fmt.Sprintf("%+v", err))
|
||||
}
|
||||
}
|
||||
// 从db加载jwt数据
|
||||
if global.GVA_DB != nil {
|
||||
system.LoadAll()
|
||||
}
|
||||
|
||||
Router := initialize.Routers()
|
||||
|
||||
address := fmt.Sprintf(":%d", global.GVA_CONFIG.System.Addr)
|
||||
s := initServer(address, Router)
|
||||
|
||||
global.GVA_LOG.Info("server run success on ", zap.String("address", address))
|
||||
|
||||
fmt.Printf(`
|
||||
欢迎使用 gin-vue-admin
|
||||
当前版本:v2.8.0
|
||||
加群方式:微信号:shouzi_1994 QQ群:470239250
|
||||
项目地址:https://github.com/flipped-aurora/gin-vue-admin
|
||||
插件市场:https://plugin.gin-vue-admin.com
|
||||
GVA讨论社区:https://support.qq.com/products/371961
|
||||
默认自动化文档地址:http://127.0.0.1%s/swagger/index.html
|
||||
默认前端文件运行地址:http://127.0.0.1:8080
|
||||
--------------------------------------版权声明--------------------------------------
|
||||
** 版权所有方:flipped-aurora开源团队 **
|
||||
** 版权持有公司:北京翻转极光科技有限责任公司 **
|
||||
** 剔除授权标识需购买商用授权:https://gin-vue-admin.com/empower/index.html **
|
||||
`, address)
|
||||
global.GVA_LOG.Error(s.ListenAndServe().Error())
|
||||
}
|
19
core/server_other.go
Normal file
19
core/server_other.go
Normal file
@@ -0,0 +1,19 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/fvbock/endless"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func initServer(address string, router *gin.Engine) server {
|
||||
s := endless.NewServer(address, router)
|
||||
s.ReadHeaderTimeout = 10 * time.Minute
|
||||
s.WriteTimeout = 10 * time.Minute
|
||||
s.MaxHeaderBytes = 1 << 20
|
||||
return s
|
||||
}
|
21
core/server_win.go
Normal file
21
core/server_win.go
Normal file
@@ -0,0 +1,21 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func initServer(address string, router *gin.Engine) server {
|
||||
return &http.Server{
|
||||
Addr: address,
|
||||
Handler: router,
|
||||
ReadTimeout: 10 * time.Minute,
|
||||
WriteTimeout: 10 * time.Minute,
|
||||
MaxHeaderBytes: 1 << 20,
|
||||
}
|
||||
}
|
71
core/viper.go
Normal file
71
core/viper.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"git.echol.cn/loser/xiecheng_server/core/internal"
|
||||
"github.com/gin-gonic/gin"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"git.echol.cn/loser/xiecheng_server/global"
|
||||
)
|
||||
|
||||
// Viper //
|
||||
// 优先级: 命令行 > 环境变量 > 默认值
|
||||
// Author [SliverHorn](https://github.com/SliverHorn)
|
||||
func Viper(path ...string) *viper.Viper {
|
||||
var config string
|
||||
|
||||
if len(path) == 0 {
|
||||
flag.StringVar(&config, "c", "", "choose config file.")
|
||||
flag.Parse()
|
||||
if config == "" { // 判断命令行参数是否为空
|
||||
if configEnv := os.Getenv(internal.ConfigEnv); configEnv == "" { // 判断 internal.ConfigEnv 常量存储的环境变量是否为空
|
||||
switch gin.Mode() {
|
||||
case gin.DebugMode:
|
||||
config = internal.ConfigDefaultFile
|
||||
case gin.ReleaseMode:
|
||||
config = internal.ConfigReleaseFile
|
||||
case gin.TestMode:
|
||||
config = internal.ConfigTestFile
|
||||
}
|
||||
fmt.Printf("您正在使用gin模式的%s环境名称,config的路径为%s\n", gin.Mode(), config)
|
||||
} else { // internal.ConfigEnv 常量存储的环境变量不为空 将值赋值于config
|
||||
config = configEnv
|
||||
fmt.Printf("您正在使用%s环境变量,config的路径为%s\n", internal.ConfigEnv, config)
|
||||
}
|
||||
} else { // 命令行参数不为空 将值赋值于config
|
||||
fmt.Printf("您正在使用命令行的-c参数传递的值,config的路径为%s\n", config)
|
||||
}
|
||||
} else { // 函数传递的可变参数的第一个值赋值于config
|
||||
config = path[0]
|
||||
fmt.Printf("您正在使用func Viper()传递的值,config的路径为%s\n", config)
|
||||
}
|
||||
|
||||
v := viper.New()
|
||||
v.SetConfigFile(config)
|
||||
v.SetConfigType("yaml")
|
||||
err := v.ReadInConfig()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Fatal error config file: %s \n", err))
|
||||
}
|
||||
v.WatchConfig()
|
||||
|
||||
v.OnConfigChange(func(e fsnotify.Event) {
|
||||
fmt.Println("config file changed:", e.Name)
|
||||
if err = v.Unmarshal(&global.GVA_CONFIG); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
})
|
||||
if err = v.Unmarshal(&global.GVA_CONFIG); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// root 适配性 根据root位置去找到对应迁移位置,保证root路径有效
|
||||
global.GVA_CONFIG.AutoCode.Root, _ = filepath.Abs("..")
|
||||
return v
|
||||
}
|
32
core/zap.go
Normal file
32
core/zap.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.echol.cn/loser/xiecheng_server/core/internal"
|
||||
"git.echol.cn/loser/xiecheng_server/global"
|
||||
"git.echol.cn/loser/xiecheng_server/utils"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Zap 获取 zap.Logger
|
||||
// Author [SliverHorn](https://github.com/SliverHorn)
|
||||
func Zap() (logger *zap.Logger) {
|
||||
if ok, _ := utils.PathExists(global.GVA_CONFIG.Zap.Director); !ok { // 判断是否有Director文件夹
|
||||
fmt.Printf("create %v directory\n", global.GVA_CONFIG.Zap.Director)
|
||||
_ = os.Mkdir(global.GVA_CONFIG.Zap.Director, os.ModePerm)
|
||||
}
|
||||
levels := global.GVA_CONFIG.Zap.Levels()
|
||||
length := len(levels)
|
||||
cores := make([]zapcore.Core, 0, length)
|
||||
for i := 0; i < length; i++ {
|
||||
core := internal.NewZapCore(levels[i])
|
||||
cores = append(cores, core)
|
||||
}
|
||||
logger = zap.New(zapcore.NewTee(cores...))
|
||||
if global.GVA_CONFIG.Zap.ShowLine {
|
||||
logger = logger.WithOptions(zap.AddCaller())
|
||||
}
|
||||
return logger
|
||||
}
|
Reference in New Issue
Block a user