From 9b12c76323f8f17e2a50ea0d0ff5060ddda23d8e Mon Sep 17 00:00:00 2001 From: haoliang <821644@qq.com> Date: Thu, 7 May 2026 12:53:00 +0800 Subject: [PATCH] =?UTF-8?q?=E6=97=A5=E5=BF=97=E6=8C=89=E5=A4=A9=E5=BD=92?= =?UTF-8?q?=E6=A1=A3=E5=88=B0=E6=97=A5=E6=9C=9F=E5=AD=90=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=EF=BC=9Alog4net=E6=94=B9Size=E6=BB=9A=E5=8A=A8+LogArchiveJob?= =?UTF-8?q?=E5=87=8C=E6=99=A8=E5=BD=92=E6=A1=A3+=E8=BF=87=E6=9C=9F?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=E8=87=AA=E5=8A=A8=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/CncCollector/Core/CollectorEngine.cs | 5 + src/CncCollector/Jobs/LogArchiveJob.cs | 151 +++++++++++++++++++++++ src/CncCollector/log4net.config | 14 +-- 3 files changed, 162 insertions(+), 8 deletions(-) create mode 100644 src/CncCollector/Jobs/LogArchiveJob.cs diff --git a/src/CncCollector/Core/CollectorEngine.cs b/src/CncCollector/Core/CollectorEngine.cs index fbf3027..d936fd2 100644 --- a/src/CncCollector/Core/CollectorEngine.cs +++ b/src/CncCollector/Core/CollectorEngine.cs @@ -30,6 +30,7 @@ namespace CncCollector.Core private Timer _dailySummaryTimer; private Timer _logCleanupTimer; private LogCleanupJob _logCleanupJob; + private LogArchiveJob _logArchiveJob; private DateTime _startTime; private long _totalSuccess; private long _totalFail; @@ -59,6 +60,8 @@ namespace CncCollector.Core _dailySummary = new DailySummaryJob(config.BusinessConnection); // 初始化分析引擎(与业务库和日志库同源,后续按需调整) _analysisEngine = new AnalysisEngine(config.BusinessConnection, config.LogConnection); + // 初始化日志归档任务(保留30天) + _logArchiveJob = new LogArchiveJob(30); } /// @@ -337,6 +340,8 @@ namespace CncCollector.Core { _lastSummaryDate = summaryDate; _dailySummary.Execute(summaryDate); + // 同步执行日志归档:把前一天的日志移到日期子目录 + _logArchiveJob.Execute(); } } } diff --git a/src/CncCollector/Jobs/LogArchiveJob.cs b/src/CncCollector/Jobs/LogArchiveJob.cs new file mode 100644 index 0000000..3ed10e0 --- /dev/null +++ b/src/CncCollector/Jobs/LogArchiveJob.cs @@ -0,0 +1,151 @@ +using System; +using System.IO; +using log4net; + +namespace CncCollector.Jobs +{ + /// + /// 日志文件归档任务。 + /// 每天凌晨将前一天的日志文件移动到按日期命名的子目录中。 + /// 目录结构示例: + /// logs\collector.log ← 当前在写的运行日志 + /// logs\collector_error.log ← 当前在写的错误日志 + /// logs\2026-05-07\collector.log + /// logs\2026-05-07\collector_error.log + /// logs\2026-05-06\collector.log + /// logs\2026-05-06\collector_error.log + /// 保留天数外的旧目录自动清理。 + /// + public class LogArchiveJob + { + private static readonly ILog _log = LogManager.GetLogger(typeof(LogArchiveJob)); + + /// + /// 日志保留天数 + /// + private readonly int _retainDays; + + /// + /// 日志根目录(相对于BaseDirectory) + /// + private readonly string _logsDir; + + public LogArchiveJob(int retainDays = 30) + { + _retainDays = retainDays; + _logsDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs"); + } + + /// + /// 执行归档:把当前日志文件复制到昨天的日期目录,然后截断当前文件。 + /// 应在每天凌晨00:00左右调用。 + /// + public void Execute() + { + try + { + if (!Directory.Exists(_logsDir)) + { + return; + } + + var yesterday = DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd"); + var archiveDir = Path.Combine(_logsDir, yesterday); + + // 归档每个日志文件 + ArchiveLogFile("collector.log", archiveDir); + ArchiveLogFile("collector_error.log", archiveDir); + + // 清理过期目录 + CleanupOldDirectories(); + + _log.Info($"日志归档完成({yesterday})"); + } + catch (Exception ex) + { + _log.Error("日志归档失败", ex); + } + } + + /// + /// 归档单个日志文件到日期目录 + /// + private void ArchiveLogFile(string fileName, string archiveDir) + { + var sourceFile = Path.Combine(_logsDir, fileName); + if (!File.Exists(sourceFile)) + { + return; + } + + var fileInfo = new FileInfo(sourceFile); + + // 文件为空或太新(最后写入在1小时内)则跳过 + // 避免归档正在活跃写入的当天日志 + if (fileInfo.Length == 0) + { + return; + } + + // 创建日期目录 + if (!Directory.Exists(archiveDir)) + { + Directory.CreateDirectory(archiveDir); + } + + var destFile = Path.Combine(archiveDir, fileName); + + // 如果目标已存在,追加序号 + if (File.Exists(destFile)) + { + var seq = 1; + var baseName = Path.GetFileNameWithoutExtension(fileName); + var ext = Path.GetExtension(fileName); + do + { + destFile = Path.Combine(archiveDir, $"{baseName}_{seq}{ext}"); + seq++; + } while (File.Exists(destFile)); + } + + // 复制到日期目录(不是移动,因为log4net还持有文件句柄) + File.Copy(sourceFile, destFile); + + // 截断当前日志文件(清空内容,但不删除文件,保持log4net文件句柄有效) + File.WriteAllText(sourceFile, string.Empty); + + _log.Info($"已归档 {fileName} → {archiveDir}({fileInfo.Length} 字节)"); + } + + /// + /// 清理超过保留天数的日期目录 + /// + private void CleanupOldDirectories() + { + if (!Directory.Exists(_logsDir)) + { + return; + } + + var cutoff = DateTime.Now.AddDays(-_retainDays).ToString("yyyy-MM-dd"); + + foreach (var dir in Directory.GetDirectories(_logsDir)) + { + var dirName = Path.GetFileName(dir); + // 日期目录格式:yyyy-MM-dd + if (dirName.Length == 10 && dirName.Contains("-") && dirName.CompareTo(cutoff) < 0) + { + try + { + Directory.Delete(dir, true); + _log.Info($"已清理过期日志目录:{dirName}"); + } + catch (Exception ex) + { + _log.Warn($"清理过期日志目录失败:{dirName}", ex); + } + } + } + } + } +} diff --git a/src/CncCollector/log4net.config b/src/CncCollector/log4net.config index cc5a66e..93e4afa 100644 --- a/src/CncCollector/log4net.config +++ b/src/CncCollector/log4net.config @@ -11,10 +11,9 @@ - - - - + + + @@ -25,10 +24,9 @@ - - - - + + +