完成日志的集中管理

This commit is contained in:
2025-09-07 20:35:40 +08:00
parent 3489f8a064
commit af1b67d0a1
8 changed files with 324 additions and 7 deletions

View File

@@ -0,0 +1,25 @@
using System;
namespace DMS.Application.DTOs.Events
{
/// <summary>
/// Nlog日志变更事件参数
/// </summary>
public class NlogChangedEventArgs : DataChangedEventArgs
{
/// <summary>
/// 变更的日志DTO
/// </summary>
public NlogDto Nlog { get; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="changeType">变更类型</param>
/// <param name="nlog">变更的日志DTO</param>
public NlogChangedEventArgs(DataChangeType changeType, NlogDto nlog) : base(changeType)
{
Nlog = nlog;
}
}
}

View File

@@ -261,6 +261,45 @@ public interface IDataCenterService
#endregion #endregion
#region
/// <summary>
/// 异步根据ID获取日志DTO。
/// </summary>
Task<NlogDto> GetNlogByIdAsync(int id);
/// <summary>
/// 异步获取所有日志DTO列表。
/// </summary>
Task<List<NlogDto>> GetAllNlogsAsync();
/// <summary>
/// 异步获取指定数量的最新日志DTO列表。
/// </summary>
Task<List<NlogDto>> GetLatestNlogsAsync(int count);
/// <summary>
/// 异步清空所有日志。
/// </summary>
Task ClearAllNlogsAsync();
/// <summary>
/// 在内存中添加日志
/// </summary>
void AddNlogToMemory(NlogDto nlogDto);
/// <summary>
/// 在内存中更新日志
/// </summary>
void UpdateNlogInMemory(NlogDto nlogDto);
/// <summary>
/// 在内存中删除日志
/// </summary>
void RemoveNlogFromMemory(int nlogId);
#endregion
#region 访 #region 访
/// <summary> /// <summary>
@@ -291,6 +330,11 @@ public interface IDataCenterService
/// 获取所有MQTT服务器的安全字典。 /// 获取所有MQTT服务器的安全字典。
/// </summary> /// </summary>
ConcurrentDictionary<int, MqttServerDto> MqttServers { get; } ConcurrentDictionary<int, MqttServerDto> MqttServers { get; }
/// <summary>
/// 获取所有日志的安全字典。
/// </summary>
ConcurrentDictionary<int, NlogDto> Nlogs { get; }
#endregion #endregion
@@ -325,6 +369,11 @@ public interface IDataCenterService
/// 异步加载所有MQTT服务器数据。 /// 异步加载所有MQTT服务器数据。
/// </summary> /// </summary>
Task<List<MqttServerDto>> LoadAllMqttServersAsync(); Task<List<MqttServerDto>> LoadAllMqttServersAsync();
/// <summary>
/// 异步加载所有日志数据。
/// </summary>
Task<List<NlogDto>> LoadAllNlogsAsync();
#endregion #endregion
@@ -360,6 +409,10 @@ public interface IDataCenterService
/// </summary> /// </summary>
event EventHandler<MqttServerChangedEventArgs> MqttServerChanged; event EventHandler<MqttServerChangedEventArgs> MqttServerChanged;
/// <summary>
/// 当日志数据发生变化时触发
/// </summary>
event EventHandler<NlogChangedEventArgs> NlogChanged;
/// <summary> /// <summary>
/// 当变量值发生变化时触发 /// 当变量值发生变化时触发

View File

@@ -15,7 +15,7 @@ using System.Linq;
namespace DMS.Application.Services; namespace DMS.Application.Services;
/// <summary> /// <summary>
/// 数据中心服务,负责管理所有的数据,包括设备、变量表、变量菜单。 /// 数据中心服务,负责管理所有的数据,包括设备、变量表、变量菜单和日志
/// 实现 <see cref="IDataCenterService"/> 接口。 /// 实现 <see cref="IDataCenterService"/> 接口。
/// </summary> /// </summary>
public class DataCenterService : IDataCenterService public class DataCenterService : IDataCenterService
@@ -27,6 +27,7 @@ public class DataCenterService : IDataCenterService
private readonly IVariableAppService _variableAppService; private readonly IVariableAppService _variableAppService;
private readonly IMenuService _menuService; private readonly IMenuService _menuService;
private readonly IMqttAppService _mqttAppService; private readonly IMqttAppService _mqttAppService;
private readonly INlogAppService _nlogAppService;
/// <summary> /// <summary>
/// 安全字典,用于存储所有设备数据 /// 安全字典,用于存储所有设备数据
@@ -58,6 +59,11 @@ public class DataCenterService : IDataCenterService
/// </summary> /// </summary>
public ConcurrentDictionary<int, MqttServerDto> MqttServers { get; } = new(); public ConcurrentDictionary<int, MqttServerDto> MqttServers { get; } = new();
/// <summary>
/// 安全字典,用于存储所有日志数据
/// </summary>
public ConcurrentDictionary<int, NlogDto> Nlogs { get; } = new();
#region #region
/// <summary> /// <summary>
@@ -90,6 +96,10 @@ public class DataCenterService : IDataCenterService
/// </summary> /// </summary>
public event EventHandler<MqttServerChangedEventArgs> MqttServerChanged; public event EventHandler<MqttServerChangedEventArgs> MqttServerChanged;
/// <summary>
/// 当日志数据发生变化时触发
/// </summary>
public event EventHandler<NlogChangedEventArgs> NlogChanged;
/// <summary> /// <summary>
/// 当变量值发生变化时触发 /// 当变量值发生变化时触发
@@ -108,6 +118,7 @@ public class DataCenterService : IDataCenterService
/// <param name="variableAppService">变量应用服务实例。</param> /// <param name="variableAppService">变量应用服务实例。</param>
/// <param name="menuService">菜单服务实例。</param> /// <param name="menuService">菜单服务实例。</param>
/// <param name="mqttAppService">MQTT应用服务实例。</param> /// <param name="mqttAppService">MQTT应用服务实例。</param>
/// <param name="nlogAppService">Nlog应用服务实例。</param>
public DataCenterService( public DataCenterService(
IRepositoryManager repositoryManager, IRepositoryManager repositoryManager,
IMapper mapper, IMapper mapper,
@@ -115,7 +126,8 @@ public class DataCenterService : IDataCenterService
IVariableTableAppService variableTableAppService, IVariableTableAppService variableTableAppService,
IVariableAppService variableAppService, IVariableAppService variableAppService,
IMenuService menuService, IMenuService menuService,
IMqttAppService mqttAppService) IMqttAppService mqttAppService,
INlogAppService nlogAppService)
{ {
_repositoryManager = repositoryManager; _repositoryManager = repositoryManager;
_mapper = mapper; _mapper = mapper;
@@ -124,6 +136,7 @@ public class DataCenterService : IDataCenterService
_variableAppService = variableAppService; _variableAppService = variableAppService;
_menuService = menuService; _menuService = menuService;
_mqttAppService = mqttAppService; _mqttAppService = mqttAppService;
_nlogAppService = nlogAppService;
} }
#region #region
@@ -644,6 +657,7 @@ public class DataCenterService : IDataCenterService
Menus.Clear(); Menus.Clear();
MenuTrees.Clear(); MenuTrees.Clear();
MqttServers.Clear(); MqttServers.Clear();
Nlogs.Clear();
// 加载所有设备 // 加载所有设备
var devices = await _repositoryManager.Devices.GetAllAsync(); var devices = await _repositoryManager.Devices.GetAllAsync();
@@ -662,6 +676,9 @@ public class DataCenterService : IDataCenterService
var menuDtos = _mapper.Map<List<MenuBeanDto>>(menus); var menuDtos = _mapper.Map<List<MenuBeanDto>>(menus);
var mqttServers = await LoadAllMqttServersAsync(); var mqttServers = await LoadAllMqttServersAsync();
// 加载所有日志
var nlogs = await LoadAllNlogsAsync();
var variableMqttAliases = await _repositoryManager.VariableMqttAliases.GetAllAsync(); var variableMqttAliases = await _repositoryManager.VariableMqttAliases.GetAllAsync();
@@ -696,6 +713,12 @@ public class DataCenterService : IDataCenterService
{ {
MqttServers.TryAdd(mqttServer.Id, mqttServer); MqttServers.TryAdd(mqttServer.Id, mqttServer);
} }
// 加载日志数据到内存
foreach (var nlog in nlogs)
{
Nlogs.TryAdd(nlog.Id, nlog);
}
// 将变量添加到安全字典 // 将变量添加到安全字典
foreach (var variableDto in variableDtos) foreach (var variableDto in variableDtos)
@@ -783,6 +806,14 @@ public class DataCenterService : IDataCenterService
{ {
return await _mqttAppService.GetAllMqttServersAsync(); return await _mqttAppService.GetAllMqttServersAsync();
} }
/// <summary>
/// 异步加载所有日志数据。
/// </summary>
public async Task<List<NlogDto>> LoadAllNlogsAsync()
{
return await _nlogAppService.GetAllLogsAsync();
}
#endregion #endregion
@@ -836,6 +867,14 @@ public class DataCenterService : IDataCenterService
MqttServerChanged?.Invoke(this, e); MqttServerChanged?.Invoke(this, e);
} }
/// <summary>
/// 触发日志变更事件
/// </summary>
protected virtual void OnNlogChanged(NlogChangedEventArgs e)
{
NlogChanged?.Invoke(this, e);
}
/// <summary> /// <summary>
/// 触发变量值变更事件 /// 触发变量值变更事件
@@ -846,7 +885,7 @@ public class DataCenterService : IDataCenterService
} }
#endregion #endregion
#region #region
/// <summary> /// <summary>
@@ -868,4 +907,71 @@ public class DataCenterService : IDataCenterService
} }
#endregion #endregion
#region
/// <summary>
/// 异步根据ID获取日志DTO。
/// </summary>
public async Task<NlogDto> GetNlogByIdAsync(int id)
{
return await _nlogAppService.GetLogByIdAsync(id);
}
/// <summary>
/// 异步获取所有日志DTO列表。
/// </summary>
public async Task<List<NlogDto>> GetAllNlogsAsync()
{
return await _nlogAppService.GetAllLogsAsync();
}
/// <summary>
/// 异步获取指定数量的最新日志DTO列表。
/// </summary>
public async Task<List<NlogDto>> GetLatestNlogsAsync(int count)
{
return await _nlogAppService.GetLatestLogsAsync(count);
}
/// <summary>
/// 异步清空所有日志。
/// </summary>
public async Task ClearAllNlogsAsync()
{
await _nlogAppService.ClearAllLogsAsync();
}
/// <summary>
/// 在内存中添加日志
/// </summary>
public void AddNlogToMemory(NlogDto nlogDto)
{
if (Nlogs.TryAdd(nlogDto.Id, nlogDto))
{
OnNlogChanged(new NlogChangedEventArgs(DataChangeType.Added, nlogDto));
}
}
/// <summary>
/// 在内存中更新日志
/// </summary>
public void UpdateNlogInMemory(NlogDto nlogDto)
{
Nlogs.AddOrUpdate(nlogDto.Id, nlogDto, (key, oldValue) => nlogDto);
OnNlogChanged(new NlogChangedEventArgs(DataChangeType.Updated, nlogDto));
}
/// <summary>
/// 在内存中删除日志
/// </summary>
public void RemoveNlogFromMemory(int nlogId)
{
if (Nlogs.TryRemove(nlogId, out var nlogDto))
{
OnNlogChanged(new NlogChangedEventArgs(DataChangeType.Deleted, nlogDto));
}
}
#endregion
} }

