mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 07:50:25 +08:00
refactor: slog替换logrus、日志操作统一、支持json、text格式等
This commit is contained in:
@@ -33,8 +33,12 @@ mysql:
|
|||||||
# password: 111049
|
# password: 111049
|
||||||
# db: 0
|
# db: 0
|
||||||
log:
|
log:
|
||||||
# 日志等级, trace, debug, info, warn, error, fatal
|
# 日志等级, debug, info, warn, error
|
||||||
level: info
|
level: info
|
||||||
|
# 日志格式类型, text/json
|
||||||
|
type: text
|
||||||
|
# 是否记录方法调用栈信息
|
||||||
|
add-source: false
|
||||||
# file:
|
# file:
|
||||||
# path: ./
|
# path: ./
|
||||||
# name: mayfly-go.log
|
# name: mayfly-go.log
|
||||||
@@ -21,7 +21,6 @@ require (
|
|||||||
github.com/pquerna/otp v1.4.0
|
github.com/pquerna/otp v1.4.0
|
||||||
github.com/redis/go-redis/v9 v9.1.0
|
github.com/redis/go-redis/v9 v9.1.0
|
||||||
github.com/robfig/cron/v3 v3.0.1 // 定时任务
|
github.com/robfig/cron/v3 v3.0.1 // 定时任务
|
||||||
github.com/sirupsen/logrus v1.9.3
|
|
||||||
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2
|
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2
|
||||||
go.mongodb.org/mongo-driver v1.12.1 // mongo
|
go.mongodb.org/mongo-driver v1.12.1 // mongo
|
||||||
golang.org/x/crypto v0.12.0 // ssh
|
golang.org/x/crypto v0.12.0 // ssh
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ func PwdAesEncrypt(password string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
aes := config.Conf.Aes
|
aes := config.Conf.Aes
|
||||||
if aes == nil {
|
if aes.Key == "" {
|
||||||
return password
|
return password
|
||||||
}
|
}
|
||||||
encryptPwd, err := aes.EncryptBase64([]byte(password))
|
encryptPwd, err := aes.EncryptBase64([]byte(password))
|
||||||
@@ -46,7 +46,7 @@ func PwdAesDecrypt(encryptPwd string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
aes := config.Conf.Aes
|
aes := config.Conf.Aes
|
||||||
if aes == nil {
|
if aes.Key == "" {
|
||||||
return encryptPwd
|
return encryptPwd
|
||||||
}
|
}
|
||||||
decryptPwd, err := aes.DecryptBase64(encryptPwd)
|
decryptPwd, err := aes.DecryptBase64(encryptPwd)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"mayfly-go/internal/machine/infrastructure/machine"
|
"mayfly-go/internal/machine/infrastructure/machine"
|
||||||
"mayfly-go/pkg/biz"
|
"mayfly-go/pkg/biz"
|
||||||
"mayfly-go/pkg/cache"
|
"mayfly-go/pkg/cache"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"mayfly-go/pkg/model"
|
"mayfly-go/pkg/model"
|
||||||
"mayfly-go/pkg/utils/collx"
|
"mayfly-go/pkg/utils/collx"
|
||||||
"mayfly-go/pkg/utils/structx"
|
"mayfly-go/pkg/utils/structx"
|
||||||
@@ -201,7 +201,7 @@ func (da *dbAppImpl) GetDbInstance(id uint64, db string) *DbInstance {
|
|||||||
DB, err := GetDbConn(d, db)
|
DB, err := GetDbConn(d, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
dbi.Close()
|
dbi.Close()
|
||||||
global.Log.Errorf("连接db失败: %s:%d/%s", d.Host, d.Port, db)
|
logx.Errorf("连接db失败: %s:%d/%s", d.Host, d.Port, db)
|
||||||
panic(biz.NewBizErr(fmt.Sprintf("数据库连接失败: %s", err.Error())))
|
panic(biz.NewBizErr(fmt.Sprintf("数据库连接失败: %s", err.Error())))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +213,7 @@ func (da *dbAppImpl) GetDbInstance(id uint64, db string) *DbInstance {
|
|||||||
DB.SetMaxIdleConns(1)
|
DB.SetMaxIdleConns(1)
|
||||||
|
|
||||||
dbi.db = DB
|
dbi.db = DB
|
||||||
global.Log.Infof("连接db: %s:%d/%s", d.Host, d.Port, db)
|
logx.Infof("连接db: %s:%d/%s", d.Host, d.Port, db)
|
||||||
if needCache {
|
if needCache {
|
||||||
dbCache.Put(cacheKey, dbi)
|
dbCache.Put(cacheKey, dbi)
|
||||||
}
|
}
|
||||||
@@ -285,7 +285,7 @@ func (di *DbInstance) GetMeta() DbMetadata {
|
|||||||
func (d *DbInstance) Close() {
|
func (d *DbInstance) Close() {
|
||||||
if d.db != nil {
|
if d.db != nil {
|
||||||
if err := d.db.Close(); err != nil {
|
if err := d.db.Close(); err != nil {
|
||||||
global.Log.Errorf("关闭数据库实例[%s]连接失败: %s", d.Id, err.Error())
|
logx.Errorf("关闭数据库实例[%s]连接失败: %s", d.Id, err.Error())
|
||||||
}
|
}
|
||||||
d.db = nil
|
d.db = nil
|
||||||
}
|
}
|
||||||
@@ -297,7 +297,7 @@ func (d *DbInstance) Close() {
|
|||||||
var dbCache = cache.NewTimedCache(consts.DbConnExpireTime, 5*time.Second).
|
var dbCache = cache.NewTimedCache(consts.DbConnExpireTime, 5*time.Second).
|
||||||
WithUpdateAccessTime(true).
|
WithUpdateAccessTime(true).
|
||||||
OnEvicted(func(key any, value any) {
|
OnEvicted(func(key any, value any) {
|
||||||
global.Log.Info(fmt.Sprintf("删除db连接缓存 id = %s", key))
|
logx.Info(fmt.Sprintf("删除db连接缓存 id = %s", key))
|
||||||
value.(*DbInstance).Close()
|
value.(*DbInstance).Close()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ func (d *dbSqlExecAppImpl) Exec(execSqlReq *DbSqlExecReq) (*DbSqlExecRes, error)
|
|||||||
stmt, err := sqlparser.Parse(sql)
|
stmt, err := sqlparser.Parse(sql)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// 就算解析失败也执行sql,让数据库来判断错误。如果是查询sql则简单判断是否有limit分页参数信息(兼容pgsql)
|
// 就算解析失败也执行sql,让数据库来判断错误。如果是查询sql则简单判断是否有limit分页参数信息(兼容pgsql)
|
||||||
// global.Log.Warnf("sqlparse解析sql[%s]失败: %s", sql, err.Error())
|
// logx.Warnf("sqlparse解析sql[%s]失败: %s", sql, err.Error())
|
||||||
lowerSql := strings.ToLower(execSqlReq.Sql)
|
lowerSql := strings.ToLower(execSqlReq.Sql)
|
||||||
isSelect := strings.HasPrefix(lowerSql, "select")
|
isSelect := strings.HasPrefix(lowerSql, "select")
|
||||||
if isSelect {
|
if isSelect {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package application
|
|||||||
import (
|
import (
|
||||||
"mayfly-go/internal/machine/domain/entity"
|
"mayfly-go/internal/machine/domain/entity"
|
||||||
"mayfly-go/internal/machine/domain/repository"
|
"mayfly-go/internal/machine/domain/repository"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"mayfly-go/pkg/model"
|
"mayfly-go/pkg/model"
|
||||||
"mayfly-go/pkg/rediscli"
|
"mayfly-go/pkg/rediscli"
|
||||||
"mayfly-go/pkg/scheduler"
|
"mayfly-go/pkg/scheduler"
|
||||||
@@ -154,7 +154,7 @@ func (m *machineCropJobAppImpl) MachineRelateCronJobs(machineId uint64, cronJobs
|
|||||||
func (m *machineCropJobAppImpl) InitCronJob() {
|
func (m *machineCropJobAppImpl) InitCronJob() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
global.Log.Errorf("机器计划任务初始化失败: %s", err.(error).Error())
|
logx.Errorf("机器计划任务初始化失败: %s", err.(error).Error())
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -241,7 +241,7 @@ func (m *machineCropJobAppImpl) runCronJob0(mid uint64, cronJob *entity.MachineC
|
|||||||
Status: entity.MachineCronJobExecStatusError,
|
Status: entity.MachineCronJobExecStatusError,
|
||||||
Res: res,
|
Res: res,
|
||||||
})
|
})
|
||||||
global.Log.Errorf("机器:[%d]执行[%s]计划任务失败: %s", mid, cronJob.Name, res)
|
logx.Errorf("机器:[%d]执行[%s]计划任务失败: %s", mid, cronJob.Name, res)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -250,9 +250,9 @@ func (m *machineCropJobAppImpl) runCronJob0(mid uint64, cronJob *entity.MachineC
|
|||||||
if res == "" {
|
if res == "" {
|
||||||
res = err.Error()
|
res = err.Error()
|
||||||
}
|
}
|
||||||
global.Log.Errorf("机器:[%d]执行[%s]计划任务失败: %s", mid, cronJob.Name, res)
|
logx.Errorf("机器:[%d]执行[%s]计划任务失败: %s", mid, cronJob.Name, res)
|
||||||
} else {
|
} else {
|
||||||
global.Log.Debugf("机器:[%d]执行[%s]计划任务成功, 执行结果: %s", mid, cronJob.Name, res)
|
logx.Debugf("机器:[%d]执行[%s]计划任务成功, 执行结果: %s", mid, cronJob.Name, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cronJob.SaveExecResType == entity.SaveExecResTypeNo ||
|
if cronJob.SaveExecResType == entity.SaveExecResTypeNo ||
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"mayfly-go/internal/machine/domain/repository"
|
"mayfly-go/internal/machine/domain/repository"
|
||||||
"mayfly-go/internal/machine/infrastructure/machine"
|
"mayfly-go/internal/machine/infrastructure/machine"
|
||||||
"mayfly-go/pkg/biz"
|
"mayfly-go/pkg/biz"
|
||||||
"mayfly-go/pkg/gormx"
|
|
||||||
"mayfly-go/pkg/model"
|
"mayfly-go/pkg/model"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -93,9 +92,9 @@ func (m *machineFileAppImpl) Save(entity *entity.MachineFile) {
|
|||||||
biz.NotNil(m.machineRepo.GetById(entity.MachineId, "Name"), "该机器不存在")
|
biz.NotNil(m.machineRepo.GetById(entity.MachineId, "Name"), "该机器不存在")
|
||||||
|
|
||||||
if entity.Id != 0 {
|
if entity.Id != 0 {
|
||||||
gormx.UpdateById(entity)
|
m.machineFileRepo.UpdateById(entity)
|
||||||
} else {
|
} else {
|
||||||
gormx.Insert(entity)
|
m.machineFileRepo.Create(entity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"mayfly-go/internal/machine/domain/entity"
|
"mayfly-go/internal/machine/domain/entity"
|
||||||
"mayfly-go/pkg/biz"
|
"mayfly-go/pkg/biz"
|
||||||
"mayfly-go/pkg/cache"
|
"mayfly-go/pkg/cache"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ func (c *Cli) connect() error {
|
|||||||
// 关闭client并从缓存中移除,如果使用隧道则也关闭
|
// 关闭client并从缓存中移除,如果使用隧道则也关闭
|
||||||
func (c *Cli) Close() {
|
func (c *Cli) Close() {
|
||||||
m := c.machine
|
m := c.machine
|
||||||
global.Log.Info(fmt.Sprintf("关闭机器客户端连接-> id: %d, name: %s, ip: %s", m.Id, m.Name, m.Ip))
|
logx.Info(fmt.Sprintf("关闭机器客户端连接-> id: %d, name: %s, ip: %s", m.Id, m.Name, m.Ip))
|
||||||
if c.client != nil {
|
if c.client != nil {
|
||||||
c.client.Close()
|
c.client.Close()
|
||||||
c.client = nil
|
c.client = nil
|
||||||
@@ -173,25 +173,24 @@ func DeleteCli(id uint64) {
|
|||||||
|
|
||||||
// 从缓存中获取客户端信息,不存在则回调获取机器信息函数,并新建
|
// 从缓存中获取客户端信息,不存在则回调获取机器信息函数,并新建
|
||||||
func GetCli(machineId uint64, getMachine func(uint64) *Info) (*Cli, error) {
|
func GetCli(machineId uint64, getMachine func(uint64) *Info) (*Cli, error) {
|
||||||
cli, err := cliCache.ComputeIfAbsent(machineId, func(_ any) (any, error) {
|
if load, ok := cliCache.Get(machineId); ok {
|
||||||
me := getMachine(machineId)
|
return load.(*Cli), nil
|
||||||
err := IfUseSshTunnelChangeIpPort(me, getMachine)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("ssh隧道连接失败: %s", err.Error())
|
|
||||||
}
|
|
||||||
c, err := newClient(me)
|
|
||||||
if err != nil {
|
|
||||||
CloseSshTunnelMachine(me.SshTunnelMachineId, me.Id)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c.sshTunnelMachineId = me.SshTunnelMachineId
|
|
||||||
return c, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if cli != nil {
|
|
||||||
return cli.(*Cli), err
|
|
||||||
}
|
}
|
||||||
return nil, err
|
|
||||||
|
me := getMachine(machineId)
|
||||||
|
err := IfUseSshTunnelChangeIpPort(me, getMachine)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("ssh隧道连接失败: %s", err.Error())
|
||||||
|
}
|
||||||
|
c, err := newClient(me)
|
||||||
|
if err != nil {
|
||||||
|
CloseSshTunnelMachine(me.SshTunnelMachineId, me.Id)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.sshTunnelMachineId = me.SshTunnelMachineId
|
||||||
|
|
||||||
|
cliCache.Put(machineId, c)
|
||||||
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 测试连接,使用传值的方式,而非引用。因为如果使用了ssh隧道,则ip和端口会变为本地映射地址与端口
|
// 测试连接,使用传值的方式,而非引用。因为如果使用了ssh隧道,则ip和端口会变为本地映射地址与端口
|
||||||
@@ -276,7 +275,7 @@ func newClient(machine *Info) (*Cli, error) {
|
|||||||
return nil, errors.New("机器不存在")
|
return nil, errors.New("机器不存在")
|
||||||
}
|
}
|
||||||
|
|
||||||
global.Log.Infof("[%s]机器连接:%s:%d", machine.Name, machine.Ip, machine.Port)
|
logx.Infof("[%s]机器连接:%s:%d", machine.Name, machine.Ip, machine.Port)
|
||||||
cli := new(Cli)
|
cli := new(Cli)
|
||||||
cli.machine = machine
|
cli.machine = machine
|
||||||
err := cli.connect()
|
err := cli.connect()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package machine
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"mayfly-go/pkg/scheduler"
|
"mayfly-go/pkg/scheduler"
|
||||||
"mayfly-go/pkg/utils/netx"
|
"mayfly-go/pkg/utils/netx"
|
||||||
"net"
|
"net"
|
||||||
@@ -29,7 +29,7 @@ var (
|
|||||||
type CheckSshTunnelMachineHasUseFunc func(int) bool
|
type CheckSshTunnelMachineHasUseFunc func(int) bool
|
||||||
|
|
||||||
func startCheckUse() {
|
func startCheckUse() {
|
||||||
global.Log.Info("开启定时检测ssh隧道机器是否还有被使用")
|
logx.Info("开启定时检测ssh隧道机器是否还有被使用")
|
||||||
// 每十分钟检查一次隧道机器是否还有被使用
|
// 每十分钟检查一次隧道机器是否还有被使用
|
||||||
scheduler.AddFun("@every 10m", func() {
|
scheduler.AddFun("@every 10m", func() {
|
||||||
if !mutex.TryLock() {
|
if !mutex.TryLock() {
|
||||||
@@ -38,7 +38,7 @@ func startCheckUse() {
|
|||||||
defer mutex.Unlock()
|
defer mutex.Unlock()
|
||||||
// 遍历隧道机器,都未被使用将会被关闭
|
// 遍历隧道机器,都未被使用将会被关闭
|
||||||
for mid, sshTunnelMachine := range sshTunnelMachines {
|
for mid, sshTunnelMachine := range sshTunnelMachines {
|
||||||
global.Log.Debugf("开始定时检查ssh隧道机器[%d]是否还有被使用...", mid)
|
logx.Debugf("开始定时检查ssh隧道机器[%d]是否还有被使用...", mid)
|
||||||
hasUse := false
|
hasUse := false
|
||||||
for _, checkUseFunc := range checkSshTunnelMachineHasUseFuncs {
|
for _, checkUseFunc := range checkSshTunnelMachineHasUseFuncs {
|
||||||
// 如果一个在使用则返回不关闭,不继续后续检查
|
// 如果一个在使用则返回不关闭,不继续后续检查
|
||||||
@@ -126,10 +126,10 @@ func (stm *SshTunnelMachine) Close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if stm.SshClient != nil {
|
if stm.SshClient != nil {
|
||||||
global.Log.Infof("ssh隧道机器[%d]未被使用, 关闭隧道...", stm.machineId)
|
logx.Infof("ssh隧道机器[%d]未被使用, 关闭隧道...", stm.machineId)
|
||||||
err := stm.SshClient.Close()
|
err := stm.SshClient.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Log.Errorf("关闭ssh隧道机器[%d]发生错误: %s", stm.machineId, err.Error())
|
logx.Errorf("关闭ssh隧道机器[%d]发生错误: %s", stm.machineId, err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete(sshTunnelMachines, stm.machineId)
|
delete(sshTunnelMachines, stm.machineId)
|
||||||
@@ -152,7 +152,7 @@ func GetSshTunnelMachine(machineId int, getMachine func(uint64) *Info) (*SshTunn
|
|||||||
}
|
}
|
||||||
sshTunnelMachine = &SshTunnelMachine{SshClient: sshClient, machineId: machineId, tunnels: map[uint64]*Tunnel{}}
|
sshTunnelMachine = &SshTunnelMachine{SshClient: sshClient, machineId: machineId, tunnels: map[uint64]*Tunnel{}}
|
||||||
|
|
||||||
global.Log.Infof("初次连接ssh隧道机器[%d][%s:%d]", machineId, me.Ip, me.Port)
|
logx.Infof("初次连接ssh隧道机器[%d][%s:%d]", machineId, me.Ip, me.Port)
|
||||||
sshTunnelMachines[machineId] = sshTunnelMachine
|
sshTunnelMachines[machineId] = sshTunnelMachine
|
||||||
|
|
||||||
// 如果实用了隧道机器且还没开始定时检查是否还被实用,则执行定时任务检测隧道是否还被使用
|
// 如果实用了隧道机器且还没开始定时检查是否还被实用,则执行定时任务检测隧道是否还被使用
|
||||||
@@ -195,31 +195,31 @@ func (r *Tunnel) Open(sshClient *ssh.Client) {
|
|||||||
localAddr := fmt.Sprintf("%s:%d", r.localHost, r.localPort)
|
localAddr := fmt.Sprintf("%s:%d", r.localHost, r.localPort)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
global.Log.Debugf("隧道 %v 等待客户端访问 %v", r.id, localAddr)
|
logx.Debugf("隧道 %v 等待客户端访问 %v", r.id, localAddr)
|
||||||
localConn, err := r.listener.Accept()
|
localConn, err := r.listener.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Log.Debugf("隧道 %v 接受连接失败 %v, 退出循环", r.id, err.Error())
|
logx.Debugf("隧道 %v 接受连接失败 %v, 退出循环", r.id, err.Error())
|
||||||
global.Log.Debug("-------------------------------------------------")
|
logx.Debug("-------------------------------------------------")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.localConnections = append(r.localConnections, localConn)
|
r.localConnections = append(r.localConnections, localConn)
|
||||||
|
|
||||||
global.Log.Debugf("隧道 %v 新增本地连接 %v", r.id, localConn.RemoteAddr().String())
|
logx.Debugf("隧道 %v 新增本地连接 %v", r.id, localConn.RemoteAddr().String())
|
||||||
remoteAddr := fmt.Sprintf("%s:%d", r.remoteHost, r.remotePort)
|
remoteAddr := fmt.Sprintf("%s:%d", r.remoteHost, r.remotePort)
|
||||||
global.Log.Debugf("隧道 %v 连接远程地址 %v ...", r.id, remoteAddr)
|
logx.Debugf("隧道 %v 连接远程地址 %v ...", r.id, remoteAddr)
|
||||||
remoteConn, err := sshClient.Dial("tcp", remoteAddr)
|
remoteConn, err := sshClient.Dial("tcp", remoteAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Log.Debugf("隧道 %v 连接远程地址 %v, 退出循环", r.id, err.Error())
|
logx.Debugf("隧道 %v 连接远程地址 %v, 退出循环", r.id, err.Error())
|
||||||
global.Log.Debug("-------------------------------------------------")
|
logx.Debug("-------------------------------------------------")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.remoteConnections = append(r.remoteConnections, remoteConn)
|
r.remoteConnections = append(r.remoteConnections, remoteConn)
|
||||||
|
|
||||||
global.Log.Debugf("隧道 %v 连接远程主机成功", r.id)
|
logx.Debugf("隧道 %v 连接远程主机成功", r.id)
|
||||||
go copyConn(localConn, remoteConn)
|
go copyConn(localConn, remoteConn)
|
||||||
go copyConn(remoteConn, localConn)
|
go copyConn(remoteConn, localConn)
|
||||||
global.Log.Debugf("隧道 %v 开始转发数据 [%v]->[%v]", r.id, localAddr, remoteAddr)
|
logx.Debugf("隧道 %v 开始转发数据 [%v]->[%v]", r.id, localAddr, remoteAddr)
|
||||||
global.Log.Debug("~~~~~~~~~~~~~~~~~~~~分割线~~~~~~~~~~~~~~~~~~~~~~~~")
|
logx.Debug("~~~~~~~~~~~~~~~~~~~~分割线~~~~~~~~~~~~~~~~~~~~~~~~")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,7 +233,7 @@ func (r *Tunnel) Close() {
|
|||||||
}
|
}
|
||||||
r.remoteConnections = nil
|
r.remoteConnections = nil
|
||||||
_ = r.listener.Close()
|
_ = r.listener.Close()
|
||||||
global.Log.Debugf("隧道 %d 监听器关闭", r.id)
|
logx.Debugf("隧道 %d 监听器关闭", r.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyConn(writer, reader net.Conn) {
|
func copyConn(writer, reader net.Conn) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
@@ -68,12 +68,12 @@ func (r TerminalSession) Start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r TerminalSession) Stop() {
|
func (r TerminalSession) Stop() {
|
||||||
global.Log.Debug("close machine ssh terminal session")
|
logx.Debug("close machine ssh terminal session")
|
||||||
r.tick.Stop()
|
r.tick.Stop()
|
||||||
r.cancel()
|
r.cancel()
|
||||||
if r.terminal != nil {
|
if r.terminal != nil {
|
||||||
if err := r.terminal.Close(); err != nil {
|
if err := r.terminal.Close(); err != nil {
|
||||||
global.Log.Errorf("关闭机器ssh终端失败: %s", err.Error())
|
logx.Errorf("关闭机器ssh终端失败: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,7 @@ func (ts TerminalSession) readFormTerminal() {
|
|||||||
rn, size, err := ts.terminal.ReadRune()
|
rn, size, err := ts.terminal.ReadRune()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != io.EOF {
|
if err != io.EOF {
|
||||||
global.Log.Error("机器ssh终端读取消息失败: ", err)
|
logx.Error("机器ssh终端读取消息失败: ", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -108,7 +108,7 @@ func (ts TerminalSession) writeToWebsocket() {
|
|||||||
if len(buf) > 0 {
|
if len(buf) > 0 {
|
||||||
s := string(buf)
|
s := string(buf)
|
||||||
if err := WriteMessage(ts.wsConn, s); err != nil {
|
if err := WriteMessage(ts.wsConn, s); err != nil {
|
||||||
global.Log.Error("机器ssh终端发送消息至websocket失败: ", err)
|
logx.Error("机器ssh终端发送消息至websocket失败: ", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 如果记录器存在,则记录操作回放信息
|
// 如果记录器存在,则记录操作回放信息
|
||||||
@@ -148,25 +148,25 @@ func (ts *TerminalSession) receiveWsMsg() {
|
|||||||
// read websocket msg
|
// read websocket msg
|
||||||
_, wsData, err := wsConn.ReadMessage()
|
_, wsData, err := wsConn.ReadMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Log.Debug("机器ssh终端读取websocket消息失败: ", err)
|
logx.Debugf("机器ssh终端读取websocket消息失败: %s", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 解析消息
|
// 解析消息
|
||||||
msgObj := WsMsg{}
|
msgObj := WsMsg{}
|
||||||
if err := json.Unmarshal(wsData, &msgObj); err != nil {
|
if err := json.Unmarshal(wsData, &msgObj); err != nil {
|
||||||
global.Log.Error("机器ssh终端消息解析失败: ", err)
|
logx.Error("机器ssh终端消息解析失败: ", err)
|
||||||
}
|
}
|
||||||
switch msgObj.Type {
|
switch msgObj.Type {
|
||||||
case Resize:
|
case Resize:
|
||||||
if msgObj.Cols > 0 && msgObj.Rows > 0 {
|
if msgObj.Cols > 0 && msgObj.Rows > 0 {
|
||||||
if err := ts.terminal.WindowChange(msgObj.Rows, msgObj.Cols); err != nil {
|
if err := ts.terminal.WindowChange(msgObj.Rows, msgObj.Cols); err != nil {
|
||||||
global.Log.Error("ssh pty change windows size failed")
|
logx.Error("ssh pty change windows size failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case Data:
|
case Data:
|
||||||
_, err := ts.terminal.Write([]byte(msgObj.Msg))
|
_, err := ts.terminal.Write([]byte(msgObj.Msg))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Log.Debugf("机器ssh终端写入消息失败: %s", err)
|
logx.Debugf("机器ssh终端写入消息失败: %s", err)
|
||||||
}
|
}
|
||||||
case Ping:
|
case Ping:
|
||||||
_, err := ts.terminal.SshSession.SendRequest("ping", true, nil)
|
_, err := ts.terminal.SshSession.SendRequest("ping", true, nil)
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ func (m *machineFileRepoImpl) Delete(id uint64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *machineFileRepoImpl) Create(entity *entity.MachineFile) {
|
func (m *machineFileRepoImpl) Create(entity *entity.MachineFile) {
|
||||||
gormx.Insert(entity)
|
biz.ErrIsNil(gormx.Insert(entity), "新增机器文件配置失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *machineFileRepoImpl) UpdateById(entity *entity.MachineFile) {
|
func (m *machineFileRepoImpl) UpdateById(entity *entity.MachineFile) {
|
||||||
gormx.UpdateById(entity)
|
biz.ErrIsNil(gormx.UpdateById(entity), "更新机器文件失败")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"mayfly-go/internal/mongo/domain/repository"
|
"mayfly-go/internal/mongo/domain/repository"
|
||||||
"mayfly-go/pkg/biz"
|
"mayfly-go/pkg/biz"
|
||||||
"mayfly-go/pkg/cache"
|
"mayfly-go/pkg/cache"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"mayfly-go/pkg/model"
|
"mayfly-go/pkg/model"
|
||||||
"mayfly-go/pkg/utils/netx"
|
"mayfly-go/pkg/utils/netx"
|
||||||
"mayfly-go/pkg/utils/structx"
|
"mayfly-go/pkg/utils/structx"
|
||||||
@@ -104,7 +104,7 @@ func (d *mongoAppImpl) GetMongoInst(id uint64) *MongoInstance {
|
|||||||
var mongoCliCache = cache.NewTimedCache(consts.MongoConnExpireTime, 5*time.Second).
|
var mongoCliCache = cache.NewTimedCache(consts.MongoConnExpireTime, 5*time.Second).
|
||||||
WithUpdateAccessTime(true).
|
WithUpdateAccessTime(true).
|
||||||
OnEvicted(func(key any, value any) {
|
OnEvicted(func(key any, value any) {
|
||||||
global.Log.Info("删除mongo连接缓存: id = ", key)
|
logx.Info("删除mongo连接缓存: id = ", key)
|
||||||
value.(*MongoInstance).Close()
|
value.(*MongoInstance).Close()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ type MongoInstance struct {
|
|||||||
func (mi *MongoInstance) Close() {
|
func (mi *MongoInstance) Close() {
|
||||||
if mi.Cli != nil {
|
if mi.Cli != nil {
|
||||||
if err := mi.Cli.Disconnect(context.Background()); err != nil {
|
if err := mi.Cli.Disconnect(context.Background()); err != nil {
|
||||||
global.Log.Errorf("关闭mongo实例[%d]连接失败: %s", mi.Id, err)
|
logx.Errorf("关闭mongo实例[%d]连接失败: %s", mi.Id, err)
|
||||||
}
|
}
|
||||||
mi.Cli = nil
|
mi.Cli = nil
|
||||||
}
|
}
|
||||||
@@ -192,7 +192,7 @@ func connect(me *entity.Mongo) (*MongoInstance, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
global.Log.Infof("连接mongo: %s", func(str string) string {
|
logx.Infof("连接mongo: %s", func(str string) string {
|
||||||
reg := regexp.MustCompile(`(^mongodb://.+?:)(.+)(@.+$)`)
|
reg := regexp.MustCompile(`(^mongodb://.+?:)(.+)(@.+$)`)
|
||||||
return reg.ReplaceAllString(str, `${1}****${3}`)
|
return reg.ReplaceAllString(str, `${1}****${3}`)
|
||||||
}(me.Uri))
|
}(me.Uri))
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"mayfly-go/internal/redis/domain/repository"
|
"mayfly-go/internal/redis/domain/repository"
|
||||||
"mayfly-go/pkg/biz"
|
"mayfly-go/pkg/biz"
|
||||||
"mayfly-go/pkg/cache"
|
"mayfly-go/pkg/cache"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"mayfly-go/pkg/model"
|
"mayfly-go/pkg/model"
|
||||||
"mayfly-go/pkg/utils/netx"
|
"mayfly-go/pkg/utils/netx"
|
||||||
"mayfly-go/pkg/utils/structx"
|
"mayfly-go/pkg/utils/structx"
|
||||||
@@ -163,7 +163,7 @@ func (r *redisAppImpl) GetRedisInstance(id uint64, db int) *RedisInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
global.Log.Infof("连接redis: %s", re.Host)
|
logx.Infof("连接redis: %s", re.Host)
|
||||||
if needCache {
|
if needCache {
|
||||||
redisCache.Put(getRedisCacheKey(id, db), ri)
|
redisCache.Put(getRedisCacheKey(id, db), ri)
|
||||||
}
|
}
|
||||||
@@ -257,7 +257,7 @@ func getRedisDialer(machineId int) func(ctx context.Context, network, addr strin
|
|||||||
var redisCache = cache.NewTimedCache(consts.RedisConnExpireTime, 5*time.Second).
|
var redisCache = cache.NewTimedCache(consts.RedisConnExpireTime, 5*time.Second).
|
||||||
WithUpdateAccessTime(true).
|
WithUpdateAccessTime(true).
|
||||||
OnEvicted(func(key any, value any) {
|
OnEvicted(func(key any, value any) {
|
||||||
global.Log.Info(fmt.Sprintf("删除redis连接缓存 id = %s", key))
|
logx.Info(fmt.Sprintf("删除redis连接缓存 id = %s", key))
|
||||||
value.(*RedisInstance).Close()
|
value.(*RedisInstance).Close()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -350,13 +350,13 @@ func (r *RedisInstance) Close() {
|
|||||||
mode := r.Info.Mode
|
mode := r.Info.Mode
|
||||||
if mode == entity.RedisModeStandalone || mode == entity.RedisModeSentinel {
|
if mode == entity.RedisModeStandalone || mode == entity.RedisModeSentinel {
|
||||||
if err := r.Cli.Close(); err != nil {
|
if err := r.Cli.Close(); err != nil {
|
||||||
global.Log.Errorf("关闭redis单机实例[%s]连接失败: %s", r.Id, err.Error())
|
logx.Errorf("关闭redis单机实例[%s]连接失败: %s", r.Id, err.Error())
|
||||||
}
|
}
|
||||||
r.Cli = nil
|
r.Cli = nil
|
||||||
}
|
}
|
||||||
if mode == entity.RedisModeCluster {
|
if mode == entity.RedisModeCluster {
|
||||||
if err := r.ClusterCli.Close(); err != nil {
|
if err := r.ClusterCli.Close(); err != nil {
|
||||||
global.Log.Errorf("关闭redis集群实例[%s]连接失败: %s", r.Id, err.Error())
|
logx.Errorf("关闭redis集群实例[%s]连接失败: %s", r.Id, err.Error())
|
||||||
}
|
}
|
||||||
r.ClusterCli = nil
|
r.ClusterCli = nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"mayfly-go/pkg/biz"
|
"mayfly-go/pkg/biz"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"mayfly-go/pkg/req"
|
"mayfly-go/pkg/req"
|
||||||
"mayfly-go/pkg/ws"
|
"mayfly-go/pkg/ws"
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ func (s *System) ConnectWs(g *gin.Context) {
|
|||||||
wsConn, err := ws.Upgrader.Upgrade(g.Writer, g.Request, nil)
|
wsConn, err := ws.Upgrader.Upgrade(g.Writer, g.Request, nil)
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
global.Log.Error(err.(error).Error())
|
logx.ErrorTrace("websocket连接失败: ", err.(error))
|
||||||
if wsConn != nil {
|
if wsConn != nil {
|
||||||
wsConn.WriteMessage(websocket.TextMessage, []byte(err.(error).Error()))
|
wsConn.WriteMessage(websocket.TextMessage, []byte(err.(error).Error()))
|
||||||
wsConn.Close()
|
wsConn.Close()
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"mayfly-go/internal/sys/domain/repository"
|
"mayfly-go/internal/sys/domain/repository"
|
||||||
"mayfly-go/pkg/biz"
|
"mayfly-go/pkg/biz"
|
||||||
"mayfly-go/pkg/cache"
|
"mayfly-go/pkg/cache"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"mayfly-go/pkg/model"
|
"mayfly-go/pkg/model"
|
||||||
"mayfly-go/pkg/utils/jsonx"
|
"mayfly-go/pkg/utils/jsonx"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -61,7 +61,7 @@ func (a *configAppImpl) GetConfig(key string) *entity.Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := a.configRepo.GetConfig(config, "Id", "Key", "Value", "Permission"); err != nil {
|
if err := a.configRepo.GetConfig(config, "Id", "Key", "Value", "Permission"); err != nil {
|
||||||
global.Log.Warnf("不存在key = [%s] 的系统配置", key)
|
logx.Warnf("不存在key = [%s] 的系统配置", key)
|
||||||
} else {
|
} else {
|
||||||
cache.SetStr(SysConfigKeyPrefix+key, jsonx.ToStr(config), -1)
|
cache.SetStr(SysConfigKeyPrefix+key, jsonx.ToStr(config), -1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package biz
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"mayfly-go/pkg/utils/anyx"
|
"mayfly-go/pkg/utils/anyx"
|
||||||
|
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -10,13 +10,14 @@ import (
|
|||||||
|
|
||||||
func ErrIsNil(err error, msg string, params ...any) {
|
func ErrIsNil(err error, msg string, params ...any) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Log.Error(msg + ": " + err.Error())
|
// logx.ErrorTrace(msg, err)
|
||||||
panic(NewBizErr(fmt.Sprintf(msg, params...)))
|
panic(NewBizErr(fmt.Sprintf(msg, params...)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ErrIsNilAppendErr(err error, msg string) {
|
func ErrIsNilAppendErr(err error, msg string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// logx.ErrorTrace(msg, err)
|
||||||
panic(NewBizErr(fmt.Sprintf(msg, err.Error())))
|
panic(NewBizErr(fmt.Sprintf(msg, err.Error())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -26,7 +27,7 @@ func IsNil(err error) {
|
|||||||
case *BizError:
|
case *BizError:
|
||||||
panic(t)
|
panic(t)
|
||||||
case error:
|
case error:
|
||||||
global.Log.Error("非业务异常: " + err.Error())
|
logx.Error("非业务异常: " + err.Error())
|
||||||
panic(NewBizErr(fmt.Sprintf("非业务异常: %s", err.Error())))
|
panic(NewBizErr(fmt.Sprintf("非业务异常: %s", err.Error())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package biz
|
package biz
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
// 业务错误
|
// 业务错误
|
||||||
type BizError struct {
|
type BizError struct {
|
||||||
code int16
|
code int16
|
||||||
@@ -23,6 +25,10 @@ func (e BizError) Code() int16 {
|
|||||||
return e.code
|
return e.code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e BizError) String() string {
|
||||||
|
return fmt.Sprintf("errCode: %d, errMsg: %s", e.Code(), e.Error())
|
||||||
|
}
|
||||||
|
|
||||||
// 创建业务逻辑错误结构体,默认为业务逻辑错误
|
// 创建业务逻辑错误结构体,默认为业务逻辑错误
|
||||||
func NewBizErr(msg string) BizError {
|
func NewBizErr(msg string) BizError {
|
||||||
return BizError{code: BizErr.code, err: msg}
|
return BizError{code: BizErr.code, err: msg}
|
||||||
|
|||||||
4
server/pkg/cache/str_cache.go
vendored
4
server/pkg/cache/str_cache.go
vendored
@@ -1,7 +1,7 @@
|
|||||||
package cache
|
package cache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"mayfly-go/pkg/rediscli"
|
"mayfly-go/pkg/rediscli"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@@ -33,7 +33,7 @@ func GetInt(key string) int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
if intV, err := strconv.Atoi(val); err != nil {
|
if intV, err := strconv.Atoi(val); err != nil {
|
||||||
global.Log.Error("获取缓存中的int值转换失败", err)
|
logx.Error("获取缓存中的int值转换失败", err)
|
||||||
return 0
|
return 0
|
||||||
} else {
|
} else {
|
||||||
return intV
|
return intV
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ func (a *Aes) DecryptBase64(data string) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (j *Aes) Valid() {
|
func (j *Aes) Valid() {
|
||||||
|
if j.Key == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
aesKeyLen := len(j.Key)
|
aesKeyLen := len(j.Key)
|
||||||
assert.IsTrue(aesKeyLen == 16 || aesKeyLen == 24 || aesKeyLen == 32,
|
assert.IsTrue(aesKeyLen == 16 || aesKeyLen == 24 || aesKeyLen == 32,
|
||||||
fmt.Sprintf("config.yml之 [aes.key] 长度需为16、24、32位长度, 当前为%d位", aesKeyLen))
|
fmt.Sprintf("config.yml之 [aes.key] 长度需为16、24、32位长度, 当前为%d位", aesKeyLen))
|
||||||
|
|||||||
@@ -3,14 +3,21 @@ package config
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"mayfly-go/pkg/logx"
|
||||||
"mayfly-go/pkg/utils/assert"
|
|
||||||
"mayfly-go/pkg/utils/ymlx"
|
"mayfly-go/pkg/utils/ymlx"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ConfigItem interface {
|
||||||
|
// 验证配置
|
||||||
|
Valid()
|
||||||
|
|
||||||
|
// 如果不存在配置值,则设置默认值
|
||||||
|
Default()
|
||||||
|
}
|
||||||
|
|
||||||
// 配置文件映射对象
|
// 配置文件映射对象
|
||||||
var Conf *Config
|
var Conf *Config
|
||||||
|
|
||||||
@@ -23,14 +30,14 @@ func Init() {
|
|||||||
// 读取配置文件信息
|
// 读取配置文件信息
|
||||||
yc := &Config{}
|
yc := &Config{}
|
||||||
if err := ymlx.LoadYml(startConfigParam.ConfigFilePath, yc); err != nil {
|
if err := ymlx.LoadYml(startConfigParam.ConfigFilePath, yc); err != nil {
|
||||||
slog.Warn(fmt.Sprintf("读取配置文件[%s]失败: %s, 使用系统默认配置或环境变量配置", startConfigParam.ConfigFilePath, err.Error()))
|
logx.Warn(fmt.Sprintf("读取配置文件[%s]失败: %s, 使用系统默认配置或环境变量配置", startConfigParam.ConfigFilePath, err.Error()))
|
||||||
// 设置默认信息,主要方便后续的系统环境变量替换
|
|
||||||
yc.SetDefaultConfig()
|
|
||||||
}
|
}
|
||||||
// 校验配置文件内容信息
|
|
||||||
yc.Valid()
|
|
||||||
// 尝试使用系统环境变量替换配置信息
|
// 尝试使用系统环境变量替换配置信息
|
||||||
yc.ReplaceOsEnv()
|
yc.ReplaceOsEnv()
|
||||||
|
|
||||||
|
yc.IfBlankDefaultValue()
|
||||||
|
// 校验配置文件内容信息
|
||||||
|
yc.Valid()
|
||||||
Conf = yc
|
Conf = yc
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,21 +48,34 @@ type CmdConfigParam struct {
|
|||||||
|
|
||||||
// yaml配置文件映射对象
|
// yaml配置文件映射对象
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Server *Server `yaml:"server"`
|
Server Server `yaml:"server"`
|
||||||
Jwt *Jwt `yaml:"jwt"`
|
Jwt Jwt `yaml:"jwt"`
|
||||||
Aes *Aes `yaml:"aes"`
|
Aes Aes `yaml:"aes"`
|
||||||
Mysql *Mysql `yaml:"mysql"`
|
Mysql Mysql `yaml:"mysql"`
|
||||||
Redis *Redis `yaml:"redis"`
|
Redis Redis `yaml:"redis"`
|
||||||
Log *Log `yaml:"log"`
|
Log Log `yaml:"log"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) IfBlankDefaultValue() {
|
||||||
|
c.Log.Default()
|
||||||
|
// 优先初始化log,因为后续的一些default方法中会需要用到。统一日志输出
|
||||||
|
logx.Init(logx.Config{
|
||||||
|
Level: c.Log.Level,
|
||||||
|
Type: c.Log.Type,
|
||||||
|
AddSource: c.Log.AddSource,
|
||||||
|
Filename: c.Log.File.Name,
|
||||||
|
Filepath: c.Log.File.Path,
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Server.Default()
|
||||||
|
c.Jwt.Default()
|
||||||
|
c.Mysql.Default()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 配置文件内容校验
|
// 配置文件内容校验
|
||||||
func (c *Config) Valid() {
|
func (c *Config) Valid() {
|
||||||
assert.IsTrue(c.Jwt != nil, "配置文件的[jwt]信息不能为空")
|
|
||||||
c.Jwt.Valid()
|
c.Jwt.Valid()
|
||||||
if c.Aes != nil {
|
c.Aes.Valid()
|
||||||
c.Aes.Valid()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 替换系统环境变量,如果环境变量中存在该值,则优秀使用环境变量设定的值
|
// 替换系统环境变量,如果环境变量中存在该值,则优秀使用环境变量设定的值
|
||||||
@@ -99,29 +119,3 @@ func (c *Config) ReplaceOsEnv() {
|
|||||||
c.Jwt.Key = jwtKey
|
c.Jwt.Key = jwtKey
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) SetDefaultConfig() {
|
|
||||||
c.Server = &Server{
|
|
||||||
Model: "release",
|
|
||||||
Port: 8888,
|
|
||||||
MachineRecPath: "./rec",
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Jwt = &Jwt{
|
|
||||||
ExpireTime: 1440,
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Aes = &Aes{
|
|
||||||
Key: "1111111111111111",
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Mysql = &Mysql{
|
|
||||||
Host: "localhost:3306",
|
|
||||||
Config: "charset=utf8&loc=Local&parseTime=true",
|
|
||||||
MaxIdleConns: 5,
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Log = &Log{
|
|
||||||
Level: "info",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,12 +1,29 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import "mayfly-go/pkg/utils/assert"
|
import (
|
||||||
|
"mayfly-go/pkg/logx"
|
||||||
|
"mayfly-go/pkg/utils/assert"
|
||||||
|
"mayfly-go/pkg/utils/stringx"
|
||||||
|
)
|
||||||
|
|
||||||
type Jwt struct {
|
type Jwt struct {
|
||||||
Key string `yaml:"key"`
|
Key string `yaml:"key"`
|
||||||
ExpireTime uint64 `yaml:"expire-time"` // 过期时间,单位分钟
|
ExpireTime uint64 `yaml:"expire-time"` // 过期时间,单位分钟
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *Jwt) Valid() {
|
func (j *Jwt) Default() {
|
||||||
assert.IsTrue(j.ExpireTime != 0, "config.yml之 [jwt.expire-time] 不能为空")
|
if j.Key == "" {
|
||||||
|
// 如果配置文件中的jwt key为空,则随机生成字符串
|
||||||
|
j.Key = stringx.Rand(32)
|
||||||
|
logx.Warnf("未配置jwt.key, 随机生成key为: %s", j.Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if j.ExpireTime == 0 {
|
||||||
|
j.ExpireTime = 1440
|
||||||
|
logx.Warnf("未配置jwt.expire-time, 默认值: %d", j.ExpireTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *Jwt) Valid() {
|
||||||
|
assert.IsTrue(j.ExpireTime != 0, "config.yml之[jwt.expire-time] 不能为空")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,28 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import "path"
|
import (
|
||||||
|
"mayfly-go/pkg/logx"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
type Log struct {
|
type Log struct {
|
||||||
Level string `yaml:"level"`
|
Level string `yaml:"level"`
|
||||||
File *LogFile `yaml:"file"`
|
Type string `yaml:"type"`
|
||||||
|
AddSource bool `yaml:"add-source"`
|
||||||
|
File LogFile `yaml:"file"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Log) Default() {
|
||||||
|
if l.Level == "" {
|
||||||
|
l.Level = "info"
|
||||||
|
logx.Warnf("未配置log.level, 默认值: %s", l.Level)
|
||||||
|
}
|
||||||
|
if l.Type == "" {
|
||||||
|
l.Type = "text"
|
||||||
|
}
|
||||||
|
if l.File.Name == "" {
|
||||||
|
l.File.Name = "mayfly-go.log"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogFile struct {
|
type LogFile struct {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
|
import "mayfly-go/pkg/logx"
|
||||||
|
|
||||||
type Mysql struct {
|
type Mysql struct {
|
||||||
AutoMigration bool `mapstructure:"auto-migration" json:"autoMigration" yaml:"auto-migration"`
|
AutoMigration bool `mapstructure:"auto-migration" json:"autoMigration" yaml:"auto-migration"`
|
||||||
Host string `mapstructure:"path" json:"host" yaml:"host"`
|
Host string `mapstructure:"path" json:"host" yaml:"host"`
|
||||||
@@ -13,6 +15,19 @@ type Mysql struct {
|
|||||||
LogZap string `mapstructure:"log-zap" json:"logZap" yaml:"log-zap"`
|
LogZap string `mapstructure:"log-zap" json:"logZap" yaml:"log-zap"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Mysql) Default() {
|
||||||
|
if m.Host == "" {
|
||||||
|
m.Host = "localhost:3306"
|
||||||
|
logx.Warnf("未配置mysql.host, 默认值: %s", m.Host)
|
||||||
|
}
|
||||||
|
if m.Config == "" {
|
||||||
|
m.Config = "charset=utf8&loc=Local&parseTime=true"
|
||||||
|
}
|
||||||
|
if m.MaxIdleConns == 0 {
|
||||||
|
m.MaxIdleConns = 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Mysql) Dsn() string {
|
func (m *Mysql) Dsn() string {
|
||||||
return m.Username + ":" + m.Password + "@tcp(" + m.Host + ")/" + m.Dbname + "?" + m.Config
|
return m.Username + ":" + m.Password + "@tcp(" + m.Host + ")/" + m.Dbname + "?" + m.Config
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
Port int `yaml:"port"`
|
Port int `yaml:"port"`
|
||||||
@@ -12,6 +14,18 @@ type Server struct {
|
|||||||
MachineRecPath string `yaml:"machine-rec-path"` // 机器终端操作回放文件存储路径
|
MachineRecPath string `yaml:"machine-rec-path"` // 机器终端操作回放文件存储路径
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) Default() {
|
||||||
|
if s.Model == "" {
|
||||||
|
s.Model = "release"
|
||||||
|
}
|
||||||
|
if s.Port == 0 {
|
||||||
|
s.Port = 8888
|
||||||
|
}
|
||||||
|
if s.MachineRecPath == "" {
|
||||||
|
s.MachineRecPath = "./rec"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) GetPort() string {
|
func (s *Server) GetPort() string {
|
||||||
return fmt.Sprintf(":%d", s.Port)
|
return fmt.Sprintf(":%d", s.Port)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ package ginx
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"mayfly-go/pkg/biz"
|
"mayfly-go/pkg/biz"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"mayfly-go/pkg/model"
|
"mayfly-go/pkg/model"
|
||||||
"mayfly-go/pkg/utils/structx"
|
"mayfly-go/pkg/utils/structx"
|
||||||
"mayfly-go/pkg/validatorx"
|
"mayfly-go/pkg/validatorx"
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime/debug"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -105,12 +104,10 @@ func ErrorRes(g *gin.Context, err any) {
|
|||||||
g.JSON(http.StatusOK, model.Error(t))
|
g.JSON(http.StatusOK, model.Error(t))
|
||||||
case error:
|
case error:
|
||||||
g.JSON(http.StatusOK, model.ServerError())
|
g.JSON(http.StatusOK, model.ServerError())
|
||||||
global.Log.Errorf("%s\n%s", t.Error(), string(debug.Stack()))
|
|
||||||
case string:
|
case string:
|
||||||
g.JSON(http.StatusOK, model.ServerError())
|
g.JSON(http.StatusOK, model.ServerError())
|
||||||
global.Log.Errorf("%s\n%s", t, string(debug.Stack()))
|
|
||||||
default:
|
default:
|
||||||
global.Log.Error(t)
|
logx.Error("未知错误", "errInfo", t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
package global
|
package global
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Log *logrus.Logger // 日志
|
Db *gorm.DB // gorm
|
||||||
Db *gorm.DB // gorm
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
package logger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"mayfly-go/pkg/config"
|
|
||||||
"mayfly-go/pkg/global"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Init() {
|
|
||||||
logger := logrus.New()
|
|
||||||
logger.SetFormatter(new(LogFormatter))
|
|
||||||
logger.SetReportCaller(true)
|
|
||||||
|
|
||||||
logConf := config.Conf.Log
|
|
||||||
// 如果不存在日志配置信息,则默认debug级别
|
|
||||||
if logConf == nil {
|
|
||||||
logger.SetLevel(logrus.DebugLevel)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据配置文件设置日志级别
|
|
||||||
if level := logConf.Level; level != "" {
|
|
||||||
l, err := logrus.ParseLevel(level)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("日志级别不存在: %s", level))
|
|
||||||
}
|
|
||||||
logger.SetLevel(l)
|
|
||||||
} else {
|
|
||||||
logger.SetLevel(logrus.DebugLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
if logFile := logConf.File; logFile != nil {
|
|
||||||
//写入文件
|
|
||||||
file, err := os.OpenFile(logFile.GetFilename(), os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModeAppend|0666)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("创建日志文件失败: %s", err.Error()))
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Out = file
|
|
||||||
}
|
|
||||||
|
|
||||||
global.Log = logger
|
|
||||||
}
|
|
||||||
|
|
||||||
type LogFormatter struct{}
|
|
||||||
|
|
||||||
func (l *LogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
|
||||||
timestamp := time.Now().Local().Format("2006-01-02 15:04:05.000")
|
|
||||||
level := entry.Level
|
|
||||||
logMsg := fmt.Sprintf("%s [%s]", timestamp, strings.ToUpper(level.String()))
|
|
||||||
// 如果存在调用信息,记录方法信息及行号
|
|
||||||
if caller := entry.Caller; caller != nil {
|
|
||||||
logMsg = logMsg + fmt.Sprintf(" [%s:%d]", caller.Function, caller.Line)
|
|
||||||
}
|
|
||||||
for k, v := range entry.Data {
|
|
||||||
logMsg = logMsg + fmt.Sprintf(" [%s=%v]", k, v)
|
|
||||||
}
|
|
||||||
logMsg = logMsg + fmt.Sprintf(" : %s\n", entry.Message)
|
|
||||||
return []byte(logMsg), nil
|
|
||||||
}
|
|
||||||
16
server/pkg/logx/color.go
Normal file
16
server/pkg/logx/color.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package logx
|
||||||
|
|
||||||
|
const (
|
||||||
|
Reset = "\033[0m"
|
||||||
|
Red = "\033[31m"
|
||||||
|
Green = "\033[32m"
|
||||||
|
Yellow = "\033[33m"
|
||||||
|
Blue = "\033[34m"
|
||||||
|
Magenta = "\033[35m"
|
||||||
|
Cyan = "\033[36m"
|
||||||
|
White = "\033[37m"
|
||||||
|
BlueBold = "\033[34;1m"
|
||||||
|
MagentaBold = "\033[35;1m"
|
||||||
|
RedBold = "\033[31;1m"
|
||||||
|
YellowBold = "\033[33;1m"
|
||||||
|
)
|
||||||
63
server/pkg/logx/config.go
Normal file
63
server/pkg/logx/config.go
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package logx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Level string
|
||||||
|
Type string // 日志类型;text、json
|
||||||
|
AddSource bool // 是否记录调用方法
|
||||||
|
Filename string
|
||||||
|
Filepath string
|
||||||
|
|
||||||
|
writer io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取日志输出源
|
||||||
|
func (c *Config) GetLogOut() io.Writer {
|
||||||
|
if c.writer != nil {
|
||||||
|
return c.writer
|
||||||
|
}
|
||||||
|
writer := os.Stdout
|
||||||
|
// 根据配置文件设置日志级别
|
||||||
|
if c.Filepath != "" && c.Filename != "" {
|
||||||
|
// 写入文件
|
||||||
|
file, err := os.OpenFile(path.Join(c.Filepath, c.Filename), os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModeAppend|0666)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("创建日志文件失败: %s", err.Error()))
|
||||||
|
}
|
||||||
|
writer = file
|
||||||
|
}
|
||||||
|
|
||||||
|
c.writer = writer
|
||||||
|
return writer
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取日志级别
|
||||||
|
func (c *Config) GetLevel() slog.Level {
|
||||||
|
switch strings.ToLower(c.Level) {
|
||||||
|
case "error":
|
||||||
|
return slog.LevelDebug
|
||||||
|
case "warn", "warning":
|
||||||
|
return slog.LevelWarn
|
||||||
|
case "info":
|
||||||
|
return slog.LevelInfo
|
||||||
|
case "debug":
|
||||||
|
return slog.LevelDebug
|
||||||
|
}
|
||||||
|
return slog.LevelInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) IsJsonType() bool {
|
||||||
|
return c.Type == "json"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) IsDebug() bool {
|
||||||
|
return strings.ToLower(c.Level) == "debug"
|
||||||
|
}
|
||||||
22
server/pkg/logx/json_handler.go
Normal file
22
server/pkg/logx/json_handler.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package logx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewJsonHandler(config *Config) *slog.JSONHandler {
|
||||||
|
replace := func(groups []string, a slog.Attr) slog.Attr {
|
||||||
|
// 格式化时间.
|
||||||
|
if a.Key == slog.TimeKey && len(groups) == 0 {
|
||||||
|
return slog.Attr{Key: "time", Value: slog.StringValue(time.Now().Local().Format("2006-01-02 15:04:05.000"))}
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
return slog.NewJSONHandler(config.GetLogOut(), &slog.HandlerOptions{
|
||||||
|
Level: config.GetLevel(),
|
||||||
|
AddSource: false, // 统一由添加公共commonAttrs时判断添加
|
||||||
|
ReplaceAttr: replace,
|
||||||
|
})
|
||||||
|
}
|
||||||
174
server/pkg/logx/logx.go
Normal file
174
server/pkg/logx/logx.go
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
package logx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"mayfly-go/pkg/utils/runtimex"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
config *Config
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetConfig() *Config {
|
||||||
|
if config == nil {
|
||||||
|
return &Config{
|
||||||
|
Level: "info",
|
||||||
|
Type: "text",
|
||||||
|
AddSource: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
func Init(logConf Config) {
|
||||||
|
config = &logConf
|
||||||
|
var handler slog.Handler
|
||||||
|
if logConf.Type == "text" {
|
||||||
|
handler = NewTextHandler(config)
|
||||||
|
} else {
|
||||||
|
handler = NewJsonHandler(config)
|
||||||
|
}
|
||||||
|
slog.SetDefault(slog.New(handler))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Print(msg string, args ...any) {
|
||||||
|
Log(context.Background(), slog.LevelInfo, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Debug(msg string, args ...any) {
|
||||||
|
Log(context.Background(), slog.LevelDebug, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Debugf(format string, args ...any) {
|
||||||
|
Log(context.Background(), slog.LevelDebug, fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func DebugWithFields(msg string, mapFields map[string]any) {
|
||||||
|
Log(context.Background(), slog.LevelDebug, msg, map2Attrs(mapFields)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// debug记录,并将堆栈信息添加至msg里,默认记录10个堆栈信息
|
||||||
|
func DebugTrace(msg string, err error) {
|
||||||
|
Log(context.Background(), slog.LevelDebug, fmt.Sprintf(msg+"%s\n%s", err.Error(), runtimex.StatckStr(2, 10)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Info(msg string, args ...any) {
|
||||||
|
Log(context.Background(), slog.LevelInfo, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func InfoContext(ctx context.Context, msg string, args ...any) {
|
||||||
|
Log(ctx, slog.LevelInfo, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Infof(format string, args ...any) {
|
||||||
|
Log(context.Background(), slog.LevelInfo, fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func InfoWithFields(msg string, mapFields map[string]any) {
|
||||||
|
Log(context.Background(), slog.LevelInfo, msg, map2Attrs(mapFields)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Warn(msg string, args ...any) {
|
||||||
|
Log(context.Background(), slog.LevelWarn, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Warnf(format string, args ...any) {
|
||||||
|
Log(context.Background(), slog.LevelWarn, fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func WarnWithFields(msg string, mapFields map[string]any) {
|
||||||
|
Log(context.Background(), slog.LevelWarn, msg, map2Attrs(mapFields)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Error(msg string, args ...any) {
|
||||||
|
Log(context.Background(), slog.LevelError, msg, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Errorf(format string, args ...any) {
|
||||||
|
Log(context.Background(), slog.LevelError, fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 错误记录,并将堆栈信息添加至msg里,默认记录10个堆栈信息
|
||||||
|
func ErrorTrace(msg string, err error) {
|
||||||
|
Log(context.Background(), slog.LevelError, fmt.Sprintf(msg+"%s\n%s", err.Error(), runtimex.StatckStr(2, 10)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrorWithFields(msg string, mapFields map[string]any) {
|
||||||
|
Log(context.Background(), slog.LevelError, msg, map2Attrs(mapFields)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Panic(msg string, args ...any) {
|
||||||
|
Log(context.Background(), slog.LevelError, msg, args...)
|
||||||
|
panic(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Panicf(format string, args ...any) {
|
||||||
|
msg := fmt.Sprintf(format, args...)
|
||||||
|
Log(context.Background(), slog.LevelError, fmt.Sprintf(format, args...))
|
||||||
|
panic(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Log(ctx context.Context, level slog.Level, msg string, args ...any) {
|
||||||
|
slog.Log(ctx, level, msg, appendCommonAttr(ctx, level, args)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取日志公共属性
|
||||||
|
func getCommonAttr(ctx context.Context, level slog.Level) []any {
|
||||||
|
commonAttrs := make([]any, 0)
|
||||||
|
|
||||||
|
// 如果系统配置添加方法信息或者为错误级别时则 记录方法信息及行号
|
||||||
|
if config.AddSource || level == slog.LevelError {
|
||||||
|
// skip [runtime.Callers, getCommonAttr, appendCommonAttr, logx.Log, logx.Info|Debug|Warn|Error..]
|
||||||
|
var pcs [1]uintptr
|
||||||
|
runtime.Callers(5, pcs[:])
|
||||||
|
fs := runtime.CallersFrames(pcs[:])
|
||||||
|
f, _ := fs.Next()
|
||||||
|
|
||||||
|
source := &Source{
|
||||||
|
Function: f.Function,
|
||||||
|
Fileline: fmt.Sprintf("%s:%d", runtimex.ParseFrameFile(f.File), f.Line),
|
||||||
|
}
|
||||||
|
commonAttrs = append(commonAttrs, slog.SourceKey, source)
|
||||||
|
}
|
||||||
|
|
||||||
|
return commonAttrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendCommonAttr(ctx context.Context, level slog.Level, args []any) []any {
|
||||||
|
commonAttrs := getCommonAttr(ctx, level)
|
||||||
|
if len(commonAttrs) > 0 {
|
||||||
|
args = append(commonAttrs, args...)
|
||||||
|
}
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
// map类型转为attr
|
||||||
|
func map2Attrs(mapArg map[string]any) []any {
|
||||||
|
atts := make([]any, 0)
|
||||||
|
for k, v := range mapArg {
|
||||||
|
atts = append(atts, slog.Any(k, v))
|
||||||
|
}
|
||||||
|
return atts
|
||||||
|
}
|
||||||
|
|
||||||
|
type Source struct {
|
||||||
|
// Function is the package path-qualified function name containing the
|
||||||
|
// source line. If non-empty, this string uniquely identifies a single
|
||||||
|
// function in the program. This may be the empty string if not known.
|
||||||
|
Function string `json:"function"`
|
||||||
|
// File and Line are the file name and line number (1-based) of the source
|
||||||
|
// line. These may be the empty string and zero, respectively, if not known.
|
||||||
|
Fileline string `json:"fileline"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Source) String() string {
|
||||||
|
// 查找最后一个/的位置, 如mayfly-go/pkg/starter.runWebServer
|
||||||
|
lastIndex := strings.LastIndex(s.Function, "/")
|
||||||
|
// 获取最后一段,即starter.runWebServer
|
||||||
|
funcName := s.Function[lastIndex+1:]
|
||||||
|
return fmt.Sprintf("%s#%s", s.Fileline, funcName)
|
||||||
|
}
|
||||||
54
server/pkg/logx/text_handler.go
Normal file
54
server/pkg/logx/text_handler.go
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package logx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"log/slog"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CustomeTextHandlerOptions struct {
|
||||||
|
SlogOpts slog.HandlerOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
type CustomeTextHandler struct {
|
||||||
|
slog.Handler
|
||||||
|
l *log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *CustomeTextHandler) Handle(ctx context.Context, r slog.Record) error {
|
||||||
|
level := r.Level.String()
|
||||||
|
timeStr := r.Time.Format("2006-01-02 15:04:05.000")
|
||||||
|
|
||||||
|
attrsStr := ""
|
||||||
|
r.Attrs(func(a slog.Attr) bool {
|
||||||
|
// 如果是source,则忽略key,简洁些
|
||||||
|
if a.Key == slog.SourceKey {
|
||||||
|
attrsStr += fmt.Sprintf("[%s]", a.Value.Any())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
attrsStr += fmt.Sprintf("[%s=%v]", a.Key, a.Value.Any())
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
if attrsStr != "" {
|
||||||
|
attrsStr = " " + attrsStr
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式为:time [level] [key=value][key2=value2] : message
|
||||||
|
h.l.Printf("%s [%s]%s : %s", timeStr, level, attrsStr, r.Message)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTextHandler(config *Config) *CustomeTextHandler {
|
||||||
|
opts := CustomeTextHandlerOptions{
|
||||||
|
SlogOpts: slog.HandlerOptions{
|
||||||
|
Level: config.GetLevel(),
|
||||||
|
AddSource: false, // 统一由添加公共commonAttrs时判断添加
|
||||||
|
}}
|
||||||
|
|
||||||
|
out := config.GetLogOut()
|
||||||
|
return &CustomeTextHandler{
|
||||||
|
Handler: slog.NewTextHandler(out, &opts.SlogOpts),
|
||||||
|
l: log.New(out, "", 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ package rediscli
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"mayfly-go/pkg/utils/stringx"
|
"mayfly-go/pkg/utils/stringx"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ func NewLock(key string, expiration time.Duration) *RedisLock {
|
|||||||
func (rl *RedisLock) Lock() bool {
|
func (rl *RedisLock) Lock() bool {
|
||||||
result, err := cli.SetNX(context.Background(), LockKeyPrefix+rl.key, rl.value, rl.expiration).Result()
|
result, err := cli.SetNX(context.Background(), LockKeyPrefix+rl.key, rl.value, rl.expiration).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Log.Errorf("redis lock setNx fail: %s", err.Error())
|
logx.Errorf("redis lock setNx fail: %s", err.Error())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ func (rl *RedisLock) UnLock() bool {
|
|||||||
|
|
||||||
result, err := script.Run(context.Background(), cli, []string{LockKeyPrefix + rl.key}, rl.value).Int64()
|
result, err := script.Run(context.Background(), cli, []string{LockKeyPrefix + rl.key}, rl.value).Int64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Log.Errorf("redis unlock runScript fail: %s", err.Error())
|
logx.Errorf("redis unlock runScript fail: %s", err.Error())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ func (rl *RedisLock) RefreshLock() bool {
|
|||||||
|
|
||||||
result, err := script.Run(context.Background(), cli, []string{LockKeyPrefix + rl.key}, rl.value, rl.expiration/time.Second).Int64()
|
result, err := script.Run(context.Background(), cli, []string{LockKeyPrefix + rl.key}, rl.value, rl.expiration/time.Second).Int64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Log.Errorf("redis refreshLock runScript fail: %s", err.Error())
|
logx.Errorf("redis refreshLock runScript fail: %s", err.Error())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,10 @@ package req
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"mayfly-go/pkg/biz"
|
"mayfly-go/pkg/biz"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"mayfly-go/pkg/utils/anyx"
|
"mayfly-go/pkg/utils/anyx"
|
||||||
|
"mayfly-go/pkg/utils/runtimex"
|
||||||
"mayfly-go/pkg/utils/stringx"
|
"mayfly-go/pkg/utils/stringx"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type SaveLogFunc func(*Ctx)
|
type SaveLogFunc func(*Ctx)
|
||||||
@@ -42,6 +41,8 @@ func (i *LogInfo) WithLogResp() *LogInfo {
|
|||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DefaultLogFrames = 10
|
||||||
|
|
||||||
func LogHandler(rc *Ctx) error {
|
func LogHandler(rc *Ctx) error {
|
||||||
if rc.Conf == nil || rc.Conf.logInfo == nil {
|
if rc.Conf == nil || rc.Conf.logInfo == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -49,24 +50,54 @@ func LogHandler(rc *Ctx) error {
|
|||||||
|
|
||||||
li := rc.Conf.logInfo
|
li := rc.Conf.logInfo
|
||||||
|
|
||||||
lfs := logrus.Fields{}
|
attrMap := make(map[string]any, 0)
|
||||||
if la := rc.LoginAccount; la != nil {
|
|
||||||
lfs["uid"] = la.Id
|
|
||||||
lfs["uname"] = la.Username
|
|
||||||
}
|
|
||||||
|
|
||||||
req := rc.GinCtx.Request
|
req := rc.GinCtx.Request
|
||||||
lfs[req.Method] = req.URL.Path
|
attrMap[req.Method] = req.URL.Path
|
||||||
|
|
||||||
|
if la := rc.LoginAccount; la != nil {
|
||||||
|
attrMap["uid"] = la.Id
|
||||||
|
attrMap["uname"] = la.Username
|
||||||
|
}
|
||||||
|
|
||||||
// 如果需要保存日志,并且保存日志处理函数存在则执行保存日志函数
|
// 如果需要保存日志,并且保存日志处理函数存在则执行保存日志函数
|
||||||
if li.save && saveLog != nil {
|
if li.save && saveLog != nil {
|
||||||
go saveLog(rc)
|
go saveLog(rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logMsg := li.Description
|
||||||
|
|
||||||
|
if logx.GetConfig().IsJsonType() {
|
||||||
|
// json格式日志处理
|
||||||
|
attrMap["req"] = rc.ReqParam
|
||||||
|
if li.LogResp {
|
||||||
|
attrMap["resp"] = rc.ResData
|
||||||
|
}
|
||||||
|
attrMap["exeTime"] = rc.timed
|
||||||
|
|
||||||
|
if rc.Err != nil {
|
||||||
|
nFrames := DefaultLogFrames
|
||||||
|
if _, ok := rc.Err.(biz.BizError); ok {
|
||||||
|
nFrames = nFrames / 2
|
||||||
|
}
|
||||||
|
attrMap["error"] = rc.Err
|
||||||
|
// 跳过log_handler等相关堆栈
|
||||||
|
attrMap["stacktrace"] = runtimex.StatckStr(5, nFrames)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 处理文本格式日志信息
|
||||||
|
if err := rc.Err; err != nil {
|
||||||
|
logMsg = getErrMsg(rc, err)
|
||||||
|
} else {
|
||||||
|
logMsg = getLogMsg(rc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := rc.Err; err != nil {
|
if err := rc.Err; err != nil {
|
||||||
global.Log.WithFields(lfs).Error(getErrMsg(rc, err))
|
logx.ErrorWithFields(logMsg, attrMap)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
global.Log.WithFields(lfs).Info(getLogMsg(rc))
|
logx.InfoWithFields(logMsg, attrMap)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,19 +116,23 @@ func getLogMsg(rc *Ctx) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getErrMsg(rc *Ctx, err any) string {
|
func getErrMsg(rc *Ctx, err any) string {
|
||||||
msg := rc.Conf.logInfo.Description
|
msg := rc.Conf.logInfo.Description + fmt.Sprintf(" ->%dms", rc.timed)
|
||||||
if !anyx.IsBlank(rc.ReqParam) {
|
if !anyx.IsBlank(rc.ReqParam) {
|
||||||
msg = msg + fmt.Sprintf("\n--> %s", stringx.AnyToStr(rc.ReqParam))
|
msg = msg + fmt.Sprintf("\n--> %s", stringx.AnyToStr(rc.ReqParam))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nFrames := DefaultLogFrames
|
||||||
var errMsg string
|
var errMsg string
|
||||||
switch t := err.(type) {
|
switch t := err.(type) {
|
||||||
case biz.BizError:
|
case biz.BizError:
|
||||||
errMsg = fmt.Sprintf("\n<-e errCode: %d, errMsg: %s", t.Code(), t.Error())
|
errMsg = fmt.Sprintf("\n<-e %s", t.String())
|
||||||
|
nFrames = nFrames / 2
|
||||||
case error:
|
case error:
|
||||||
errMsg = fmt.Sprintf("\n<-e errMsg: %s", t.Error())
|
errMsg = fmt.Sprintf("\n<-e errMsg: %s", t.Error())
|
||||||
case string:
|
case string:
|
||||||
errMsg = fmt.Sprintf("\n<-e errMsg: %s", t)
|
errMsg = fmt.Sprintf("\n<-e errMsg: %s", t)
|
||||||
}
|
}
|
||||||
|
// 加上堆栈信息
|
||||||
|
errMsg += fmt.Sprintf("\n<-stacktrace: %s", runtimex.StatckStr(5, nFrames))
|
||||||
return (msg + errMsg)
|
return (msg + errMsg)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ type Ctx struct {
|
|||||||
|
|
||||||
func (rc *Ctx) Handle(handler HandlerFunc) {
|
func (rc *Ctx) Handle(handler HandlerFunc) {
|
||||||
ginCtx := rc.GinCtx
|
ginCtx := rc.GinCtx
|
||||||
|
begin := time.Now()
|
||||||
defer func() {
|
defer func() {
|
||||||
|
rc.timed = time.Since(begin).Milliseconds()
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
rc.Err = err
|
rc.Err = err
|
||||||
ginx.ErrorRes(ginCtx, err)
|
ginx.ErrorRes(ginCtx, err)
|
||||||
@@ -47,7 +49,6 @@ func (rc *Ctx) Handle(handler HandlerFunc) {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
begin := time.Now()
|
|
||||||
handler(rc)
|
handler(rc)
|
||||||
rc.timed = time.Since(begin).Milliseconds()
|
rc.timed = time.Since(begin).Milliseconds()
|
||||||
if rc.Conf == nil || !rc.Conf.noRes {
|
if rc.Conf == nil || !rc.Conf.noRes {
|
||||||
|
|||||||
@@ -5,47 +5,24 @@ import (
|
|||||||
|
|
||||||
"mayfly-go/pkg/biz"
|
"mayfly-go/pkg/biz"
|
||||||
"mayfly-go/pkg/config"
|
"mayfly-go/pkg/config"
|
||||||
"mayfly-go/pkg/global"
|
|
||||||
"mayfly-go/pkg/model"
|
"mayfly-go/pkg/model"
|
||||||
"mayfly-go/pkg/utils/stringx"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 初始化jwt key与expire time等
|
|
||||||
func InitTokenConfig() {
|
|
||||||
if ExpTime == 0 {
|
|
||||||
JwtKey = config.Conf.Jwt.Key
|
|
||||||
ExpTime = config.Conf.Jwt.ExpireTime
|
|
||||||
|
|
||||||
// 如果配置文件中的jwt key为空,则随机生成字符串
|
|
||||||
if JwtKey == "" {
|
|
||||||
JwtKey = stringx.Rand(32)
|
|
||||||
global.Log.Infof("config.yml未配置jwt.key, 随机生成key为: %s", JwtKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
JwtKey string
|
|
||||||
ExpTime uint64
|
|
||||||
)
|
|
||||||
|
|
||||||
// 创建用户token
|
// 创建用户token
|
||||||
func CreateToken(userId uint64, username string) string {
|
func CreateToken(userId uint64, username string) string {
|
||||||
InitTokenConfig()
|
|
||||||
|
|
||||||
// 带权限创建令牌
|
// 带权限创建令牌
|
||||||
// 设置有效期,过期需要重新登录获取token
|
// 设置有效期,过期需要重新登录获取token
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||||
"id": userId,
|
"id": userId,
|
||||||
"username": username,
|
"username": username,
|
||||||
"exp": time.Now().Add(time.Minute * time.Duration(ExpTime)).Unix(),
|
"exp": time.Now().Add(time.Minute * time.Duration(config.Conf.Jwt.ExpireTime)).Unix(),
|
||||||
})
|
})
|
||||||
|
|
||||||
// 使用自定义字符串加密 and get the complete encoded token as a string
|
// 使用自定义字符串加密 and get the complete encoded token as a string
|
||||||
tokenString, err := token.SignedString([]byte(JwtKey))
|
tokenString, err := token.SignedString([]byte(config.Conf.Jwt.Key))
|
||||||
biz.ErrIsNilAppendErr(err, "token创建失败: %s")
|
biz.ErrIsNilAppendErr(err, "token创建失败: %s")
|
||||||
return tokenString
|
return tokenString
|
||||||
}
|
}
|
||||||
@@ -55,11 +32,10 @@ func ParseToken(tokenStr string) (*model.LoginAccount, error) {
|
|||||||
if tokenStr == "" {
|
if tokenStr == "" {
|
||||||
return nil, errors.New("token error")
|
return nil, errors.New("token error")
|
||||||
}
|
}
|
||||||
InitTokenConfig()
|
|
||||||
|
|
||||||
// Parse token
|
// Parse token
|
||||||
token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (any, error) {
|
token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (any, error) {
|
||||||
return []byte(JwtKey), nil
|
return []byte(config.Conf.Jwt.Key), nil
|
||||||
})
|
})
|
||||||
if err != nil || token == nil {
|
if err != nil || token == nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package scheduler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"mayfly-go/pkg/biz"
|
"mayfly-go/pkg/biz"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
@@ -32,7 +32,7 @@ func Remove(id cron.EntryID) {
|
|||||||
|
|
||||||
// 根据任务key移除
|
// 根据任务key移除
|
||||||
func RemoveByKey(key string) {
|
func RemoveByKey(key string) {
|
||||||
global.Log.Debugf("移除cron任务 => [key = %s]", key)
|
logx.Debugf("移除cron任务 => [key = %s]", key)
|
||||||
id, ok := key2IdMap.Load(key)
|
id, ok := key2IdMap.Load(key)
|
||||||
if ok {
|
if ok {
|
||||||
Remove(id.(cron.EntryID))
|
Remove(id.(cron.EntryID))
|
||||||
@@ -53,7 +53,7 @@ func AddFun(spec string, cmd func()) cron.EntryID {
|
|||||||
|
|
||||||
// 根据key添加定时任务
|
// 根据key添加定时任务
|
||||||
func AddFunByKey(key, spec string, cmd func()) {
|
func AddFunByKey(key, spec string, cmd func()) {
|
||||||
global.Log.Debugf("添加cron任务 => [key = %s]", key)
|
logx.Debugf("添加cron任务 => [key = %s]", key)
|
||||||
RemoveByKey(key)
|
RemoveByKey(key)
|
||||||
key2IdMap.Store(key, AddFun(spec, cmd))
|
key2IdMap.Store(key, AddFun(spec, cmd))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,15 +3,18 @@ package starter
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"mayfly-go/pkg/config"
|
"mayfly-go/pkg/config"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
|
"os"
|
||||||
|
"runtime/debug"
|
||||||
)
|
)
|
||||||
|
|
||||||
func printBanner() {
|
func printBanner() {
|
||||||
global.Log.Print(fmt.Sprintf(`
|
buildInfo, _ := debug.ReadBuildInfo()
|
||||||
|
logx.Print(fmt.Sprintf(`
|
||||||
__ _
|
__ _
|
||||||
_ __ ___ __ _ _ _ / _| |_ _ __ _ ___
|
_ __ ___ __ _ _ _ / _| |_ _ __ _ ___
|
||||||
| '_ ' _ \ / _' | | | | |_| | | | |_____ / _' |/ _ \
|
| '_ ' _ \ / _' | | | | |_| | | | |_____ / _' |/ _ \
|
||||||
| | | | | | (_| | |_| | _| | |_| |_____| (_| | (_) | version: %s
|
| | | | | | (_| | |_| | _| | |_| |_____| (_| | (_) | version: %s | go_version: %s | pid: %d
|
||||||
|_| |_| |_|\__,_|\__, |_| |_|\__, | \__, |\___/
|
|_| |_| |_|\__,_|\__, |_| |_|\__, | \__, |\___/
|
||||||
|___/ |___/ |___/ `, config.Version))
|
|___/ |___/ |___/ `, config.Version, buildInfo.GoVersion, os.Getpid()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"mayfly-go/pkg/config"
|
"mayfly-go/pkg/config"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/global"
|
||||||
"os"
|
"mayfly-go/pkg/logx"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gorm.io/driver/mysql"
|
"gorm.io/driver/mysql"
|
||||||
@@ -19,11 +19,11 @@ func initDb() {
|
|||||||
|
|
||||||
func gormMysql() *gorm.DB {
|
func gormMysql() *gorm.DB {
|
||||||
m := config.Conf.Mysql
|
m := config.Conf.Mysql
|
||||||
if m == nil || m.Dbname == "" {
|
if m.Dbname == "" {
|
||||||
global.Log.Panic("未找到数据库配置信息")
|
logx.Panic("未找到数据库配置信息")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
global.Log.Infof("连接mysql [%s]", m.Host)
|
logx.Infof("连接mysql [%s]", m.Host)
|
||||||
mysqlConfig := mysql.Config{
|
mysqlConfig := mysql.Config{
|
||||||
DSN: m.Dsn(), // DSN data source name
|
DSN: m.Dsn(), // DSN data source name
|
||||||
DefaultStringSize: 191, // string 类型字段的默认长度
|
DefaultStringSize: 191, // string 类型字段的默认长度
|
||||||
@@ -34,18 +34,19 @@ func gormMysql() *gorm.DB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sqlLogLevel := logger.Error
|
sqlLogLevel := logger.Error
|
||||||
logConf := config.Conf.Log
|
logConf := logx.GetConfig()
|
||||||
// 如果为配置文件中配置的系统日志级别为debug,则打印gorm执行的sql信息
|
// 如果为配置文件中配置的系统日志级别为debug,则打印gorm执行的sql信息
|
||||||
if logConf.Level == "debug" {
|
if logConf.IsDebug() {
|
||||||
sqlLogLevel = logger.Info
|
sqlLogLevel = logger.Info
|
||||||
}
|
}
|
||||||
|
|
||||||
gormLogger := logger.New(
|
gormLogger := logger.New(
|
||||||
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
|
log.New(logConf.GetLogOut(), "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
|
||||||
logger.Config{
|
logger.Config{
|
||||||
SlowThreshold: time.Second, // 慢 SQL 阈值
|
SlowThreshold: time.Second, // 慢 SQL 阈值
|
||||||
LogLevel: sqlLogLevel, // 日志级别, 改为logger.Info即可显示sql语句
|
LogLevel: sqlLogLevel, // 日志级别, 改为logger.Info即可显示sql语句
|
||||||
IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误
|
IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误
|
||||||
Colorful: true, // 禁用彩色打印
|
Colorful: false, // 禁用彩色打印
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -55,7 +56,7 @@ func gormMysql() *gorm.DB {
|
|||||||
}, Logger: gormLogger}
|
}, Logger: gormLogger}
|
||||||
|
|
||||||
if db, err := gorm.Open(mysql.New(mysqlConfig), ormConfig); err != nil {
|
if db, err := gorm.Open(mysql.New(mysqlConfig), ormConfig); err != nil {
|
||||||
global.Log.Panicf("连接mysql失败! [%s]", err.Error())
|
logx.Panicf("连接mysql失败! [%s]", err.Error())
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
sqlDB, _ := db.DB()
|
sqlDB, _ := db.DB()
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"mayfly-go/pkg/config"
|
"mayfly-go/pkg/config"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"mayfly-go/pkg/rediscli"
|
"mayfly-go/pkg/rediscli"
|
||||||
|
|
||||||
"github.com/redis/go-redis/v9"
|
"github.com/redis/go-redis/v9"
|
||||||
@@ -17,11 +17,11 @@ func initRedis() {
|
|||||||
func connRedis() *redis.Client {
|
func connRedis() *redis.Client {
|
||||||
// 设置redis客户端
|
// 设置redis客户端
|
||||||
redisConf := config.Conf.Redis
|
redisConf := config.Conf.Redis
|
||||||
if redisConf == nil {
|
if redisConf.Host == "" {
|
||||||
// global.Log.Panic("未找到redis配置信息")
|
// logx.Panic("未找到redis配置信息")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
global.Log.Infof("连接redis [%s:%d]", redisConf.Host, redisConf.Port)
|
logx.Infof("连接redis [%s:%d]", redisConf.Host, redisConf.Port)
|
||||||
rdb := redis.NewClient(&redis.Options{
|
rdb := redis.NewClient(&redis.Options{
|
||||||
Addr: fmt.Sprintf("%s:%d", redisConf.Host, redisConf.Port),
|
Addr: fmt.Sprintf("%s:%d", redisConf.Host, redisConf.Port),
|
||||||
Password: redisConf.Password, // no password set
|
Password: redisConf.Password, // no password set
|
||||||
@@ -30,7 +30,7 @@ func connRedis() *redis.Client {
|
|||||||
// 测试连接
|
// 测试连接
|
||||||
_, e := rdb.Ping(context.TODO()).Result()
|
_, e := rdb.Ping(context.TODO()).Result()
|
||||||
if e != nil {
|
if e != nil {
|
||||||
global.Log.Panic(fmt.Sprintf("连接redis失败! [%s:%d][%s]", redisConf.Host, redisConf.Port, e.Error()))
|
logx.Panicf("连接redis失败! [%s:%d][%s]", redisConf.Host, redisConf.Port, e.Error())
|
||||||
}
|
}
|
||||||
return rdb
|
return rdb
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,17 +5,14 @@ import (
|
|||||||
"mayfly-go/migrations"
|
"mayfly-go/migrations"
|
||||||
"mayfly-go/pkg/config"
|
"mayfly-go/pkg/config"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/global"
|
||||||
"mayfly-go/pkg/logger"
|
"mayfly-go/pkg/logx"
|
||||||
"mayfly-go/pkg/validatorx"
|
"mayfly-go/pkg/validatorx"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RunWebServer() {
|
func RunWebServer() {
|
||||||
// 初始化config.yml配置文件映射信息
|
// 初始化config.yml配置文件映射信息或使用环境变量。并初始化系统日志相关配置
|
||||||
config.Init()
|
config.Init()
|
||||||
|
|
||||||
// 初始化日志配置信息
|
|
||||||
logger.Init()
|
|
||||||
|
|
||||||
// 打印banner
|
// 打印banner
|
||||||
printBanner()
|
printBanner()
|
||||||
|
|
||||||
@@ -27,7 +24,7 @@ func RunWebServer() {
|
|||||||
|
|
||||||
// 数据库升级操作
|
// 数据库升级操作
|
||||||
if err := migrations.RunMigrations(global.Db); err != nil {
|
if err := migrations.RunMigrations(global.Db); err != nil {
|
||||||
global.Log.Fatalf("数据库升级失败: %v", err)
|
logx.Panicf("数据库升级失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 参数校验器初始化、如错误提示中文转译等
|
// 参数校验器初始化、如错误提示中文转译等
|
||||||
|
|||||||
@@ -4,11 +4,18 @@ import (
|
|||||||
"mayfly-go/initialize"
|
"mayfly-go/initialize"
|
||||||
"mayfly-go/pkg/biz"
|
"mayfly-go/pkg/biz"
|
||||||
"mayfly-go/pkg/config"
|
"mayfly-go/pkg/config"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"mayfly-go/pkg/req"
|
"mayfly-go/pkg/req"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func runWebServer() {
|
func runWebServer() {
|
||||||
|
// 设置gin日志输出器
|
||||||
|
logOut := logx.GetConfig().GetLogOut()
|
||||||
|
gin.DefaultErrorWriter = logOut
|
||||||
|
gin.DefaultWriter = logOut
|
||||||
|
|
||||||
// 权限处理器
|
// 权限处理器
|
||||||
req.UseBeforeHandlerInterceptor(req.PermissionHandler)
|
req.UseBeforeHandlerInterceptor(req.PermissionHandler)
|
||||||
// 日志处理器
|
// 日志处理器
|
||||||
@@ -21,7 +28,7 @@ func runWebServer() {
|
|||||||
|
|
||||||
server := config.Conf.Server
|
server := config.Conf.Server
|
||||||
port := server.GetPort()
|
port := server.GetPort()
|
||||||
global.Log.Infof("Listening and serving HTTP on %s", port)
|
logx.Infof("Listening and serving HTTP on %s", port)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if server.Tls != nil && server.Tls.Enable {
|
if server.Tls != nil && server.Tls.Enable {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package jsonx
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/buger/jsonparser"
|
"github.com/buger/jsonparser"
|
||||||
@@ -18,7 +18,7 @@ func ToMapByBytes(bytes []byte) map[string]any {
|
|||||||
var res map[string]any
|
var res map[string]any
|
||||||
err := json.Unmarshal(bytes, &res)
|
err := json.Unmarshal(bytes, &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Log.Errorf("json字符串转map失败: %s", err.Error())
|
logx.Errorf("json字符串转map失败: %s", err.Error())
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
@@ -26,7 +26,7 @@ func ToMapByBytes(bytes []byte) map[string]any {
|
|||||||
// 转换为json字符串
|
// 转换为json字符串
|
||||||
func ToStr(val any) string {
|
func ToStr(val any) string {
|
||||||
if strBytes, err := json.Marshal(val); err != nil {
|
if strBytes, err := json.Marshal(val); err != nil {
|
||||||
global.Log.Error("toJsonStr error: ", err)
|
logx.ErrorTrace("toJsonStr error: ", err)
|
||||||
return ""
|
return ""
|
||||||
} else {
|
} else {
|
||||||
return string(strBytes)
|
return string(strBytes)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package netx
|
package netx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/lionsoul2014/ip2region/binding/golang/xdb"
|
"github.com/lionsoul2014/ip2region/binding/golang/xdb"
|
||||||
@@ -43,7 +43,7 @@ func Ip2Region(ip string) string {
|
|||||||
vIndex, err := xdb.LoadVectorIndexFromFile(ip2RegionDbPath)
|
vIndex, err := xdb.LoadVectorIndexFromFile(ip2RegionDbPath)
|
||||||
// 第一次加载失败,则默认调整为不使用ip2Region
|
// 第一次加载失败,则默认调整为不使用ip2Region
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Log.Errorf("failed to load ip2region vector index from `%s`: %s\n", ip2RegionDbPath, err)
|
logx.Errorf("failed to load ip2region vector index from `%s`: %s\n", ip2RegionDbPath, err)
|
||||||
useIp2Region = false
|
useIp2Region = false
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,7 @@ func Ip2Region(ip string) string {
|
|||||||
// 2、用全局的 vIndex 创建带 VectorIndex 缓存的查询对象。
|
// 2、用全局的 vIndex 创建带 VectorIndex 缓存的查询对象。
|
||||||
searcher, err := xdb.NewWithVectorIndex(ip2RegionDbPath, vectorIndex)
|
searcher, err := xdb.NewWithVectorIndex(ip2RegionDbPath, vectorIndex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Log.Errorf("failed to create searcher with vector index: %s\n", err)
|
logx.Errorf("failed to create searcher with vector index: %s\n", err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ func Ip2Region(ip string) string {
|
|||||||
// do the search
|
// do the search
|
||||||
region, err := searcher.SearchByStr(ip)
|
region, err := searcher.SearchByStr(ip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Log.Warnf("failed to SearchIP(%s): %s\n", ip, err)
|
logx.Warnf("failed to SearchIP(%s): %s\n", ip, err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return region
|
return region
|
||||||
|
|||||||
44
server/pkg/utils/runtimex/runtimex.go
Normal file
44
server/pkg/utils/runtimex/runtimex.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package runtimex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 获取指定堆栈描述信息
|
||||||
|
//
|
||||||
|
// @param skip: 跳过堆栈个数
|
||||||
|
// @param nFrames: 需要描述的堆栈个数
|
||||||
|
func StatckStr(skip, nFrames int) string {
|
||||||
|
pcs := make([]uintptr, nFrames+1)
|
||||||
|
n := runtime.Callers(skip+1, pcs)
|
||||||
|
if n == 0 {
|
||||||
|
return "(no stack)"
|
||||||
|
}
|
||||||
|
frames := runtime.CallersFrames(pcs[:n])
|
||||||
|
var b strings.Builder
|
||||||
|
i := 0
|
||||||
|
for {
|
||||||
|
frame, more := frames.Next()
|
||||||
|
fmt.Fprintf(&b, "called from %s (%s:%d)\n\t", frame.Function, ParseFrameFile(frame.File), frame.Line)
|
||||||
|
if !more {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
if i >= nFrames {
|
||||||
|
fmt.Fprintf(&b, "(rest of stack elided...)\n")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理栈帧文件名
|
||||||
|
func ParseFrameFile(frameFile string) string {
|
||||||
|
// 尝试将完整路径如/usr/local/.../mayfly-go/server/pkg/starter/web-server.go切割为pkg/starter/web-server.go
|
||||||
|
if ss := strings.Split(frameFile, "mayfly-go/server/"); len(ss) > 1 {
|
||||||
|
return ss[1]
|
||||||
|
}
|
||||||
|
return frameFile
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package validatorx
|
package validatorx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
@@ -33,7 +33,7 @@ func RegisterPattern(patternName string, regexpStr string, errMsg string) {
|
|||||||
func patternValidFunc(f validator.FieldLevel) bool {
|
func patternValidFunc(f validator.FieldLevel) bool {
|
||||||
reg := regexpMap[f.Param()]
|
reg := regexpMap[f.Param()]
|
||||||
if reg == nil {
|
if reg == nil {
|
||||||
global.Log.Warnf("%s的正则校验规则不存在!", f.Param())
|
logx.Warnf("%s的正则校验规则不存在!", f.Param())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package ws
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"mayfly-go/pkg/global"
|
"mayfly-go/pkg/logx"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ func checkConn() {
|
|||||||
|
|
||||||
// 删除ws连接
|
// 删除ws连接
|
||||||
func Delete(userid uint64) {
|
func Delete(userid uint64) {
|
||||||
global.Log.Debug("移除websocket连接:uid = ", userid)
|
logx.Debugf("移除websocket连接: uid = %d", userid)
|
||||||
conn := conns[userid]
|
conn := conns[userid]
|
||||||
if conn != nil {
|
if conn != nil {
|
||||||
conn.Close()
|
conn.Close()
|
||||||
|
|||||||
Reference in New Issue
Block a user