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
|
{
|
/// <summary>
|
/// 优化的日志自动保存服务
|
/// 功能:批量保存48小时内每一条日志到D盘02 LBLog文件夹
|
/// 触发条件:最多300条或十分钟批量保存一次
|
/// </summary>
|
public class LogAutoSaveService
|
{
|
private readonly ObservableCollection<LogEntry> _logEntries;
|
private Timer _cleanupTimer;
|
private Timer _batchSaveTimer;
|
private const int CLEANUP_INTERVAL_MS = 60 * 60 * 1000; // 1小时清理一次
|
private const int BATCH_SAVE_INTERVAL_MS = 600000; // 十分钟批量保存一次
|
private const int MAX_BATCH_SIZE = 300; // 最多300条日志批量保存
|
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<LogEntry> _logBuffer = new Queue<LogEntry>(); // 日志缓冲区
|
private int _bufferCount = 0; // 缓冲区计数
|
|
public LogAutoSaveService(ObservableCollection<LogEntry> 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);
|
}
|
|
/// <summary>
|
/// 初始化当前日志文件路径
|
/// </summary>
|
private void InitializeCurrentLogFile()
|
{
|
string currentDate = DateTime.Now.ToString("yyyyMMdd");
|
string fileName = $"Log_{currentDate}.txt";
|
_currentLogFilePath = Path.Combine(_logDirectory, fileName);
|
}
|
|
/// <summary>
|
/// 添加日志到缓冲区,延迟批量保存
|
/// </summary>
|
public void LogAdded(LogEntry logEntry)
|
{
|
if (_isSaving) return;
|
|
lock (_bufferLock)
|
{
|
_logBuffer.Enqueue(logEntry);
|
_bufferCount++;
|
|
// 如果缓冲区达到最大大小,立即触发保存
|
if (_bufferCount >= MAX_BATCH_SIZE)
|
{
|
Task.Run(() => SaveBatchAsync());
|
}
|
}
|
}
|
|
/// <summary>
|
/// 批量保存定时器回调
|
/// </summary>
|
private void OnBatchSaveTimerElapsed(object state)
|
{
|
if (!_isSaving && _bufferCount > 0)
|
{
|
Task.Run(() => SaveBatchAsync());
|
}
|
}
|
|
/// <summary>
|
/// 异步批量保存日志
|
/// </summary>
|
private async Task SaveBatchAsync()
|
{
|
if (_isSaving) return;
|
|
_isSaving = true;
|
|
try
|
{
|
// 检查是否需要切换到新文件
|
await CheckAndSwitchLogFileAsync();
|
|
// 获取缓冲区中的所有日志
|
List<LogEntry> batchToSave;
|
lock (_bufferLock)
|
{
|
if (_bufferCount == 0)
|
{
|
_isSaving = false;
|
return;
|
}
|
|
batchToSave = new List<LogEntry>(_logBuffer);
|
_logBuffer.Clear();
|
_bufferCount = 0;
|
}
|
|
// 批量保存到文件
|
await SaveBatchToFileAsync(batchToSave);
|
|
Console.WriteLine($"批量保存了 {batchToSave.Count} 条日志到文件");
|
}
|
catch (Exception ex)
|
{
|
Console.WriteLine($"批量保存失败: {ex.Message}");
|
}
|
finally
|
{
|
_isSaving = false;
|
}
|
}
|
|
/// <summary>
|
/// 批量保存日志到文件
|
/// </summary>
|
private async Task SaveBatchToFileAsync(List<LogEntry> 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}");
|
}
|
}
|
});
|
}
|
|
/// <summary>
|
/// 检查是否需要切换到新的日志文件
|
/// </summary>
|
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());
|
}
|
}
|
|
/// <summary>
|
/// 清理超过48小时的日志文件
|
/// </summary>
|
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}");
|
}
|
});
|
}
|
|
/// <summary>
|
/// 手动保存当前所有日志
|
/// </summary>
|
public void ForceSave()
|
{
|
if (!_isSaving)
|
{
|
Task.Run(() => SaveBatchAsync());
|
}
|
}
|
|
/// <summary>
|
/// 停止服务
|
/// </summary>
|
public void Stop()
|
{
|
_batchSaveTimer?.Dispose();
|
_batchSaveTimer = null;
|
_cleanupTimer?.Dispose();
|
_cleanupTimer = null;
|
|
// 保存最后的日志
|
if (!_isSaving && _bufferCount > 0)
|
{
|
ForceSave();
|
}
|
}
|
|
/// <summary>
|
/// 获取保存统计信息
|
/// </summary>
|
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} 条";
|
}
|
}
|
}
|
}
|