113 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			113 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| 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
 | ||
| {
 | ||
|     /// <summary>
 | ||
|     /// 一个线程安全的、基于队列的日志记录器。
 | ||
|     /// 使用一个独立的后台线程来处理文件写入,避免业务线程阻塞。
 | ||
|     /// </summary>
 | ||
|     public static class ThreadSafeLogger
 | ||
|     {
 | ||
|         // 使用线程安全的队列作为日志消息的缓冲区
 | ||
|         private static readonly BlockingCollection<string> _logQueue = new BlockingCollection<string>();
 | ||
| 
 | ||
|         // 日志写入线程
 | ||
|         private static Thread _logWriterThread;
 | ||
| 
 | ||
|         private static StreamWriter _logFileWriter;
 | ||
| 
 | ||
|         // 事件,用于将格式化后的日志消息广播给UI等监听者
 | ||
|         public static event Action<string> OnLogMessage;
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 初始化日志记录器,启动后台写入线程。
 | ||
|         /// </summary>
 | ||
|         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}");
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 将一条日志消息添加到队列中。这个方法是线程安全的,且执行速度非常快。
 | ||
|         /// </summary>
 | ||
|         /// <param name="message">原始日志消息。</param>
 | ||
|         public static void Log(string message)
 | ||
|         {
 | ||
|             string formattedMessage = $"[{DateTime.Now:HH:mm:ss.fff}] {message}";
 | ||
|             _logQueue.Add(formattedMessage);
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 后台线程的工作方法。它会持续不断地从队列中取出消息并处理。
 | ||
|         /// </summary>
 | ||
|         private static void ProcessLogQueue()
 | ||
|         {
 | ||
|             // GetConsumingEnumerable会阻塞等待,直到有新的项加入队列或队列被标记为已完成
 | ||
|             foreach (string message in _logQueue.GetConsumingEnumerable())
 | ||
|             {
 | ||
|                 try
 | ||
|                 {
 | ||
|                     // 1. 写入文件
 | ||
|                     _logFileWriter?.WriteLine(message);
 | ||
| 
 | ||
|                     // 2. 触发事件,通知UI
 | ||
|                     OnLogMessage?.Invoke(message);
 | ||
|                 }
 | ||
|                 catch
 | ||
|                 {
 | ||
|                     // 忽略在日志线程本身发生的写入错误
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 关闭日志记录器,释放资源。
 | ||
|         /// </summary>
 | ||
|         public static void Shutdown()
 | ||
|         {
 | ||
|             Log("日志系统正在关闭...");
 | ||
| 
 | ||
|             // 标记队列不再接受新的项目。这会让ProcessLogQueue中的循环在处理完所有剩余项后自然结束。
 | ||
|             _logQueue.CompleteAdding();
 | ||
| 
 | ||
|             // 等待日志线程处理完所有剩余的日志,最多等待2秒
 | ||
|             _logWriterThread?.Join(2000);
 | ||
| 
 | ||
|             // 关闭文件流
 | ||
|             _logFileWriter?.Close();
 | ||
|             _logFileWriter?.Dispose();
 | ||
|         }
 | ||
|     }
 | ||
| }
 |