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
|
||||
# db: 0
|
||||
log:
|
||||
# 日志等级, trace, debug, info, warn, error, fatal
|
||||
# 日志等级, debug, info, warn, error
|
||||
level: info
|
||||
# 日志格式类型, text/json
|
||||
type: text
|
||||
# 是否记录方法调用栈信息
|
||||
add-source: false
|
||||
# file:
|
||||
# path: ./
|
||||
# name: mayfly-go.log
|
||||
@@ -21,7 +21,6 @@ require (
|
||||
github.com/pquerna/otp v1.4.0
|
||||
github.com/redis/go-redis/v9 v9.1.0
|
||||
github.com/robfig/cron/v3 v3.0.1 // 定时任务
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2
|
||||
go.mongodb.org/mongo-driver v1.12.1 // mongo
|
||||
golang.org/x/crypto v0.12.0 // ssh
|
||||
|
||||
@@ -32,7 +32,7 @@ func PwdAesEncrypt(password string) string {
|
||||
return ""
|
||||
}
|
||||
aes := config.Conf.Aes
|
||||
if aes == nil {
|
||||
if aes.Key == "" {
|
||||
return password
|
||||
}
|
||||
encryptPwd, err := aes.EncryptBase64([]byte(password))
|
||||
@@ -46,7 +46,7 @@ func PwdAesDecrypt(encryptPwd string) string {
|
||||
return ""
|
||||
}
|
||||
aes := config.Conf.Aes
|
||||
if aes == nil {
|
||||
if aes.Key == "" {
|
||||
return encryptPwd
|
||||
}
|
||||
decryptPwd, err := aes.DecryptBase64(encryptPwd)
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"mayfly-go/internal/machine/infrastructure/machine"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/cache"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"mayfly-go/pkg/utils/structx"
|
||||
@@ -201,7 +201,7 @@ func (da *dbAppImpl) GetDbInstance(id uint64, db string) *DbInstance {
|
||||
DB, err := GetDbConn(d, db)
|
||||
if err != nil {
|
||||
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())))
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ func (da *dbAppImpl) GetDbInstance(id uint64, db string) *DbInstance {
|
||||
DB.SetMaxIdleConns(1)
|
||||
|
||||
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 {
|
||||
dbCache.Put(cacheKey, dbi)
|
||||
}
|
||||
@@ -285,7 +285,7 @@ func (di *DbInstance) GetMeta() DbMetadata {
|
||||
func (d *DbInstance) Close() {
|
||||
if d.db != 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
|
||||
}
|
||||
@@ -297,7 +297,7 @@ func (d *DbInstance) Close() {
|
||||
var dbCache = cache.NewTimedCache(consts.DbConnExpireTime, 5*time.Second).
|
||||
WithUpdateAccessTime(true).
|
||||
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()
|
||||
})
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ func (d *dbSqlExecAppImpl) Exec(execSqlReq *DbSqlExecReq) (*DbSqlExecRes, error)
|
||||
stmt, err := sqlparser.Parse(sql)
|
||||
if err != nil {
|
||||
// 就算解析失败也执行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)
|
||||
isSelect := strings.HasPrefix(lowerSql, "select")
|
||||
if isSelect {
|
||||
|
||||
@@ -3,7 +3,7 @@ package application
|
||||
import (
|
||||
"mayfly-go/internal/machine/domain/entity"
|
||||
"mayfly-go/internal/machine/domain/repository"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/rediscli"
|
||||
"mayfly-go/pkg/scheduler"
|
||||
@@ -154,7 +154,7 @@ func (m *machineCropJobAppImpl) MachineRelateCronJobs(machineId uint64, cronJobs
|
||||
func (m *machineCropJobAppImpl) InitCronJob() {
|
||||
defer func() {
|
||||
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,
|
||||
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 == "" {
|
||||
res = err.Error()
|
||||
}
|
||||
global.Log.Errorf("机器:[%d]执行[%s]计划任务失败: %s", mid, cronJob.Name, res)
|
||||
logx.Errorf("机器:[%d]执行[%s]计划任务失败: %s", mid, cronJob.Name, res)
|
||||
} 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 ||
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"mayfly-go/internal/machine/domain/repository"
|
||||
"mayfly-go/internal/machine/infrastructure/machine"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/gormx"
|
||||
"mayfly-go/pkg/model"
|
||||
"os"
|
||||
"strings"
|
||||
@@ -93,9 +92,9 @@ func (m *machineFileAppImpl) Save(entity *entity.MachineFile) {
|
||||
biz.NotNil(m.machineRepo.GetById(entity.MachineId, "Name"), "该机器不存在")
|
||||
|
||||
if entity.Id != 0 {
|
||||
gormx.UpdateById(entity)
|
||||
m.machineFileRepo.UpdateById(entity)
|
||||
} else {
|
||||
gormx.Insert(entity)
|
||||
m.machineFileRepo.Create(entity)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"mayfly-go/internal/machine/domain/entity"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/cache"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
@@ -72,7 +72,7 @@ func (c *Cli) connect() error {
|
||||
// 关闭client并从缓存中移除,如果使用隧道则也关闭
|
||||
func (c *Cli) Close() {
|
||||
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 {
|
||||
c.client.Close()
|
||||
c.client = nil
|
||||
@@ -173,7 +173,10 @@ func DeleteCli(id uint64) {
|
||||
|
||||
// 从缓存中获取客户端信息,不存在则回调获取机器信息函数,并新建
|
||||
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 {
|
||||
return load.(*Cli), nil
|
||||
}
|
||||
|
||||
me := getMachine(machineId)
|
||||
err := IfUseSshTunnelChangeIpPort(me, getMachine)
|
||||
if err != nil {
|
||||
@@ -185,13 +188,9 @@ func GetCli(machineId uint64, getMachine func(uint64) *Info) (*Cli, error) {
|
||||
return nil, err
|
||||
}
|
||||
c.sshTunnelMachineId = me.SshTunnelMachineId
|
||||
return c, nil
|
||||
})
|
||||
|
||||
if cli != nil {
|
||||
return cli.(*Cli), err
|
||||
}
|
||||
return nil, err
|
||||
cliCache.Put(machineId, c)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// 测试连接,使用传值的方式,而非引用。因为如果使用了ssh隧道,则ip和端口会变为本地映射地址与端口
|
||||
@@ -276,7 +275,7 @@ func newClient(machine *Info) (*Cli, error) {
|
||||
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.machine = machine
|
||||
err := cli.connect()
|
||||
|
||||
@@ -3,7 +3,7 @@ package machine
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/scheduler"
|
||||
"mayfly-go/pkg/utils/netx"
|
||||
"net"
|
||||
@@ -29,7 +29,7 @@ var (
|
||||
type CheckSshTunnelMachineHasUseFunc func(int) bool
|
||||
|
||||
func startCheckUse() {
|
||||
global.Log.Info("开启定时检测ssh隧道机器是否还有被使用")
|
||||
logx.Info("开启定时检测ssh隧道机器是否还有被使用")
|
||||
// 每十分钟检查一次隧道机器是否还有被使用
|
||||
scheduler.AddFun("@every 10m", func() {
|
||||
if !mutex.TryLock() {
|
||||
@@ -38,7 +38,7 @@ func startCheckUse() {
|
||||
defer mutex.Unlock()
|
||||
// 遍历隧道机器,都未被使用将会被关闭
|
||||
for mid, sshTunnelMachine := range sshTunnelMachines {
|
||||
global.Log.Debugf("开始定时检查ssh隧道机器[%d]是否还有被使用...", mid)
|
||||
logx.Debugf("开始定时检查ssh隧道机器[%d]是否还有被使用...", mid)
|
||||
hasUse := false
|
||||
for _, checkUseFunc := range checkSshTunnelMachineHasUseFuncs {
|
||||
// 如果一个在使用则返回不关闭,不继续后续检查
|
||||
@@ -126,10 +126,10 @@ func (stm *SshTunnelMachine) Close() {
|
||||
}
|
||||
|
||||
if stm.SshClient != nil {
|
||||
global.Log.Infof("ssh隧道机器[%d]未被使用, 关闭隧道...", stm.machineId)
|
||||
logx.Infof("ssh隧道机器[%d]未被使用, 关闭隧道...", stm.machineId)
|
||||
err := stm.SshClient.Close()
|
||||
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)
|
||||
@@ -152,7 +152,7 @@ func GetSshTunnelMachine(machineId int, getMachine func(uint64) *Info) (*SshTunn
|
||||
}
|
||||
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
|
||||
|
||||
// 如果实用了隧道机器且还没开始定时检查是否还被实用,则执行定时任务检测隧道是否还被使用
|
||||
@@ -195,31 +195,31 @@ func (r *Tunnel) Open(sshClient *ssh.Client) {
|
||||
localAddr := fmt.Sprintf("%s:%d", r.localHost, r.localPort)
|
||||
|
||||
for {
|
||||
global.Log.Debugf("隧道 %v 等待客户端访问 %v", r.id, localAddr)
|
||||
logx.Debugf("隧道 %v 等待客户端访问 %v", r.id, localAddr)
|
||||
localConn, err := r.listener.Accept()
|
||||
if err != nil {
|
||||
global.Log.Debugf("隧道 %v 接受连接失败 %v, 退出循环", r.id, err.Error())
|
||||
global.Log.Debug("-------------------------------------------------")
|
||||
logx.Debugf("隧道 %v 接受连接失败 %v, 退出循环", r.id, err.Error())
|
||||
logx.Debug("-------------------------------------------------")
|
||||
return
|
||||
}
|
||||
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)
|
||||
global.Log.Debugf("隧道 %v 连接远程地址 %v ...", r.id, remoteAddr)
|
||||
logx.Debugf("隧道 %v 连接远程地址 %v ...", r.id, remoteAddr)
|
||||
remoteConn, err := sshClient.Dial("tcp", remoteAddr)
|
||||
if err != nil {
|
||||
global.Log.Debugf("隧道 %v 连接远程地址 %v, 退出循环", r.id, err.Error())
|
||||
global.Log.Debug("-------------------------------------------------")
|
||||
logx.Debugf("隧道 %v 连接远程地址 %v, 退出循环", r.id, err.Error())
|
||||
logx.Debug("-------------------------------------------------")
|
||||
return
|
||||
}
|
||||
r.remoteConnections = append(r.remoteConnections, remoteConn)
|
||||
|
||||
global.Log.Debugf("隧道 %v 连接远程主机成功", r.id)
|
||||
logx.Debugf("隧道 %v 连接远程主机成功", r.id)
|
||||
go copyConn(localConn, remoteConn)
|
||||
go copyConn(remoteConn, localConn)
|
||||
global.Log.Debugf("隧道 %v 开始转发数据 [%v]->[%v]", r.id, localAddr, remoteAddr)
|
||||
global.Log.Debug("~~~~~~~~~~~~~~~~~~~~分割线~~~~~~~~~~~~~~~~~~~~~~~~")
|
||||
logx.Debugf("隧道 %v 开始转发数据 [%v]->[%v]", r.id, localAddr, remoteAddr)
|
||||
logx.Debug("~~~~~~~~~~~~~~~~~~~~分割线~~~~~~~~~~~~~~~~~~~~~~~~")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ func (r *Tunnel) Close() {
|
||||
}
|
||||
r.remoteConnections = nil
|
||||
_ = r.listener.Close()
|
||||
global.Log.Debugf("隧道 %d 监听器关闭", r.id)
|
||||
logx.Debugf("隧道 %d 监听器关闭", r.id)
|
||||
}
|
||||
|
||||
func copyConn(writer, reader net.Conn) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
@@ -68,12 +68,12 @@ func (r TerminalSession) Start() {
|
||||
}
|
||||
|
||||
func (r TerminalSession) Stop() {
|
||||
global.Log.Debug("close machine ssh terminal session")
|
||||
logx.Debug("close machine ssh terminal session")
|
||||
r.tick.Stop()
|
||||
r.cancel()
|
||||
if r.terminal != 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()
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
global.Log.Error("机器ssh终端读取消息失败: ", err)
|
||||
logx.Error("机器ssh终端读取消息失败: ", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -108,7 +108,7 @@ func (ts TerminalSession) writeToWebsocket() {
|
||||
if len(buf) > 0 {
|
||||
s := string(buf)
|
||||
if err := WriteMessage(ts.wsConn, s); err != nil {
|
||||
global.Log.Error("机器ssh终端发送消息至websocket失败: ", err)
|
||||
logx.Error("机器ssh终端发送消息至websocket失败: ", err)
|
||||
return
|
||||
}
|
||||
// 如果记录器存在,则记录操作回放信息
|
||||
@@ -148,25 +148,25 @@ func (ts *TerminalSession) receiveWsMsg() {
|
||||
// read websocket msg
|
||||
_, wsData, err := wsConn.ReadMessage()
|
||||
if err != nil {
|
||||
global.Log.Debug("机器ssh终端读取websocket消息失败: ", err)
|
||||
logx.Debugf("机器ssh终端读取websocket消息失败: %s", err.Error())
|
||||
return
|
||||
}
|
||||
// 解析消息
|
||||
msgObj := WsMsg{}
|
||||
if err := json.Unmarshal(wsData, &msgObj); err != nil {
|
||||
global.Log.Error("机器ssh终端消息解析失败: ", err)
|
||||
logx.Error("机器ssh终端消息解析失败: ", err)
|
||||
}
|
||||
switch msgObj.Type {
|
||||
case Resize:
|
||||
if msgObj.Cols > 0 && msgObj.Rows > 0 {
|
||||
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:
|
||||
_, err := ts.terminal.Write([]byte(msgObj.Msg))
|
||||
if err != nil {
|
||||
global.Log.Debugf("机器ssh终端写入消息失败: %s", err)
|
||||
logx.Debugf("机器ssh终端写入消息失败: %s", err)
|
||||
}
|
||||
case Ping:
|
||||
_, 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) {
|
||||
gormx.Insert(entity)
|
||||
biz.ErrIsNil(gormx.Insert(entity), "新增机器文件配置失败")
|
||||
}
|
||||
|
||||
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/pkg/biz"
|
||||
"mayfly-go/pkg/cache"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/utils/netx"
|
||||
"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).
|
||||
WithUpdateAccessTime(true).
|
||||
OnEvicted(func(key any, value any) {
|
||||
global.Log.Info("删除mongo连接缓存: id = ", key)
|
||||
logx.Info("删除mongo连接缓存: id = ", key)
|
||||
value.(*MongoInstance).Close()
|
||||
})
|
||||
|
||||
@@ -162,7 +162,7 @@ type MongoInstance struct {
|
||||
func (mi *MongoInstance) Close() {
|
||||
if mi.Cli != 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
|
||||
}
|
||||
@@ -192,7 +192,7 @@ func connect(me *entity.Mongo) (*MongoInstance, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
global.Log.Infof("连接mongo: %s", func(str string) string {
|
||||
logx.Infof("连接mongo: %s", func(str string) string {
|
||||
reg := regexp.MustCompile(`(^mongodb://.+?:)(.+)(@.+$)`)
|
||||
return reg.ReplaceAllString(str, `${1}****${3}`)
|
||||
}(me.Uri))
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"mayfly-go/internal/redis/domain/repository"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/cache"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/utils/netx"
|
||||
"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 {
|
||||
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).
|
||||
WithUpdateAccessTime(true).
|
||||
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()
|
||||
})
|
||||
|
||||
@@ -350,13 +350,13 @@ func (r *RedisInstance) Close() {
|
||||
mode := r.Info.Mode
|
||||
if mode == entity.RedisModeStandalone || mode == entity.RedisModeSentinel {
|
||||
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
|
||||
}
|
||||
if mode == entity.RedisModeCluster {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package api
|
||||
|
||||
import (
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/req"
|
||||
"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)
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
global.Log.Error(err.(error).Error())
|
||||
logx.ErrorTrace("websocket连接失败: ", err.(error))
|
||||
if wsConn != nil {
|
||||
wsConn.WriteMessage(websocket.TextMessage, []byte(err.(error).Error()))
|
||||
wsConn.Close()
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"mayfly-go/internal/sys/domain/repository"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/cache"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/utils/jsonx"
|
||||
"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 {
|
||||
global.Log.Warnf("不存在key = [%s] 的系统配置", key)
|
||||
logx.Warnf("不存在key = [%s] 的系统配置", key)
|
||||
} else {
|
||||
cache.SetStr(SysConfigKeyPrefix+key, jsonx.ToStr(config), -1)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package biz
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/utils/anyx"
|
||||
|
||||
"reflect"
|
||||
@@ -10,13 +10,14 @@ import (
|
||||
|
||||
func ErrIsNil(err error, msg string, params ...any) {
|
||||
if err != nil {
|
||||
global.Log.Error(msg + ": " + err.Error())
|
||||
// logx.ErrorTrace(msg, err)
|
||||
panic(NewBizErr(fmt.Sprintf(msg, params...)))
|
||||
}
|
||||
}
|
||||
|
||||
func ErrIsNilAppendErr(err error, msg string) {
|
||||
if err != nil {
|
||||
// logx.ErrorTrace(msg, err)
|
||||
panic(NewBizErr(fmt.Sprintf(msg, err.Error())))
|
||||
}
|
||||
}
|
||||
@@ -26,7 +27,7 @@ func IsNil(err error) {
|
||||
case *BizError:
|
||||
panic(t)
|
||||
case error:
|
||||
global.Log.Error("非业务异常: " + err.Error())
|
||||
logx.Error("非业务异常: " + err.Error())
|
||||
panic(NewBizErr(fmt.Sprintf("非业务异常: %s", err.Error())))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package biz
|
||||
|
||||
import "fmt"
|
||||
|
||||
// 业务错误
|
||||
type BizError struct {
|
||||
code int16
|
||||
@@ -23,6 +25,10 @@ func (e BizError) Code() int16 {
|
||||
return e.code
|
||||
}
|
||||
|
||||
func (e BizError) String() string {
|
||||
return fmt.Sprintf("errCode: %d, errMsg: %s", e.Code(), e.Error())
|
||||
}
|
||||
|
||||
// 创建业务逻辑错误结构体,默认为业务逻辑错误
|
||||
func NewBizErr(msg string) BizError {
|
||||
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
|
||||
|
||||
import (
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/rediscli"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -33,7 +33,7 @@ func GetInt(key string) int {
|
||||
return 0
|
||||
}
|
||||
if intV, err := strconv.Atoi(val); err != nil {
|
||||
global.Log.Error("获取缓存中的int值转换失败", err)
|
||||
logx.Error("获取缓存中的int值转换失败", err)
|
||||
return 0
|
||||
} else {
|
||||
return intV
|
||||
|
||||
@@ -21,6 +21,9 @@ func (a *Aes) DecryptBase64(data string) ([]byte, error) {
|
||||
}
|
||||
|
||||
func (j *Aes) Valid() {
|
||||
if j.Key == "" {
|
||||
return
|
||||
}
|
||||
aesKeyLen := len(j.Key)
|
||||
assert.IsTrue(aesKeyLen == 16 || aesKeyLen == 24 || aesKeyLen == 32,
|
||||
fmt.Sprintf("config.yml之 [aes.key] 长度需为16、24、32位长度, 当前为%d位", aesKeyLen))
|
||||
|
||||
@@ -3,14 +3,21 @@ package config
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"mayfly-go/pkg/utils/assert"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/utils/ymlx"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type ConfigItem interface {
|
||||
// 验证配置
|
||||
Valid()
|
||||
|
||||
// 如果不存在配置值,则设置默认值
|
||||
Default()
|
||||
}
|
||||
|
||||
// 配置文件映射对象
|
||||
var Conf *Config
|
||||
|
||||
@@ -23,14 +30,14 @@ func Init() {
|
||||
// 读取配置文件信息
|
||||
yc := &Config{}
|
||||
if err := ymlx.LoadYml(startConfigParam.ConfigFilePath, yc); err != nil {
|
||||
slog.Warn(fmt.Sprintf("读取配置文件[%s]失败: %s, 使用系统默认配置或环境变量配置", startConfigParam.ConfigFilePath, err.Error()))
|
||||
// 设置默认信息,主要方便后续的系统环境变量替换
|
||||
yc.SetDefaultConfig()
|
||||
logx.Warn(fmt.Sprintf("读取配置文件[%s]失败: %s, 使用系统默认配置或环境变量配置", startConfigParam.ConfigFilePath, err.Error()))
|
||||
}
|
||||
// 校验配置文件内容信息
|
||||
yc.Valid()
|
||||
// 尝试使用系统环境变量替换配置信息
|
||||
yc.ReplaceOsEnv()
|
||||
|
||||
yc.IfBlankDefaultValue()
|
||||
// 校验配置文件内容信息
|
||||
yc.Valid()
|
||||
Conf = yc
|
||||
}
|
||||
|
||||
@@ -41,21 +48,34 @@ type CmdConfigParam struct {
|
||||
|
||||
// yaml配置文件映射对象
|
||||
type Config struct {
|
||||
Server *Server `yaml:"server"`
|
||||
Jwt *Jwt `yaml:"jwt"`
|
||||
Aes *Aes `yaml:"aes"`
|
||||
Mysql *Mysql `yaml:"mysql"`
|
||||
Redis *Redis `yaml:"redis"`
|
||||
Log *Log `yaml:"log"`
|
||||
Server Server `yaml:"server"`
|
||||
Jwt Jwt `yaml:"jwt"`
|
||||
Aes Aes `yaml:"aes"`
|
||||
Mysql Mysql `yaml:"mysql"`
|
||||
Redis Redis `yaml:"redis"`
|
||||
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() {
|
||||
assert.IsTrue(c.Jwt != nil, "配置文件的[jwt]信息不能为空")
|
||||
c.Jwt.Valid()
|
||||
if c.Aes != nil {
|
||||
c.Aes.Valid()
|
||||
}
|
||||
}
|
||||
|
||||
// 替换系统环境变量,如果环境变量中存在该值,则优秀使用环境变量设定的值
|
||||
@@ -99,29 +119,3 @@ func (c *Config) ReplaceOsEnv() {
|
||||
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
|
||||
|
||||
import "mayfly-go/pkg/utils/assert"
|
||||
import (
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/utils/assert"
|
||||
"mayfly-go/pkg/utils/stringx"
|
||||
)
|
||||
|
||||
type Jwt struct {
|
||||
Key string `yaml:"key"`
|
||||
ExpireTime uint64 `yaml:"expire-time"` // 过期时间,单位分钟
|
||||
}
|
||||
|
||||
func (j *Jwt) Valid() {
|
||||
assert.IsTrue(j.ExpireTime != 0, "config.yml之 [jwt.expire-time] 不能为空")
|
||||
func (j *Jwt) Default() {
|
||||
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
|
||||
|
||||
import "path"
|
||||
import (
|
||||
"mayfly-go/pkg/logx"
|
||||
"path"
|
||||
)
|
||||
|
||||
type Log struct {
|
||||
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 {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package config
|
||||
|
||||
import "mayfly-go/pkg/logx"
|
||||
|
||||
type Mysql struct {
|
||||
AutoMigration bool `mapstructure:"auto-migration" json:"autoMigration" yaml:"auto-migration"`
|
||||
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"`
|
||||
}
|
||||
|
||||
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 {
|
||||
return m.Username + ":" + m.Password + "@tcp(" + m.Host + ")/" + m.Dbname + "?" + m.Config
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package config
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
Port int `yaml:"port"`
|
||||
@@ -12,6 +14,18 @@ type Server struct {
|
||||
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 {
|
||||
return fmt.Sprintf(":%d", s.Port)
|
||||
}
|
||||
|
||||
@@ -3,12 +3,11 @@ package ginx
|
||||
import (
|
||||
"io"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/utils/structx"
|
||||
"mayfly-go/pkg/validatorx"
|
||||
"net/http"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -105,12 +104,10 @@ func ErrorRes(g *gin.Context, err any) {
|
||||
g.JSON(http.StatusOK, model.Error(t))
|
||||
case error:
|
||||
g.JSON(http.StatusOK, model.ServerError())
|
||||
global.Log.Errorf("%s\n%s", t.Error(), string(debug.Stack()))
|
||||
case string:
|
||||
g.JSON(http.StatusOK, model.ServerError())
|
||||
global.Log.Errorf("%s\n%s", t, string(debug.Stack()))
|
||||
default:
|
||||
global.Log.Error(t)
|
||||
logx.Error("未知错误", "errInfo", t)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var (
|
||||
Log *logrus.Logger // 日志
|
||||
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 (
|
||||
"context"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/utils/stringx"
|
||||
"time"
|
||||
|
||||
@@ -33,7 +33,7 @@ func NewLock(key string, expiration time.Duration) *RedisLock {
|
||||
func (rl *RedisLock) Lock() bool {
|
||||
result, err := cli.SetNX(context.Background(), LockKeyPrefix+rl.key, rl.value, rl.expiration).Result()
|
||||
if err != nil {
|
||||
global.Log.Errorf("redis lock setNx fail: %s", err.Error())
|
||||
logx.Errorf("redis lock setNx fail: %s", err.Error())
|
||||
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()
|
||||
if err != nil {
|
||||
global.Log.Errorf("redis unlock runScript fail: %s", err.Error())
|
||||
logx.Errorf("redis unlock runScript fail: %s", err.Error())
|
||||
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()
|
||||
if err != nil {
|
||||
global.Log.Errorf("redis refreshLock runScript fail: %s", err.Error())
|
||||
logx.Errorf("redis refreshLock runScript fail: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,10 @@ package req
|
||||
import (
|
||||
"fmt"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/utils/anyx"
|
||||
"mayfly-go/pkg/utils/runtimex"
|
||||
"mayfly-go/pkg/utils/stringx"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type SaveLogFunc func(*Ctx)
|
||||
@@ -42,6 +41,8 @@ func (i *LogInfo) WithLogResp() *LogInfo {
|
||||
return i
|
||||
}
|
||||
|
||||
const DefaultLogFrames = 10
|
||||
|
||||
func LogHandler(rc *Ctx) error {
|
||||
if rc.Conf == nil || rc.Conf.logInfo == nil {
|
||||
return nil
|
||||
@@ -49,24 +50,54 @@ func LogHandler(rc *Ctx) error {
|
||||
|
||||
li := rc.Conf.logInfo
|
||||
|
||||
lfs := logrus.Fields{}
|
||||
if la := rc.LoginAccount; la != nil {
|
||||
lfs["uid"] = la.Id
|
||||
lfs["uname"] = la.Username
|
||||
}
|
||||
attrMap := make(map[string]any, 0)
|
||||
|
||||
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 {
|
||||
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 {
|
||||
global.Log.WithFields(lfs).Error(getErrMsg(rc, err))
|
||||
logMsg = getErrMsg(rc, err)
|
||||
} else {
|
||||
logMsg = getLogMsg(rc)
|
||||
}
|
||||
}
|
||||
|
||||
if err := rc.Err; err != nil {
|
||||
logx.ErrorWithFields(logMsg, attrMap)
|
||||
return nil
|
||||
}
|
||||
global.Log.WithFields(lfs).Info(getLogMsg(rc))
|
||||
logx.InfoWithFields(logMsg, attrMap)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -85,19 +116,23 @@ func getLogMsg(rc *Ctx) 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) {
|
||||
msg = msg + fmt.Sprintf("\n--> %s", stringx.AnyToStr(rc.ReqParam))
|
||||
}
|
||||
|
||||
nFrames := DefaultLogFrames
|
||||
var errMsg string
|
||||
switch t := err.(type) {
|
||||
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:
|
||||
errMsg = fmt.Sprintf("\n<-e errMsg: %s", t.Error())
|
||||
case string:
|
||||
errMsg = fmt.Sprintf("\n<-e errMsg: %s", t)
|
||||
}
|
||||
// 加上堆栈信息
|
||||
errMsg += fmt.Sprintf("\n<-stacktrace: %s", runtimex.StatckStr(5, nFrames))
|
||||
return (msg + errMsg)
|
||||
}
|
||||
|
||||
@@ -26,7 +26,9 @@ type Ctx struct {
|
||||
|
||||
func (rc *Ctx) Handle(handler HandlerFunc) {
|
||||
ginCtx := rc.GinCtx
|
||||
begin := time.Now()
|
||||
defer func() {
|
||||
rc.timed = time.Since(begin).Milliseconds()
|
||||
if err := recover(); err != nil {
|
||||
rc.Err = err
|
||||
ginx.ErrorRes(ginCtx, err)
|
||||
@@ -47,7 +49,6 @@ func (rc *Ctx) Handle(handler HandlerFunc) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
begin := time.Now()
|
||||
handler(rc)
|
||||
rc.timed = time.Since(begin).Milliseconds()
|
||||
if rc.Conf == nil || !rc.Conf.noRes {
|
||||
|
||||
@@ -5,47 +5,24 @@ import (
|
||||
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/config"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/utils/stringx"
|
||||
"time"
|
||||
|
||||
"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
|
||||
func CreateToken(userId uint64, username string) string {
|
||||
InitTokenConfig()
|
||||
|
||||
// 带权限创建令牌
|
||||
// 设置有效期,过期需要重新登录获取token
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||
"id": userId,
|
||||
"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
|
||||
tokenString, err := token.SignedString([]byte(JwtKey))
|
||||
tokenString, err := token.SignedString([]byte(config.Conf.Jwt.Key))
|
||||
biz.ErrIsNilAppendErr(err, "token创建失败: %s")
|
||||
return tokenString
|
||||
}
|
||||
@@ -55,11 +32,10 @@ func ParseToken(tokenStr string) (*model.LoginAccount, error) {
|
||||
if tokenStr == "" {
|
||||
return nil, errors.New("token error")
|
||||
}
|
||||
InitTokenConfig()
|
||||
|
||||
// Parse token
|
||||
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 {
|
||||
return nil, err
|
||||
|
||||
@@ -2,7 +2,7 @@ package scheduler
|
||||
|
||||
import (
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"sync"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
@@ -32,7 +32,7 @@ func Remove(id cron.EntryID) {
|
||||
|
||||
// 根据任务key移除
|
||||
func RemoveByKey(key string) {
|
||||
global.Log.Debugf("移除cron任务 => [key = %s]", key)
|
||||
logx.Debugf("移除cron任务 => [key = %s]", key)
|
||||
id, ok := key2IdMap.Load(key)
|
||||
if ok {
|
||||
Remove(id.(cron.EntryID))
|
||||
@@ -53,7 +53,7 @@ func AddFun(spec string, cmd func()) cron.EntryID {
|
||||
|
||||
// 根据key添加定时任务
|
||||
func AddFunByKey(key, spec string, cmd func()) {
|
||||
global.Log.Debugf("添加cron任务 => [key = %s]", key)
|
||||
logx.Debugf("添加cron任务 => [key = %s]", key)
|
||||
RemoveByKey(key)
|
||||
key2IdMap.Store(key, AddFun(spec, cmd))
|
||||
}
|
||||
|
||||
@@ -3,15 +3,18 @@ package starter
|
||||
import (
|
||||
"fmt"
|
||||
"mayfly-go/pkg/config"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
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"
|
||||
"mayfly-go/pkg/config"
|
||||
"mayfly-go/pkg/global"
|
||||
"os"
|
||||
"mayfly-go/pkg/logx"
|
||||
"time"
|
||||
|
||||
"gorm.io/driver/mysql"
|
||||
@@ -19,11 +19,11 @@ func initDb() {
|
||||
|
||||
func gormMysql() *gorm.DB {
|
||||
m := config.Conf.Mysql
|
||||
if m == nil || m.Dbname == "" {
|
||||
global.Log.Panic("未找到数据库配置信息")
|
||||
if m.Dbname == "" {
|
||||
logx.Panic("未找到数据库配置信息")
|
||||
return nil
|
||||
}
|
||||
global.Log.Infof("连接mysql [%s]", m.Host)
|
||||
logx.Infof("连接mysql [%s]", m.Host)
|
||||
mysqlConfig := mysql.Config{
|
||||
DSN: m.Dsn(), // DSN data source name
|
||||
DefaultStringSize: 191, // string 类型字段的默认长度
|
||||
@@ -34,18 +34,19 @@ func gormMysql() *gorm.DB {
|
||||
}
|
||||
|
||||
sqlLogLevel := logger.Error
|
||||
logConf := config.Conf.Log
|
||||
logConf := logx.GetConfig()
|
||||
// 如果为配置文件中配置的系统日志级别为debug,则打印gorm执行的sql信息
|
||||
if logConf.Level == "debug" {
|
||||
if logConf.IsDebug() {
|
||||
sqlLogLevel = logger.Info
|
||||
}
|
||||
|
||||
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{
|
||||
SlowThreshold: time.Second, // 慢 SQL 阈值
|
||||
LogLevel: sqlLogLevel, // 日志级别, 改为logger.Info即可显示sql语句
|
||||
IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误
|
||||
Colorful: true, // 禁用彩色打印
|
||||
Colorful: false, // 禁用彩色打印
|
||||
},
|
||||
)
|
||||
|
||||
@@ -55,7 +56,7 @@ func gormMysql() *gorm.DB {
|
||||
}, Logger: gormLogger}
|
||||
|
||||
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
|
||||
} else {
|
||||
sqlDB, _ := db.DB()
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"mayfly-go/pkg/config"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/rediscli"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
@@ -17,11 +17,11 @@ func initRedis() {
|
||||
func connRedis() *redis.Client {
|
||||
// 设置redis客户端
|
||||
redisConf := config.Conf.Redis
|
||||
if redisConf == nil {
|
||||
// global.Log.Panic("未找到redis配置信息")
|
||||
if redisConf.Host == "" {
|
||||
// logx.Panic("未找到redis配置信息")
|
||||
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{
|
||||
Addr: fmt.Sprintf("%s:%d", redisConf.Host, redisConf.Port),
|
||||
Password: redisConf.Password, // no password set
|
||||
@@ -30,7 +30,7 @@ func connRedis() *redis.Client {
|
||||
// 测试连接
|
||||
_, e := rdb.Ping(context.TODO()).Result()
|
||||
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
|
||||
}
|
||||
|
||||
@@ -5,17 +5,14 @@ import (
|
||||
"mayfly-go/migrations"
|
||||
"mayfly-go/pkg/config"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logger"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/validatorx"
|
||||
)
|
||||
|
||||
func RunWebServer() {
|
||||
// 初始化config.yml配置文件映射信息
|
||||
// 初始化config.yml配置文件映射信息或使用环境变量。并初始化系统日志相关配置
|
||||
config.Init()
|
||||
|
||||
// 初始化日志配置信息
|
||||
logger.Init()
|
||||
|
||||
// 打印banner
|
||||
printBanner()
|
||||
|
||||
@@ -27,7 +24,7 @@ func RunWebServer() {
|
||||
|
||||
// 数据库升级操作
|
||||
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/pkg/biz"
|
||||
"mayfly-go/pkg/config"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/req"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func runWebServer() {
|
||||
// 设置gin日志输出器
|
||||
logOut := logx.GetConfig().GetLogOut()
|
||||
gin.DefaultErrorWriter = logOut
|
||||
gin.DefaultWriter = logOut
|
||||
|
||||
// 权限处理器
|
||||
req.UseBeforeHandlerInterceptor(req.PermissionHandler)
|
||||
// 日志处理器
|
||||
@@ -21,7 +28,7 @@ func runWebServer() {
|
||||
|
||||
server := config.Conf.Server
|
||||
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
|
||||
if server.Tls != nil && server.Tls.Enable {
|
||||
|
||||
@@ -2,7 +2,7 @@ package jsonx
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"strings"
|
||||
|
||||
"github.com/buger/jsonparser"
|
||||
@@ -18,7 +18,7 @@ func ToMapByBytes(bytes []byte) map[string]any {
|
||||
var res map[string]any
|
||||
err := json.Unmarshal(bytes, &res)
|
||||
if err != nil {
|
||||
global.Log.Errorf("json字符串转map失败: %s", err.Error())
|
||||
logx.Errorf("json字符串转map失败: %s", err.Error())
|
||||
}
|
||||
return res
|
||||
}
|
||||
@@ -26,7 +26,7 @@ func ToMapByBytes(bytes []byte) map[string]any {
|
||||
// 转换为json字符串
|
||||
func ToStr(val any) string {
|
||||
if strBytes, err := json.Marshal(val); err != nil {
|
||||
global.Log.Error("toJsonStr error: ", err)
|
||||
logx.ErrorTrace("toJsonStr error: ", err)
|
||||
return ""
|
||||
} else {
|
||||
return string(strBytes)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package netx
|
||||
|
||||
import (
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"net"
|
||||
|
||||
"github.com/lionsoul2014/ip2region/binding/golang/xdb"
|
||||
@@ -43,7 +43,7 @@ func Ip2Region(ip string) string {
|
||||
vIndex, err := xdb.LoadVectorIndexFromFile(ip2RegionDbPath)
|
||||
// 第一次加载失败,则默认调整为不使用ip2Region
|
||||
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
|
||||
return ""
|
||||
}
|
||||
@@ -54,7 +54,7 @@ func Ip2Region(ip string) string {
|
||||
// 2、用全局的 vIndex 创建带 VectorIndex 缓存的查询对象。
|
||||
searcher, err := xdb.NewWithVectorIndex(ip2RegionDbPath, vectorIndex)
|
||||
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 ""
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ func Ip2Region(ip string) string {
|
||||
// do the search
|
||||
region, err := searcher.SearchByStr(ip)
|
||||
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 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
|
||||
|
||||
import (
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"regexp"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
@@ -33,7 +33,7 @@ func RegisterPattern(patternName string, regexpStr string, errMsg string) {
|
||||
func patternValidFunc(f validator.FieldLevel) bool {
|
||||
reg := regexpMap[f.Param()]
|
||||
if reg == nil {
|
||||
global.Log.Warnf("%s的正则校验规则不存在!", f.Param())
|
||||
logx.Warnf("%s的正则校验规则不存在!", f.Param())
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package ws
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
@@ -56,7 +56,7 @@ func checkConn() {
|
||||
|
||||
// 删除ws连接
|
||||
func Delete(userid uint64) {
|
||||
global.Log.Debug("移除websocket连接:uid = ", userid)
|
||||
logx.Debugf("移除websocket连接: uid = %d", userid)
|
||||
conn := conns[userid]
|
||||
if conn != nil {
|
||||
conn.Close()
|
||||
|
||||
Reference in New Issue
Block a user