using HslCommunication.LogNet; using System.Collections.Concurrent; using System.IO; using WinFormsApp.Utils; namespace guoke { /// /// 日志服务 /// public class LogService { public static LogService Log; // 按照文件大小切割日志,指定10M,不限制日志文件数量 public ILogNet logNet { get; set; } public LogService() { LogConfigModel logConfig = new LogConfigModel(); //构建配置 logConfig = ConfigReader.GetObject("Logs"); //创建日志实例 logNet = new LogNetFileSize(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, logConfig.LogFilePath), logConfig.MaxFileSize * 1024 * 1024, logConfig.MaxArchiveFiles); logNet.SetMessageDegree(logConfig.LogLevel); // 如果所有的日志在记录之前需要在控制台显示出来 logNet.BeforeSaveToFile += (object sender, HslEventArgs e) => { Console.WriteLine(e.HslMessage.ToString()); }; Log = this; Log.Info("日志", $"等级:{logConfig.LogLevel},大小:{logConfig.MaxFileSize * 1024 * 1024}B,数量:{logConfig.MaxArchiveFiles}"); } #region 时间 // 使用并发字典替代普通字典+锁,提高并发性能 private static readonly ConcurrentDictionary _loggedMessages = new ConcurrentDictionary(); // 过期时间配置为60秒 private static TimeSpan _expirationTime = TimeSpan.FromSeconds(60); // 上次清理时间 private static DateTime _lastCleanupTime = DateTime.MinValue; // 清理间隔设置为过期时间的一半,平衡性能和内存使用 private static TimeSpan _cleanupInterval = TimeSpan.FromSeconds(30); /// /// 记录错误日志(带时间控制) /// /// 日志消息 public void ErrorTime(string key, string message, bool log = true) => LogWithTimeControl(key, message, Error, log); /// /// 记录警告日志(带时间控制) /// /// 日志消息 public void WarnTime(string key, string message, bool log = true) => LogWithTimeControl(key, message, Warn, log); /// /// 记录警告日志(带时间控制) /// /// 日志消息 public void InfoTime(string key, string message, bool log = true) => LogWithTimeControl(key, message, Info, log); // 带时间控制的通用日志记录方法 private void LogWithTimeControl(string key, string message, Action logAction, bool log) { if (log) { TryCleanupExpiredMessages(); // 检查消息是否已记录且未过期 if (_loggedMessages.TryGetValue(message, out var lastLoggedTime) && (DateTime.Now - lastLoggedTime) <= _expirationTime) { return; } // 记录日志并更新记录时间 logAction($"T:{key}", message); _loggedMessages.AddOrUpdate(message, DateTime.Now, (_, __) => DateTime.Now); } } // 尝试清理过期消息 private static void TryCleanupExpiredMessages() { var now = DateTime.Now; // 检查是否达到清理间隔 if ((now - _lastCleanupTime) < _cleanupInterval) { return; } // 获取所有过期键 var expiredKeys = _loggedMessages .Where(kv => (now - kv.Value) > _expirationTime) .Select(kv => kv.Key) .ToList(); // 移除过期键 foreach (var key in expiredKeys) { _loggedMessages.TryRemove(key, out _); } _lastCleanupTime = now; } #endregion public void String(string message) { logNet.WriteAnyString($"mes:{message}");// 写任意的数据,不受格式化影响 } public void Debug(string message) { logNet.WriteDebug(message); } public void Info(string message) { logNet.WriteInfo(message); } public void Warn(string message) { logNet.WriteWarn(message); } public void Error(string message) { logNet.WriteError(message); } public void Fatal(string message) { logNet.WriteFatal(message); } public void Debug(string key, string message) { logNet.WriteDebug(key,message); } public void Info(string key, string message) { logNet.WriteInfo(key, message); } public void Warn(string key, string message) { logNet.WriteWarn(key, message); } public void Error(string key, string message) { logNet.WriteError(key, message); } public void Warn(string key, string message,bool log=true) { if (log) logNet.WriteWarn(key, message); } public void Error(string key, string message, bool log = true) { if (log) logNet.WriteError(key, message); } public void Fatal(string key, string message, bool log = true) { if (log) logNet.WriteFatal(key, message); } /// /// 获取日志文件列表 /// /// /// /// private List GetFileNamesWithoutExtension(string folderPath, string fileExtension) { List fileNames = new List(); try { // 检查文件夹是否存在 if (Directory.Exists(folderPath)) { // 获取指定文件夹内指定后缀的所有文件 string[] files = Directory.GetFiles(folderPath, $"*.{fileExtension}"); foreach (string file in files) { // 获取不包含后缀的文件名 string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file); fileNames.Add(fileNameWithoutExtension); } } else { Warn("日志","指定的文件夹不存在"); } } catch (Exception e) { Error("日志",$"发生错误:{e.Message}"); } return fileNames; } /// /// 读取日志 /// /// /// private static List ParseLogFile(string filePath) { List logs = new List(); string currentLog = string.Empty; foreach (var line in File.ReadLines(filePath)) { if (line.Contains("[信息]") || line.Contains("[错误]") || line.Contains("[调试]") || line.Contains("[警告]")) { if (!string.IsNullOrEmpty(currentLog)) { logs.Add(currentLog); } currentLog = line; } else { if (!string.IsNullOrEmpty(currentLog)) { currentLog += Environment.NewLine + line; } } } // 添加最后一个日志条目 if (!string.IsNullOrEmpty(currentLog)) { logs.Add(currentLog); } return logs; } } /// /// 日志配置模型 /// public class LogConfigModel { // 日志文件的最大大小(以m为单位) public int MaxFileSize { get; set; } = 1; // 允许的最大存档文件数量 public int MaxArchiveFiles { get; set; } = 100; /// /// 日志文件路径 /// public string LogFilePath { get; set; } = "logs"; // 日志记录的最低等级 public HslMessageDegree LogLevel { get; set; }= HslMessageDegree.DEBUG; } }