diff --git a/config/config.go b/config/config.go index 36e28ce..89e8a58 100644 --- a/config/config.go +++ b/config/config.go @@ -5,7 +5,7 @@ package config const ( ProjectName = "gtbox" - ProjectVersion = "v0.1.95" + ProjectVersion = "v0.1.96" ProjectDescription = "[Golang]日常开发工具箱" ) diff --git a/gtbox_log/gtbox_log.go b/gtbox_log/gtbox_log.go index 752a4b8..7bb6ca5 100644 --- a/gtbox_log/gtbox_log.go +++ b/gtbox_log/gtbox_log.go @@ -6,7 +6,6 @@ package gtbox_log import ( "fmt" "github.com/george012/gtbox/gtbox_color" - "github.com/george012/gtbox/gtbox_time" rotatelogs "github.com/lestrrat-go/file-rotatelogs" "github.com/sirupsen/logrus" "os" @@ -102,12 +101,13 @@ func setupDefaultLog() *GTLog { type GTLog struct { sync.RWMutex - logger *logrus.Logger // 添加这一行 - modelName string - logDir string - logDirWithDate string - entryTime time.Time // 日志初始化时间,留作后续比对使用 - lastCheckTime time.Time // 记录最后一次检查时间,用作日志轮转 + saveFileEnabled bool + logger *logrus.Logger // 添加这一行 + modelName string + logDir string + logDirWithDate string + entryTime time.Time // 日志初始化时间,留作后续比对使用 + lastCheckTime time.Time // 记录最后一次检查时间,用作日志轮转 } @@ -132,36 +132,25 @@ func (aLog *GTLog) logF(style GTLogStyle, format string, args ...interface{}) { defer aLog.Unlock() colorFormat := format - if instanceConfig().enableSaveLogFile != true { - // TODO 每分钟检查一次是否需要更新日志文件路径 - now := time.Now().UTC() - if now.Sub(aLog.lastCheckTime) > time.Minute { - if gtbox_time.GTDateEqualYearMoonDay(aLog.lastCheckTime, now) == false { - aLog.logDirWithDate = fmt.Sprintf("%s/%s", aLog.logDir, now.Format("2006-01-02")) - rLog := newLogSaveHandler(aLog) - aLog.logger.SetOutput(rLog) - aLog.lastCheckTime = now + + // 对每个占位符、非占位符片段和'['、']'进行迭代,为它们添加相应的颜色 + re := regexp.MustCompile(`(%[vTsdfqTbcdoxXUeEgGp]+)|(\[|\])|([^%\[\]]+)`) + colorFormat = re.ReplaceAllStringFunc(format, func(s string) string { + switch { + case strings.HasPrefix(s, "%"): + return fmt.Sprintf("%s%s%s", gtbox_color.ANSIColorForegroundBrightYellow, s, gtbox_color.ANSIColorReset) + case s == "[" || s == "]": + return s // 保持 `[` 和 `]` 的原始颜色 + default: + if style == GTLogStyleError { + return fmt.Sprintf("%s%s%s", gtbox_color.ANSIColorForegroundBrightRed, s, gtbox_color.ANSIColorReset) + } else if style == GTLogStyleInfo { + return fmt.Sprintf("%s%s%s", gtbox_color.ANSIColorForegroundBrightGreen, s, gtbox_color.ANSIColorReset) + } else { + return fmt.Sprintf("%s%s%s", gtbox_color.ANSIColorForegroundBrightCyan, s, gtbox_color.ANSIColorReset) } } - // 对每个占位符、非占位符片段和'['、']'进行迭代,为它们添加相应的颜色 - re := regexp.MustCompile(`(%[vTsdfqTbcdoxXUeEgGp]+)|(\[|\])|([^%\[\]]+)`) - colorFormat = re.ReplaceAllStringFunc(format, func(s string) string { - switch { - case strings.HasPrefix(s, "%"): - return fmt.Sprintf("%s%s%s", gtbox_color.ANSIColorForegroundBrightYellow, s, gtbox_color.ANSIColorReset) - case s == "[" || s == "]": - return s // 保持 `[` 和 `]` 的原始颜色 - default: - if style == GTLogStyleError { - return fmt.Sprintf("%s%s%s", gtbox_color.ANSIColorForegroundBrightRed, s, gtbox_color.ANSIColorReset) - } else if style == GTLogStyleInfo { - return fmt.Sprintf("%s%s%s", gtbox_color.ANSIColorForegroundBrightGreen, s, gtbox_color.ANSIColorReset) - } else { - return fmt.Sprintf("%s%s%s", gtbox_color.ANSIColorForegroundBrightCyan, s, gtbox_color.ANSIColorReset) - } - } - }) - } + }) if style != GTLogStyleInfo { pc, _, _, _ := runtime.Caller(2) @@ -291,9 +280,6 @@ func NewGTLog(modelName string) *GTLog { gtLog.logger.SetLevel(logrus.TraceLevel) - // 设置默认日志输出为控制台 - gtLog.logger.SetOutput(os.Stdout) - // 根据LogLevel设置logrus的日志级别 switch currentLogConfig.logLeve { case GTLogStyleFatal: @@ -312,6 +298,11 @@ func NewGTLog(modelName string) *GTLog { gtLog.logger.SetLevel(logrus.InfoLevel) } + gtLog.saveFileEnabled = instanceConfig().enableSaveLogFile + + // 设置默认日志输出为控制台 + gtLog.logger.SetOutput(os.Stdout) + // 设置日志输出,可以根据EnableSaveLogFile和其他参数来配置 // (省略了日志轮转和文件输出的设置,可以直接使用SetupLogTools中相关的代码) // 设置Log @@ -319,6 +310,15 @@ func NewGTLog(modelName string) *GTLog { rLog := newLogSaveHandler(gtLog) gtLog.logger.SetOutput(rLog) } + + // 启动日志维护 Goroutine,首次执行完成后继续初始化操作 + gtLog.startLogMaintenance(func(done chan struct{}) { + // 在这里执行首次操作,比如检查日志目录和初始化逻辑 + fmt.Println("First run checks completed") + // 通知首次任务完成 + close(done) + }) + return gtLog } diff --git a/gtbox_log/gtbox_log_policy.go b/gtbox_log/gtbox_log_policy.go new file mode 100644 index 0000000..5d6f0d8 --- /dev/null +++ b/gtbox_log/gtbox_log_policy.go @@ -0,0 +1,95 @@ +package gtbox_log + +import ( + "fmt" + "os" + "time" +) + +func (aLog *GTLog) startLogMaintenance(firstRunFunc func(done chan struct{})) { + done := make(chan struct{}) // 创建无缓冲通道用于同步 + + go func() { + firstRunDone := false // 用于跟踪首次循环是否完成 + ticker := time.NewTicker(time.Minute) // 每分钟检查一次 + defer ticker.Stop() + + for { + if !firstRunDone { // 如果还没有执行第一次 + // 首次执行传入的检查和清理函数 + aLog.checkAndUpdateLogDir() + aLog.cleanOldLogs() + firstRunDone = true // 标记第一次运行已完成 + firstRunFunc(done) // 调用 firstRunFunc,并在其内部关闭通道 + } else { + select { + case <-ticker.C: + // 定时任务:每分钟检查一次 + aLog.checkAndUpdateLogDir() + aLog.cleanOldLogs() + } + } + } + }() + + <-done // 等待通道关闭,表示首次执行已完成 +} + +// checkAndUpdateLogDir 检查并更新日志目录 +func (aLog *GTLog) checkAndUpdateLogDir() { + // TODO 每分钟检查一次是否需要更新日志文件路径 + now := time.Now().UTC() + newLogDirWithDate := fmt.Sprintf("%s/%s", aLog.logDir, now.Format("2006-01-02")) + + if aLog.logDirWithDate != newLogDirWithDate { + aLog.logDirWithDate = newLogDirWithDate + rLog := newLogSaveHandler(aLog) + aLog.logger.SetOutput(rLog) + aLog.lastCheckTime = now + } +} + +func (aLog *GTLog) cleanOldLogs() { + if aLog.saveFileEnabled == false { + return + } + + dirs, err := os.ReadDir(aLog.logDir) + if err != nil { + fmt.Printf("Error reading log directory: %s\n", err) + return + } + + now := time.Now() + maxAge := time.Duration(instanceConfig().logMaxSaveDays) * 24 * time.Hour + + for _, dir := range dirs { + if !dir.IsDir() { + continue + } + + dirPath := fmt.Sprintf("%s/%s", aLog.logDir, dir.Name()) + + // 跳过当前正在使用的日志目录 + if dirPath == aLog.logDirWithDate { + continue + } + + // 假设目录名格式为 YYYY-MM-DD + dirDate, err := time.Parse("2006-01-02", dir.Name()) + if err != nil { + // 如果解析失败,跳过此目录 + continue + } + + // 判断目录是否超出保存期限 + if now.Sub(dirDate) > maxAge { + err := os.RemoveAll(dirPath) + if err != nil { + fmt.Printf("Error removing directory: %s, error: %v\n", dirPath, err) + } else { + fmt.Printf("Deleted old log directory: %s\n", dirPath) + } + } + } +} diff --git a/gtbox_log/gtbox_log_test/gtbox_log_test.go b/gtbox_log/gtbox_log_test/gtbox_log_test.go index cc361c6..f1626e8 100644 --- a/gtbox_log/gtbox_log_test/gtbox_log_test.go +++ b/gtbox_log/gtbox_log_test/gtbox_log_test.go @@ -7,24 +7,24 @@ import ( ) func TestCustomLog(t *testing.T) { - gtbox_log.SetupLogTools("testP", false, gtbox_log.GTLogStyleTrace, 3, gtbox_log.GTLogSaveHours, "") + gtbox_log.SetupLogTools("testP", true, gtbox_log.GTLogStyleTrace, 3, gtbox_log.GTLogSaveHours, "") - for q := 0; q < 3; q++ { - gtbox_log.LogDebugf("main_test %d", q) - gtbox_log.LogInfof("main_test %d", q) - gtbox_log.LogWarnf("main_test %d", q) - gtbox_log.LogTracef("main_test %d", q) - gtbox_log.LogErrorf("main_test %d", q) + for q := 0; q < 1; q++ { + gtbox_log.LogDebugf("main_test %d debug", q) + gtbox_log.LogInfof("main_test %d info", q) + gtbox_log.LogWarnf("main_test %d warning", q) + gtbox_log.LogTracef("main_test %d trace", q) + gtbox_log.LogErrorf("main_test %d error", q) } - for i := 0; i < 3; i++ { - a_loger := gtbox_log.NewGTLog(fmt.Sprintf("at_%d", i)) - for j := 0; j < 3; j++ { - a_loger.LogDebugf("at_ %d", j) - a_loger.LogInfof("at_ %d", j) - a_loger.LogWarnf("at_ %d", j) - a_loger.LogTracef("at_ %d", j) - a_loger.LogErrorf("at_ %d", j) + for i := 0; i < 2; i++ { + a_loger := gtbox_log.NewGTLog(fmt.Sprintf("at_%d_all", i)) + for j := 0; j < 1; j++ { + a_loger.LogDebugf("at_ %d debug", j) + a_loger.LogInfof("at_ %d info", j) + a_loger.LogWarnf("at_ %d warning", j) + a_loger.LogTracef("at_ %d trace", j) + a_loger.LogErrorf("at_ %d error", j) } }