diff --git a/server/cmd/main.go b/server/cmd/main.go index 807df8f..3852f2f 100644 --- a/server/cmd/main.go +++ b/server/cmd/main.go @@ -7,8 +7,10 @@ import ( "kenaito-conf/server/internal/dao" "kenaito-conf/server/internal/handler" "kenaito-conf/server/internal/middleware" + "kenaito-conf/server/internal/model" "kenaito-conf/server/internal/service" "log" + "time" "github.com/gin-gonic/gin" ) @@ -126,6 +128,17 @@ func main() { // start server addr := fmt.Sprintf(":%d", config.Cfg.Server.Port) log.Printf("Server starting on %s", addr) + + // 启动定时任务:清理过期的客户端实例记录 + go func() { + ticker := time.NewTicker(1 * time.Minute) + defer ticker.Stop() + for range ticker.C { + fiveMinutesAgo := time.Now().Add(-5 * time.Minute) + dao.Engine.Where("last_ping_at < ?", fiveMinutesAgo).Delete(&model.ClientInstance{}) + } + }() + if err := r.Run(addr); err != nil { log.Fatalf("server error: %v", err) } diff --git a/server/go.mod b/server/go.mod index 2d8c609..f85c7c3 100644 --- a/server/go.mod +++ b/server/go.mod @@ -7,7 +7,9 @@ require ( github.com/gin-gonic/gin v1.12.0 github.com/go-sql-driver/mysql v1.10.1 github.com/golang-jwt/jwt/v5 v5.3.1 + go.uber.org/zap v1.28.0 golang.org/x/crypto v0.58.0 + gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v3 v3.0.1 xorm.io/xorm v1.4.3 ) @@ -39,6 +41,7 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.3.1 // indirect go.mongodb.org/mongo-driver/v2 v2.8.0 // indirect + go.uber.org/multierr v1.10.0 // indirect golang.org/x/arch v0.29.0 // indirect golang.org/x/net v0.60.0 // indirect golang.org/x/sys v0.49.0 // indirect diff --git a/server/go.sum b/server/go.sum index cf7a489..8f470af 100644 --- a/server/go.sum +++ b/server/go.sum @@ -112,8 +112,16 @@ github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= go.mongodb.org/mongo-driver/v2 v2.8.0 h1:CxWDGQYY8QQwNjAl/aq2sfWakdnWZynnqJ9F4DhHbP8= go.mongodb.org/mongo-driver/v2 v2.8.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= +go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/arch v0.29.0 h1:8sSET5wB0+exBm0FGmOtdHMqjlRdV2DRD3/IV6OZgho= golang.org/x/arch v0.29.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8= golang.org/x/crypto v0.58.0 h1:COkYLr4k7nDI4r6QtMML2AfzeIswWHAJthLS6K/M/54= @@ -141,6 +149,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/server/internal/handler/config_api.go b/server/internal/handler/config_api.go index e97b650..4f58955 100644 --- a/server/internal/handler/config_api.go +++ b/server/internal/handler/config_api.go @@ -1,8 +1,8 @@ package handler import ( - "fmt" "kenaito-conf/server/internal/dao" + "kenaito-conf/server/internal/logger" "kenaito-conf/server/internal/model" "kenaito-conf/server/internal/service" "net/http" @@ -242,14 +242,11 @@ func (h *ConfigApiHandler) recordClientInstances(ip string, configIds []int, app } _, err := dao.Engine.Insert(&instance) if err != nil { - fmt.Printf("[recordClientInstances] insert error: %v\n", err) + logger.SugaredLogger.Errorf("[recordClientInstances] insert error: %v", err) continue } } } - // cleanup records older than 5 minutes - fiveMinutesAgo := now.Add(-5 * time.Minute) - dao.Engine.Where("last_ping_at < ?", fiveMinutesAgo).Delete(&model.ClientInstance{}) } // func (h *ConfigApiHandler) Ping(c *gin.Context) { diff --git a/server/internal/logger/index.go b/server/internal/logger/index.go new file mode 100644 index 0000000..710e52a --- /dev/null +++ b/server/internal/logger/index.go @@ -0,0 +1,57 @@ +package logger + +import ( + "os" + "time" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "gopkg.in/natefinch/lumberjack.v2" +) + +var globalLogger *zap.Logger + +// SugaredLogger 全局 SugaredLogger,任意位置可直接使用 +var SugaredLogger *zap.SugaredLogger + +// 初始化全局日志(控制台 + application.log 轮转文件) +func init() { + encoderConfig := zapcore.EncoderConfig{ + TimeKey: "time", + LevelKey: "level", + NameKey: "logger", + CallerKey: "caller", + MessageKey: "msg", + StacktraceKey: "stack", + LineEnding: zapcore.DefaultLineEnding, + EncodeLevel: zapcore.CapitalColorLevelEncoder, + EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString(t.Format("2006-01-02 15:04:05")) + }, + EncodeDuration: zapcore.StringDurationEncoder, + EncodeCaller: zapcore.ShortCallerEncoder, + } + + // 日志轮转配置 + lumberjackLogger := &lumberjack.Logger{ + Filename: "application.log", + MaxSize: 100, // 每个日志文件最大 100MB + MaxBackups: 5, // 最多保留 5 个旧日志文件 + MaxAge: 30, // 日志文件最多保留 30 天 + Compress: true, // 压缩旧日志 + } + + // 同时输出到控制台和文件 + consoleEncoder := zapcore.NewConsoleEncoder(encoderConfig) + consoleWriter := zapcore.AddSync(os.Stdout) + fileWriter := zapcore.AddSync(lumberjackLogger) + + core := zapcore.NewTee( + zapcore.NewCore(consoleEncoder, consoleWriter, zap.InfoLevel), + zapcore.NewCore(consoleEncoder, fileWriter, zap.InfoLevel), + ) + + globalLogger = zap.New(core, zap.AddCaller(), zap.AddStacktrace(zap.ErrorLevel)) + SugaredLogger = globalLogger.Sugar() + zap.ReplaceGlobals(globalLogger) +}