WpfApp/Services/LogService.cs

254 lines
8.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using HslCommunication.LogNet;
using System.Collections.Concurrent;
using System.IO;
using WinFormsApp.Utils;
namespace guoke
{
/// <summary>
/// 日志服务
/// </summary>
public class LogService
{
public static LogService Log;
// 按照文件大小切割日志指定10M不限制日志文件数量
public ILogNet logNet { get; set; }
public LogService()
{
LogConfigModel logConfig = new LogConfigModel();
//构建配置
logConfig = ConfigReader.GetObject<LogConfigModel>("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<string, DateTime> _loggedMessages =
new ConcurrentDictionary<string, DateTime>();
// 过期时间配置为60秒
private static TimeSpan _expirationTime = TimeSpan.FromSeconds(60);
// 上次清理时间
private static DateTime _lastCleanupTime = DateTime.MinValue;
// 清理间隔设置为过期时间的一半,平衡性能和内存使用
private static TimeSpan _cleanupInterval = TimeSpan.FromSeconds(30);
/// <summary>
/// 记录错误日志(带时间控制)
/// </summary>
/// <param name="message">日志消息</param>
public void ErrorTime(string key, string message, bool log = true) => LogWithTimeControl(key, message, Error, log);
/// <summary>
/// 记录警告日志(带时间控制)
/// </summary>
/// <param name="message">日志消息</param>
public void WarnTime(string key, string message, bool log = true) => LogWithTimeControl(key, message, Warn, log);
/// <summary>
/// 记录警告日志(带时间控制)
/// </summary>
/// <param name="message">日志消息</param>
public void InfoTime(string key, string message, bool log = true) => LogWithTimeControl(key, message, Info, log);
// 带时间控制的通用日志记录方法
private void LogWithTimeControl(string key, string message, Action<string, string> 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);
}
/// <summary>
/// 获取日志文件列表
/// </summary>
/// <param name="folderPath"></param>
/// <param name="fileExtension"></param>
/// <returns></returns>
private List<string> GetFileNamesWithoutExtension(string folderPath, string fileExtension)
{
List<string> fileNames = new List<string>();
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;
}
/// <summary>
/// 读取日志
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
private static List<string> ParseLogFile(string filePath)
{
List<string> logs = new List<string>();
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;
}
}
/// <summary>
/// 日志配置模型
/// </summary>
public class LogConfigModel
{
// 日志文件的最大大小以m为单位
public int MaxFileSize { get; set; } = 1;
// 允许的最大存档文件数量
public int MaxArchiveFiles { get; set; } = 100;
/// <summary>
/// 日志文件路径
/// </summary>
public string LogFilePath { get; set; } = "logs";
// 日志记录的最低等级
public HslMessageDegree LogLevel { get; set; }= HslMessageDegree.DEBUG;
}
}