From fe596f9db05103917c9257348edcbd3ecb5b46e8 Mon Sep 17 00:00:00 2001
From: yanjinhui <3306209981@qq.com>
Date: 星期四, 16 四月 2026 19:12:38 +0800
Subject: [PATCH] Merge branch 'master' of http://115.159.85.185:8098/r/RuiShengZhiNeng/GaoPuLiTiKu
---
代码管理/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Filter/Log/LogCleanupService.cs | 426 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 426 insertions(+), 0 deletions(-)
diff --git "a/\344\273\243\347\240\201\347\256\241\347\220\206/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Filter/Log/LogCleanupService.cs" "b/\344\273\243\347\240\201\347\256\241\347\220\206/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Filter/Log/LogCleanupService.cs"
new file mode 100644
index 0000000..002b48b
--- /dev/null
+++ "b/\344\273\243\347\240\201\347\256\241\347\220\206/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Filter/Log/LogCleanupService.cs"
@@ -0,0 +1,426 @@
+锘縰sing Microsoft.Extensions.Hosting;
+using SqlSugar;
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using WIDESEAWCS_Core.DB;
+using WIDESEAWCS_Core.Seed;
+using WIDESEAWCS_Model.Models;
+
+namespace WIDESEAWCS_Core.LogHelper
+{
+ /// <summary>
+ /// 鏃ュ織鏁版嵁娓呯悊鏈嶅姟
+ /// </summary>
+ public class LogCleanupService : IHostedService, IDisposable
+ {
+ private Timer _cleanupTimer;
+ private bool _isDisposed = false;
+ private readonly object _lockObject = new object();
+
+ /// <summary>
+ /// 鏁版嵁淇濈暀澶╂暟锛堥粯璁�90澶╋級
+ /// </summary>
+ public int RetentionDays { get; set; } = 90;
+
+ /// <summary>
+ /// 娓呯悊闂撮殧锛堝皬鏃讹紝榛樿24灏忔椂锛�
+ /// </summary>
+ public int CleanupIntervalHours { get; set; } = 24;
+
+ /// <summary>
+ /// 娓呯悊鎵ц鏃堕棿锛堝皬鏃讹紝0-23锛岄粯璁ゅ噷鏅�2鐐癸級
+ /// </summary>
+ public int CleanupHour { get; set; } = 2;
+
+ /// <summary>
+ /// 鏄惁鍚敤褰掓。
+ /// </summary>
+ public bool EnableArchive { get; set; } = false;
+
+ /// <summary>
+ /// 鏄惁鍚敤鑷姩娓呯悊
+ /// </summary>
+ public bool EnableAutoCleanup { get; set; } = true;
+
+ /// <summary>
+ /// 鏃ュ織鏂囦欢淇濈暀澶╂暟
+ /// </summary>
+ public int LogRetentionDays { get; set; } = 30;
+ /// <summary>
+ /// 鏃ュ織鏂囦欢璺緞
+ /// </summary>
+ private string LogFilePath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs", "LogCleanup", $"Cleanup_{DateTime.Now:yyyyMMdd}.log");
+
+ public Task StartAsync(CancellationToken cancellationToken)
+ {
+ if (EnableAutoCleanup)
+ {
+ // 纭繚鏃ュ織鐩綍瀛樺湪
+ EnsureLogDirectoryExists();
+
+ // 璁$畻鍒颁笅涓�涓竻鐞嗘椂闂寸殑闂撮殧
+ var now = DateTime.Now;
+ var nextCleanupTime = DateTime.Today.AddHours(CleanupHour);
+
+ if (now > nextCleanupTime)
+ {
+ nextCleanupTime = nextCleanupTime.AddDays(1);
+ }
+
+ var timeToFirstCleanup = nextCleanupTime - now;
+
+ // 璁剧疆瀹氭椂鍣紝鍦ㄦ寚瀹氭椂闂存墽琛屾竻鐞�
+ _cleanupTimer = new Timer(CleanupCallback, null,
+ timeToFirstCleanup,
+ TimeSpan.FromHours(CleanupIntervalHours));
+
+ WriteLog($"鏃ュ織娓呯悊鏈嶅姟宸插惎鍔紝棣栨娓呯悊鏃堕棿: {nextCleanupTime:yyyy-MM-dd HH:mm:ss}");
+ }
+
+ return Task.CompletedTask;
+ }
+
+ /// <summary>
+ /// 纭繚鏃ュ織鐩綍瀛樺湪
+ /// </summary>
+ private void EnsureLogDirectoryExists()
+ {
+ try
+ {
+ string logDirectory = Path.GetDirectoryName(LogFilePath);
+ if (!Directory.Exists(logDirectory))
+ {
+ Directory.CreateDirectory(logDirectory);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"鍒涘缓鏃ュ織鐩綍澶辫触: {ex.Message}");
+ }
+ }
+
+ /// <summary>
+ /// 鍐欏叆鏃ュ織鍒版枃浠�
+ /// </summary>
+ private void WriteLog(string message, bool isError = false)
+ {
+ try
+ {
+ lock (_lockObject)
+ {
+ EnsureLogDirectoryExists();
+ string logMessage = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {(isError ? "[ERROR]" : "[INFO]")} {message}";
+
+ // 鍐欏叆鏂囦欢
+ File.AppendAllText(LogFilePath, logMessage + Environment.NewLine);
+
+ // 鍚屾椂杈撳嚭鍒版帶鍒跺彴锛堝彲閫夛紝渚夸簬璋冭瘯锛�
+ Console.WriteLine(logMessage);
+
+ // 鏃ュ織鏂囦欢杩囧ぇ鏃惰嚜鍔ㄦ竻鐞嗭紙淇濈暀鏈�杩�30澶╃殑鏃ュ織鏂囦欢锛�
+ AutoCleanupLogFiles();
+ }
+ }
+ catch (Exception ex)
+ {
+ // 濡傛灉鏂囦欢鏃ュ織澶辫触锛岃嚦灏戣緭鍑哄埌鎺у埗鍙�
+ Console.WriteLine($"鍐欏叆鏃ュ織鏂囦欢澶辫触: {ex.Message}");
+ Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}");
+ }
+ }
+
+ /// <summary>
+ /// 鑷姩娓呯悊杩囨湡鐨勬棩蹇楁枃浠讹紙淇濈暀30澶╋級
+ /// </summary>
+ private void AutoCleanupLogFiles()
+ {
+ try
+ {
+ string logDirectory = Path.GetDirectoryName(LogFilePath);
+ if (Directory.Exists(logDirectory))
+ {
+ var files = Directory.GetFiles(logDirectory, "Cleanup_*.log");
+ DateTime cutoffDate = DateTime.Now.AddDays(-30);
+
+ foreach (var file in files)
+ {
+ try
+ {
+ // 浠庢枃浠跺悕涓彁鍙栨棩鏈�
+ string fileName = Path.GetFileNameWithoutExtension(file);
+ if (fileName.StartsWith("Cleanup_"))
+ {
+ string dateStr = fileName.Replace("Cleanup_", "");
+ if (DateTime.TryParseExact(dateStr, "yyyyMMdd", null, System.Globalization.DateTimeStyles.None, out DateTime fileDate))
+ {
+ if (fileDate < cutoffDate)
+ {
+ File.Delete(file);
+ WriteLog($"鍒犻櫎杩囨湡鏃ュ織鏂囦欢: {Path.GetFileName(file)}");
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"鍒犻櫎杩囨湡鏃ュ織鏂囦欢澶辫触 {file}: {ex.Message}");
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"娓呯悊鏃ュ織鏂囦欢澶辫触: {ex.Message}");
+ }
+ }
+
+ private void CleanupCallback(object state)
+ {
+ Task.Run(() => CleanupAsync());
+ }
+
+ /// <summary>
+ /// 鎵ц娓呯悊
+ /// </summary>
+ public async Task CleanupAsync()
+ {
+ try
+ {
+ WriteLog($"寮�濮嬫竻鐞� {RetentionDays} 澶╁墠鐨勬棩蹇楁暟鎹�");
+
+ using (SqlSugarClient sugarClient = new SqlSugarClient(new ConnectionConfig()
+ {
+ ConnectionString = DBContext.GetMainConnectionDb().Connection,
+ IsAutoCloseConnection = true,
+ DbType = DBContext.DbType,
+ }))
+ {
+ DateTime cutoffDate = DateTime.Now.AddDays(-RetentionDays);
+
+ WriteLog($"鎴鏃ユ湡: {cutoffDate:yyyy-MM-dd HH:mm:ss}");
+
+ if (EnableArchive)
+ {
+ // 鍏堝綊妗e啀鍒犻櫎
+ await ArchiveDataAsync(sugarClient, cutoffDate);
+ }
+
+ // 鍒犻櫎鍘嗗彶鏁版嵁
+ int deletedCount = await sugarClient.Deleteable<Dt_InterfaceLog>()
+ .Where(x => x.CreateDate < cutoffDate)
+ .ExecuteCommandAsync();
+
+ WriteLog($"娓呯悊瀹屾垚锛屽叡鍒犻櫎 {deletedCount} 鏉¤褰�");
+
+ // 鍙�夛細璁板綍娓呯悊鏃ュ織鍒版暟鎹簱
+ await LogCleanupResult(sugarClient, deletedCount, cutoffDate);
+ }
+ }
+ catch (Exception ex)
+ {
+ WriteLog($"娓呯悊澶辫触: {ex.Message}", true);
+ WriteLog($"璇︾粏閿欒: {ex.ToString()}", true);
+ }
+ }
+
+ private async Task ArchiveDataAsync(SqlSugarClient sugarClient, DateTime cutoffDate)
+ {
+ try
+ {
+ string archiveTableName = $"Dt_InterfaceLog_Archive_{DateTime.Now:yyyyMM}";
+
+ WriteLog($"寮�濮嬪綊妗f暟鎹埌琛�: {archiveTableName}");
+
+ // 鍒涘缓褰掓。琛�
+ string createTableSql = $@"
+ IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='{archiveTableName}' AND xtype='U')
+ BEGIN
+ SELECT * INTO {archiveTableName} FROM Dt_InterfaceLog WHERE 1=0
+ ALTER TABLE {archiveTableName} ADD ArchiveDate datetime DEFAULT GETDATE()
+ END";
+ await sugarClient.Ado.ExecuteCommandAsync(createTableSql);
+
+ // 褰掓。鏁版嵁
+ string archiveSql = $@"
+ INSERT INTO {archiveTableName} (Id, ApiCode, ApiName, ApiAddress, PushFrequency,
+ PushState, Requestor, RequestParameters, RequestParametersHash, Recipient,
+ ResponseParameters, ResponseParametersHash, Remark, CreateTime, ArchiveDate)
+ SELECT Id, ApiCode, ApiName, ApiAddress, PushFrequency, PushState,
+ Requestor, RequestParameters, RequestParametersHash, Recipient,
+ ResponseParameters, ResponseParametersHash, Remark, CreateTime, GETDATE()
+ FROM Dt_InterfaceLog
+ WHERE CreateTime < @CutoffDate";
+
+ int archivedCount = await sugarClient.Ado.ExecuteCommandAsync(archiveSql,
+ new { CutoffDate = cutoffDate });
+
+ WriteLog($"褰掓。瀹屾垚锛屽叡褰掓。 {archivedCount} 鏉¤褰曞埌 {archiveTableName}");
+ }
+ catch (Exception ex)
+ {
+ WriteLog($"褰掓。澶辫触: {ex.Message}", true);
+ }
+ }
+
+ private async Task LogCleanupResult(SqlSugarClient sugarClient, int deletedCount, DateTime cutoffDate)
+ {
+ try
+ {
+ // 鍒涘缓娓呯悊鏃ュ織琛紙濡傛灉涓嶅瓨鍦級
+ string createLogTableSql = @"
+ IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='LogCleanupHistory' AND xtype='U')
+ BEGIN
+ CREATE TABLE LogCleanupHistory (
+ Id INT IDENTITY(1,1) PRIMARY KEY,
+ TableName NVARCHAR(100),
+ DeletedCount INT,
+ CutoffDate DATETIME,
+ CleanupTime DATETIME DEFAULT GETDATE()
+ )
+ END";
+ await sugarClient.Ado.ExecuteCommandAsync(createLogTableSql);
+
+ // 璁板綍娓呯悊鏃ュ織
+ string insertLogSql = @"
+ INSERT INTO LogCleanupHistory (TableName, DeletedCount, CutoffDate, CleanupTime)
+ VALUES ('Dt_InterfaceLog', @DeletedCount, @CutoffDate, GETDATE())";
+
+ await sugarClient.Ado.ExecuteCommandAsync(insertLogSql,
+ new { DeletedCount = deletedCount, CutoffDate = cutoffDate });
+
+ WriteLog($"娓呯悊璁板綍宸插啓鍏ユ暟鎹簱鏃ュ織琛�");
+ }
+ catch (Exception ex)
+ {
+ WriteLog($"鍐欏叆鏁版嵁搴撴棩蹇楀け璐�: {ex.Message}", true);
+ }
+ }
+
+ /// <summary>
+ /// 鎵嬪姩鎵ц娓呯悊
+ /// </summary>
+ public async Task<int> ManualCleanup(int days = 90)
+ {
+ try
+ {
+ WriteLog($"鎵嬪姩娓呯悊寮�濮嬶紝鍒犻櫎瓒呰繃 {days} 澶╃殑鏁版嵁");
+
+ using (SqlSugarClient sugarClient = new SqlSugarClient(new ConnectionConfig()
+ {
+ ConnectionString = DBContext.GetMainConnectionDb().Connection,
+ IsAutoCloseConnection = true,
+ DbType = DBContext.DbType,
+ }))
+ {
+ DateTime cutoffDate = DateTime.Now.AddDays(-days);
+ int deletedCount = await sugarClient.Deleteable<Dt_InterfaceLog>()
+ .Where(x => x.CreateDate < cutoffDate)
+ .ExecuteCommandAsync();
+
+ WriteLog($"鎵嬪姩娓呯悊瀹屾垚锛屽垹闄� {deletedCount} 鏉¤褰�");
+ return deletedCount;
+ }
+ }
+ catch (Exception ex)
+ {
+ WriteLog($"鎵嬪姩娓呯悊澶辫触: {ex.Message}", true);
+ return 0;
+ }
+ }
+
+ /// <summary>
+ /// 鑾峰彇娓呯悊缁熻淇℃伅
+ /// </summary>
+ public async Task<CleanupStatistics> GetStatistics()
+ {
+ try
+ {
+ using (SqlSugarClient sugarClient = new SqlSugarClient(new ConnectionConfig()
+ {
+ ConnectionString = DBContext.GetMainConnectionDb().Connection,
+ IsAutoCloseConnection = true,
+ DbType = DBContext.DbType,
+ }))
+ {
+ var totalCount = await sugarClient.Queryable<Dt_InterfaceLog>().CountAsync();
+ var oldestLog = await sugarClient.Queryable<Dt_InterfaceLog>()
+ .OrderBy(x => x.CreateDate)
+ .FirstAsync();
+ var newestLog = await sugarClient.Queryable<Dt_InterfaceLog>()
+ .OrderBy(x => x.CreateDate, OrderByType.Desc)
+ .FirstAsync();
+
+ return new CleanupStatistics
+ {
+ TotalCount = totalCount,
+ OldestLogTime = oldestLog?.CreateDate,
+ NewestLogTime = newestLog?.CreateDate,
+ RetentionDays = RetentionDays,
+ LastCleanupTime = GetLastCleanupTime(),
+ LogFilePath = LogFilePath
+ };
+ }
+ }
+ catch (Exception ex)
+ {
+ WriteLog($"鑾峰彇缁熻淇℃伅澶辫触: {ex.Message}", true);
+ return null;
+ }
+ }
+
+ private DateTime? GetLastCleanupTime()
+ {
+ try
+ {
+ string logDirectory = Path.GetDirectoryName(LogFilePath);
+ if (Directory.Exists(logDirectory))
+ {
+ var latestLogFile = Directory.GetFiles(logDirectory, "Cleanup_*.log")
+ .OrderByDescending(f => f)
+ .FirstOrDefault();
+
+ if (latestLogFile != null && File.Exists(latestLogFile))
+ {
+ return File.GetLastWriteTime(latestLogFile);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"鑾峰彇涓婃娓呯悊鏃堕棿澶辫触: {ex.Message}");
+ }
+ return null;
+ }
+
+ public Task StopAsync(CancellationToken cancellationToken)
+ {
+ _cleanupTimer?.Dispose();
+ WriteLog("鏃ュ織娓呯悊鏈嶅姟宸插仠姝�");
+ return Task.CompletedTask;
+ }
+
+ public void Dispose()
+ {
+ if (!_isDisposed)
+ {
+ _cleanupTimer?.Dispose();
+ _isDisposed = true;
+ }
+ }
+ }
+
+ /// <summary>
+ /// 娓呯悊缁熻淇℃伅
+ /// </summary>
+ public class CleanupStatistics
+ {
+ public int TotalCount { get; set; }
+ public DateTime? OldestLogTime { get; set; }
+ public DateTime? NewestLogTime { get; set; }
+ public int RetentionDays { get; set; }
+ public DateTime? LastCleanupTime { get; set; }
+ public string LogFilePath { get; set; }
+ }
+}
\ No newline at end of file
--
Gitblit v1.9.3