View File

@@ -5,5 +5,6 @@ public enum LoadTypes
Devices, Devices,
Menu, Menu,
Mqtts, Mqtts,
Logs,
All All
} }

View File

@@ -277,7 +277,9 @@ public partial class App : System.Windows.Application
provider.GetRequiredService<IMapper>(), provider.GetRequiredService<IMapper>(),
provider.GetRequiredService<INlogAppService>(), provider.GetRequiredService<INlogAppService>(),
provider.GetRequiredService<IDialogService>(), provider.GetRequiredService<IDialogService>(),
provider.GetRequiredService<INotificationService>() provider.GetRequiredService<INotificationService>(),
provider.GetRequiredService<DataServices>(),
provider.GetRequiredService<IDataCenterService>()
) )
); );
services.AddScoped<MqttServerDetailViewModel>(); services.AddScoped<MqttServerDetailViewModel>();

View File

@@ -12,6 +12,7 @@ using DMS.Core.Models;
using DMS.Message; using DMS.Message;
using DMS.WPF.ViewModels.Items; using DMS.WPF.ViewModels.Items;
using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using ObservableCollections;
namespace DMS.WPF.Services; namespace DMS.WPF.Services;
@@ -50,6 +51,10 @@ public partial class DataServices : ObservableObject, IRecipient<LoadMessage>, I
[ObservableProperty] [ObservableProperty]
private ObservableCollection<MqttServerItemViewModel> _mqttServers; private ObservableCollection<MqttServerItemViewModel> _mqttServers;
// 日志列表。
[ObservableProperty]
private ObservableCollection<NlogItemViewModel> _nlogs;
// 设备列表变更事件,当设备列表数据更新时触发。 // 设备列表变更事件,当设备列表数据更新时触发。
public event Action<List<Device>> OnDeviceListChanged; public event Action<List<Device>> OnDeviceListChanged;
@@ -79,6 +84,37 @@ public partial class DataServices : ObservableObject, IRecipient<LoadMessage>, I
})); }));
} }
/// <summary>
/// 处理日志变更事件
/// </summary>
private void OnNlogChanged(object sender, NlogChangedEventArgs e)
{
// 在UI线程上更新日志
App.Current.Dispatcher.BeginInvoke(new Action(() =>
{
switch (e.ChangeType)
{
case DataChangeType.Added:
Nlogs.Add(_mapper.Map<NlogItemViewModel>(e.Nlog));
break;
case DataChangeType.Updated:
var existingLog = Nlogs.FirstOrDefault(l => l.Id == e.Nlog.Id);
if (existingLog != null)
{
_mapper.Map(e.Nlog, existingLog);
}
break;
case DataChangeType.Deleted:
var logToRemove = Nlogs.FirstOrDefault(l => l.Id == e.Nlog.Id);
if (logToRemove != null)
{
Nlogs.Remove(logToRemove);
}
break;
}
}));
}
/// <summary> /// <summary>
/// DataServices类的构造函数。 /// DataServices类的构造函数。
@@ -98,10 +134,13 @@ public partial class DataServices : ObservableObject, IRecipient<LoadMessage>, I
Menus = new ObservableCollection<MenuItemViewModel>(); Menus = new ObservableCollection<MenuItemViewModel>();
MenuTrees = new ObservableCollection<MenuItemViewModel>(); MenuTrees = new ObservableCollection<MenuItemViewModel>();
MqttServers = new ObservableCollection<MqttServerItemViewModel>(); MqttServers = new ObservableCollection<MqttServerItemViewModel>();
Nlogs = new ObservableCollection<NlogItemViewModel>();
// 监听变量值变更事件 // 监听变量值变更事件
_dataCenterService.VariableValueChanged += OnVariableValueChanged; _dataCenterService.VariableValueChanged += OnVariableValueChanged;
_dataCenterService.OnLoadDataCompleted += OnLoadDataCompleted; _dataCenterService.OnLoadDataCompleted += OnLoadDataCompleted;
// 监听日志变更事件
_dataCenterService.NlogChanged += OnNlogChanged;
// 注册消息接收 // 注册消息接收
// WeakReferenceMessenger.Register<LoadMessage>(this, (r, m) => r.Receive(m)); // WeakReferenceMessenger.Register<LoadMessage>(this, (r, m) => r.Receive(m));
@@ -144,6 +183,9 @@ public partial class DataServices : ObservableObject, IRecipient<LoadMessage>, I
// 加载MQTT服务器数据 // 加载MQTT服务器数据
MqttServers = _mapper.Map<ObservableCollection<MqttServerItemViewModel>>(_dataCenterService.MqttServers.Values); MqttServers = _mapper.Map<ObservableCollection<MqttServerItemViewModel>>(_dataCenterService.MqttServers.Values);
// 加载日志数据
Nlogs = _mapper.Map<ObservableCollection<NlogItemViewModel>>(_dataCenterService.Nlogs.Values);
BuildMenuTrees(); BuildMenuTrees();
} }
@@ -477,6 +519,9 @@ public partial class DataServices : ObservableObject, IRecipient<LoadMessage>, I
case LoadTypes.Mqtts: case LoadTypes.Mqtts:
_ = Task.Run(async () => await LoadMqttServers(_mqttAppService)); _ = Task.Run(async () => await LoadMqttServers(_mqttAppService));
break; break;
case LoadTypes.Logs:
// 日志数据已在IDataCenterService中处理
break;
case LoadTypes.All: case LoadTypes.All:
// 加载所有数据 // 加载所有数据
LoadAllDatas(); LoadAllDatas();

