using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using SmartScanner.ViewModel; namespace SmartScanner { /// /// 优化的日志自动保存服务 /// 功能:批量保存24小时内每一条日志到D盘02 LBLog文件夹 /// 触发条件:最多100条或5秒内批量保存一次 /// public class LogAutoSaveService { private readonly ObservableCollection _logEntries; private Timer _cleanupTimer; private Timer _batchSaveTimer; private const int CLEANUP_INTERVAL_MS = 60 * 60 * 1000; // 1小时清理一次 private const int BATCH_SAVE_INTERVAL_MS = 5000; // 5秒批量保存一次 private const int MAX_BATCH_SIZE = 100; // 最多100条日志批量保存 private readonly string _logDirectory = @"D:\02 LBLog"; private bool _isSaving = false; private readonly object _fileLock = new object(); private readonly object _bufferLock = new object(); private string _currentLogFilePath; private readonly Queue _logBuffer = new Queue(); // 日志缓冲区 private int _bufferCount = 0; // 缓冲区计数 public LogAutoSaveService(ObservableCollection logEntries) { _logEntries = logEntries ?? throw new ArgumentNullException(nameof(logEntries)); // 创建日志目录 if (!Directory.Exists(_logDirectory)) { Directory.CreateDirectory(_logDirectory); } // 初始化当前日志文件路径 InitializeCurrentLogFile(); // 启动批量保存定时器 _batchSaveTimer = new Timer(OnBatchSaveTimerElapsed, null, BATCH_SAVE_INTERVAL_MS, BATCH_SAVE_INTERVAL_MS); // 启动清理定时器 _cleanupTimer = new Timer(OnCleanupTimerElapsed, null, CLEANUP_INTERVAL_MS, CLEANUP_INTERVAL_MS); } /// /// 初始化当前日志文件路径 /// private void InitializeCurrentLogFile() { string currentDate = DateTime.Now.ToString("yyyyMMdd"); string fileName = $"Log_{currentDate}.txt"; _currentLogFilePath = Path.Combine(_logDirectory, fileName); } /// /// 添加日志到缓冲区,延迟批量保存 /// public void LogAdded(LogEntry logEntry) { if (_isSaving) return; lock (_bufferLock) { _logBuffer.Enqueue(logEntry); _bufferCount++; // 如果缓冲区达到最大大小,立即触发保存 if (_bufferCount >= MAX_BATCH_SIZE) { Task.Run(() => SaveBatchAsync()); } } } /// /// 批量保存定时器回调 /// private void OnBatchSaveTimerElapsed(object state) { if (!_isSaving && _bufferCount > 0) { Task.Run(() => SaveBatchAsync()); } } /// /// 异步批量保存日志 /// private async Task SaveBatchAsync() { if (_isSaving) return; _isSaving = true; try { // 检查是否需要切换到新文件 await CheckAndSwitchLogFileAsync(); // 获取缓冲区中的所有日志 List batchToSave; lock (_bufferLock) { if (_bufferCount == 0) { _isSaving = false; return; } batchToSave = new List(_logBuffer); _logBuffer.Clear(); _bufferCount = 0; } // 批量保存到文件 await SaveBatchToFileAsync(batchToSave); Console.WriteLine($"批量保存了 {batchToSave.Count} 条日志到文件"); } catch (Exception ex) { Console.WriteLine($"批量保存失败: {ex.Message}"); } finally { _isSaving = false; } } /// /// 批量保存日志到文件 /// private async Task SaveBatchToFileAsync(List batch) { await Task.Run(() => { lock (_fileLock) { try { using (StreamWriter writer = new StreamWriter(_currentLogFilePath, true, Encoding.UTF8)) { foreach (var entry in batch) { string logLine = $"[{entry.Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{entry.Level}] {entry.Message}"; writer.WriteLine(logLine); } } } catch (Exception ex) { Console.WriteLine($"批量保存到文件失败: {ex.Message}"); } } }); } /// /// 检查是否需要切换到新的日志文件 /// private async Task CheckAndSwitchLogFileAsync() { await Task.Run(() => { string currentDate = DateTime.Now.ToString("yyyyMMdd"); string fileName = $"Log_{currentDate}.txt"; string newFilePath = Path.Combine(_logDirectory, fileName); // 如果日期变化,切换到新文件 if (_currentLogFilePath != newFilePath) { _currentLogFilePath = newFilePath; } }); } private void OnCleanupTimerElapsed(object state) { // 清理超过48小时的日志文件 if (!_isSaving) { Task.Run(() => CleanupOldLogFilesAsync()); } } /// /// 清理超过48小时的日志文件 /// private async Task CleanupOldLogFilesAsync() { await Task.Run(() => { try { if (Directory.Exists(_logDirectory)) { var files = Directory.GetFiles(_logDirectory, "Log_*.txt"); DateTime cutoffTime = DateTime.Now.AddHours(-48); foreach (string file in files) { try { FileInfo fileInfo = new FileInfo(file); if (fileInfo.LastWriteTime < cutoffTime) { File.Delete(file); Console.WriteLine($"清理过期日志文件: {file}"); } } catch (Exception ex) { Console.WriteLine($"清理文件失败 {file}: {ex.Message}"); } } } } catch (Exception ex) { Console.WriteLine($"清理过期日志文件失败: {ex.Message}"); } }); } /// /// 手动保存当前所有日志 /// public void ForceSave() { if (!_isSaving) { Task.Run(() => SaveBatchAsync()); } } /// /// 停止服务 /// public void Stop() { _batchSaveTimer?.Dispose(); _batchSaveTimer = null; _cleanupTimer?.Dispose(); _cleanupTimer = null; // 保存最后的日志 if (!_isSaving && _bufferCount > 0) { ForceSave(); } } /// /// 获取保存统计信息 /// public string GetStatus() { try { string currentFileInfo = ""; if (File.Exists(_currentLogFilePath)) { FileInfo fileInfo = new FileInfo(_currentLogFilePath); currentFileInfo = $", 当前文件大小: {fileInfo.Length / 1024} KB"; } return $"自动保存服务运行中 - 缓冲区: {_bufferCount} 条{currentFileInfo}"; } catch { return $"自动保存服务运行中 - 缓冲区: {_bufferCount} 条"; } } } }