using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Check.Main.Common { /// /// 一个线程安全的、基于队列的日志记录器。 /// 使用一个独立的后台线程来处理文件写入,避免业务线程阻塞。 /// public static class ThreadSafeLogger { // 使用线程安全的队列作为日志消息的缓冲区 private static readonly BlockingCollection _logQueue = new BlockingCollection(); // 日志写入线程 private static Thread _logWriterThread; private static StreamWriter _logFileWriter; // 事件,用于将格式化后的日志消息广播给UI等监听者 public static event Action OnLogMessage; /// /// 初始化日志记录器,启动后台写入线程。 /// public static void Initialize() { try { string logDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"); Directory.CreateDirectory(logDirectory); string logFileName = $"Log_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.txt"; string logFilePath = Path.Combine(logDirectory, logFileName); _logFileWriter = new StreamWriter(logFilePath, append: true, encoding: Encoding.UTF8) { AutoFlush = true }; // 创建并启动后台线程 _logWriterThread = new Thread(ProcessLogQueue) { IsBackground = true, // 设置为后台线程,这样主程序退出时它会自动终止 Name = "LogWriterThread" }; _logWriterThread.Start(); Log("日志系统已初始化。"); } catch (Exception ex) { // 如果初始化失败,尝试通过事件通知UI OnLogMessage?.Invoke($"[CRITICAL] 日志系统初始化失败: {ex.Message}"); } } /// /// 将一条日志消息添加到队列中。这个方法是线程安全的,且执行速度非常快。 /// /// 原始日志消息。 public static void Log(string message) { string formattedMessage = $"[{DateTime.Now:HH:mm:ss.fff}] {message}"; _logQueue.Add(formattedMessage); } /// /// 后台线程的工作方法。它会持续不断地从队列中取出消息并处理。 /// private static void ProcessLogQueue() { // GetConsumingEnumerable会阻塞等待,直到有新的项加入队列或队列被标记为已完成 foreach (string message in _logQueue.GetConsumingEnumerable()) { try { // 1. 写入文件 _logFileWriter?.WriteLine(message); // 2. 触发事件,通知UI OnLogMessage?.Invoke(message); } catch { // 忽略在日志线程本身发生的写入错误 } } } /// /// 关闭日志记录器,释放资源。 /// public static void Shutdown() { Log("日志系统正在关闭..."); // 标记队列不再接受新的项目。这会让ProcessLogQueue中的循环在处理完所有剩余项后自然结束。 _logQueue.CompleteAdding(); // 等待日志线程处理完所有剩余的日志,最多等待2秒 _logWriterThread?.Join(2000); // 关闭文件流 _logFileWriter?.Close(); _logFileWriter?.Dispose(); } } }