View File

@@ -7,6 +7,11 @@ public class NlogItemViewModel : ObservableObject
{ {
private Nlog _nlog; private Nlog _nlog;
public NlogItemViewModel()
{
_nlog = new Nlog();
}
public NlogItemViewModel(Nlog nlog) public NlogItemViewModel(Nlog nlog)
{ {
_nlog = nlog; _nlog = nlog;

View File

@@ -15,15 +15,19 @@ using DMS.WPF.ViewModels.Dialogs;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System; using System;
using DMS.WPF.Services;
using DMS.Application.DTOs.Events;
namespace DMS.WPF.ViewModels; namespace DMS.WPF.ViewModels;
partial class LogHistoryViewModel : ViewModelBase partial class LogHistoryViewModel : ViewModelBase,IDisposable
{ {
public DataServices DataServices { get; }
private readonly IMapper _mapper; private readonly IMapper _mapper;
private readonly INlogAppService _nlogAppService; private readonly INlogAppService _nlogAppService;
private readonly IDialogService _dialogService; private readonly IDialogService _dialogService;
private readonly INotificationService _notificationService; private readonly INotificationService _notificationService;
private readonly IDataCenterService _dataCenterService;
[ObservableProperty] [ObservableProperty]
private NlogItemViewModel _selectedLog; private NlogItemViewModel _selectedLog;
@@ -43,16 +47,85 @@ partial class LogHistoryViewModel : ViewModelBase
public ObservableCollection<string> LogLevels { get; } = new ObservableCollection<string> { "Trace", "Debug", "Info", "Warn", "Error", "Fatal" }; public ObservableCollection<string> LogLevels { get; } = new ObservableCollection<string> { "Trace", "Debug", "Info", "Warn", "Error", "Fatal" };
public LogHistoryViewModel(IMapper mapper, INlogAppService nlogAppService, IDialogService dialogService, INotificationService notificationService) public LogHistoryViewModel(IMapper mapper, INlogAppService nlogAppService, IDialogService dialogService,
INotificationService notificationService, DataServices dataServices, IDataCenterService dataCenterService)
{ {
_mapper = mapper; _mapper = mapper;
_nlogAppService = nlogAppService; _nlogAppService = nlogAppService;
_dialogService = dialogService; _dialogService = dialogService;
_notificationService = notificationService; _notificationService = notificationService;
DataServices = dataServices;
_dataCenterService = dataCenterService;
_logItemList = new ObservableList<NlogItemViewModel>(); _logItemList = new ObservableList<NlogItemViewModel>(DataServices.Nlogs);
_synchronizedView = _logItemList.CreateView(v => v); _synchronizedView = _logItemList.CreateView(v => v);
LogItemListView = _synchronizedView.ToNotifyCollectionChanged(); LogItemListView = _synchronizedView.ToNotifyCollectionChanged();
// 订阅日志变更事件
_dataCenterService.NlogChanged += OnNlogChanged;
}
/// <summary>
/// 处理日志变更事件
/// </summary>
private void OnNlogChanged(object sender, NlogChangedEventArgs e)
{
// 在UI线程上更新日志
App.Current.Dispatcher.BeginInvoke(new Action(() =>
{
switch (e.ChangeType)
{
case DataChangeType.Added:
var newLogItem = new NlogItemViewModel(new Nlog
{
Id = e.Nlog.Id,
LogTime = e.Nlog.LogTime,
Level = e.Nlog.Level,
ThreadId = e.Nlog.ThreadId,
ThreadName = e.Nlog.ThreadName,
Callsite = e.Nlog.Callsite,
CallsiteLineNumber = e.Nlog.CallsiteLineNumber,
Message = e.Nlog.Message,
Logger = e.Nlog.Logger,
Exception = e.Nlog.Exception,
CallerFilePath = e.Nlog.CallerFilePath,
CallerLineNumber = e.Nlog.CallerLineNumber,
CallerMember = e.Nlog.CallerMember
});
_logItemList.Add(newLogItem);
break;
case DataChangeType.Updated:
var existingLog = _logItemList.FirstOrDefault(l => l.Id == e.Nlog.Id);
if (existingLog != null)
{
existingLog = new NlogItemViewModel(new Nlog
{
Id = e.Nlog.Id,
LogTime = e.Nlog.LogTime,
Level = e.Nlog.Level,
ThreadId = e.Nlog.ThreadId,
ThreadName = e.Nlog.ThreadName,
Callsite = e.Nlog.Callsite,
CallsiteLineNumber = e.Nlog.CallsiteLineNumber,
Message = e.Nlog.Message,
Logger = e.Nlog.Logger,
Exception = e.Nlog.Exception,
CallerFilePath = e.Nlog.CallerFilePath,
CallerLineNumber = e.Nlog.CallerLineNumber,
CallerMember = e.Nlog.CallerMember
});
}
break;
case DataChangeType.Deleted:
var logToRemove = _logItemList.FirstOrDefault(l => l.Id == e.Nlog.Id);
if (logToRemove != null)
{
_logItemList.Remove(logToRemove);
}
break;
}
}));
} }
private bool FilterLogs(NlogItemViewModel item) private bool FilterLogs(NlogItemViewModel item)
@@ -165,4 +238,11 @@ partial class LogHistoryViewModel : ViewModelBase
_notificationService.ShowError($"加载日志时发生错误: {ex.Message}", ex); _notificationService.ShowError($"加载日志时发生错误: {ex.Message}", ex);
} }
} }
public void Dispose()
{
// 取消订阅事件
_dataCenterService.NlogChanged -= OnNlogChanged;
}
} }