log日志bug修改

This commit is contained in:
hsc
2026-06-24 10:18:54 +08:00
parent c4470af013
commit 4deb785135
16 changed files with 169 additions and 101 deletions

View File

@@ -59,6 +59,10 @@ namespace ADP
} }
protected override void OnInitialized() protected override void OnInitialized()
{ {
// 配置全局日志分发器:按 CurrentScope 路由到对应 LogArea
var globalInfo = Container.Resolve<GlobalInfo>();
LoggerHelper.Progress = new ScopeLogDispatcher(globalInfo);
//初始化数据库 //初始化数据库
//DatabaseConfig.SetTenant(10001); //DatabaseConfig.SetTenant(10001);
//DatabaseConfig.InitMySql("127.0.0.1",3306,"ADP","root","123456"); //DatabaseConfig.InitMySql("127.0.0.1",3306,"ADP","root","123456");

View File

@@ -6,6 +6,7 @@ using Notifications.Wpf.Core;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
@@ -226,7 +227,7 @@ namespace ADP.ViewModels
if (targetContext.RunState == "运行") if (targetContext.RunState == "运行")
{ {
targetContext.SingleStep = false; targetContext.SingleStep = false;
LoggerHelper.InfoWithNotify($"{_globalInfo.UserName} 执行工位 [{runningScope}] 运行命令"); LoggerHelper.InfoWithNotify(runningScope, $"{_globalInfo.UserName} 执行工位 [{runningScope}] 运行命令");
targetContext.RunState = "暂停"; targetContext.RunState = "暂停";
targetContext.RunIcon = PackIconKind.Pause; targetContext.RunIcon = PackIconKind.Pause;
@@ -252,7 +253,7 @@ namespace ADP.ViewModels
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.ErrorWithNotify($"工位 [{runningScope}] 异常中止: {ex.Message}"); LoggerHelper.ErrorWithNotify(runningScope, $"工位 [{runningScope}] 异常中止: {ex.Message}");
} }
// 💡 测试正常完毕或取消:停止当前工位的 SW并将最终时间固化到 RunningTime 字段中 // 💡 测试正常完毕或取消:停止当前工位的 SW并将最终时间固化到 RunningTime 字段中
@@ -285,7 +286,7 @@ namespace ADP.ViewModels
} }
else // 用户点击了暂停 else // 用户点击了暂停
{ {
LoggerHelper.InfoWithNotify($"{_globalInfo.UserName} 点击工位 [{runningScope}] 暂停命令"); LoggerHelper.InfoWithNotify(runningScope, $"{_globalInfo.UserName} 点击工位 [{runningScope}] 暂停命令");
targetContext.SingleStep = true; targetContext.SingleStep = true;
targetContext.IsStop = true; targetContext.IsStop = true;
targetContext.RunState = "运行"; targetContext.RunState = "运行";
@@ -308,7 +309,7 @@ namespace ADP.ViewModels
if (targetContext.RunState == "运行") if (targetContext.RunState == "运行")
{ {
targetContext.SingleStep = true; targetContext.SingleStep = true;
LoggerHelper.InfoWithNotify($"{_globalInfo.UserName} 执行工位 [{runningScope}] 单步执行命令"); LoggerHelper.InfoWithNotify(runningScope, $"{_globalInfo.UserName} 执行工位 [{runningScope}] 单步执行命令");
targetContext.RunState = "暂停"; targetContext.RunState = "暂停";
targetContext.RunIcon = PackIconKind.Pause; targetContext.RunIcon = PackIconKind.Pause;
@@ -334,7 +335,7 @@ namespace ADP.ViewModels
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.ErrorWithNotify($"工位 [{runningScope}] 单步执行异常: {ex.Message}"); LoggerHelper.ErrorWithNotify(runningScope, $"工位 [{runningScope}] 单步执行异常: {ex.Message}");
} }
// 💡 单步单步完成后会被 StepRunning 挂起,在此暂时停止 SW // 💡 单步单步完成后会被 StepRunning 挂起,在此暂时停止 SW
@@ -378,7 +379,7 @@ namespace ADP.ViewModels
return; return;
} }
LoggerHelper.InfoWithNotify($"{_globalInfo.UserName} 执行工位 [{runningScope}] 复位命令"); LoggerHelper.InfoWithNotify(runningScope, $"{_globalInfo.UserName} 执行工位 [{runningScope}] 复位命令");
_executionTasks.TryGetValue(runningScope, out var currentTask); _executionTasks.TryGetValue(runningScope, out var currentTask);
_errorExecutionTasks.TryGetValue(runningScope, out var errorTask); _errorExecutionTasks.TryGetValue(runningScope, out var errorTask);
@@ -428,7 +429,7 @@ namespace ADP.ViewModels
return; return;
} }
LoggerHelper.InfoWithNotify($"{_globalInfo.UserName} 执行工位 [{runningScope}] 异常流程命令"); LoggerHelper.InfoWithNotify(runningScope, $"{_globalInfo.UserName} 执行工位 [{runningScope}] 异常流程命令");
// 💡 异常测试启动计时 // 💡 异常测试启动计时
targetContext.SW.Start(); targetContext.SW.Start();
@@ -445,7 +446,7 @@ namespace ADP.ViewModels
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.ErrorWithNotify($"工位 [{runningScope}] 异常流程执行出错: {ex.Message}"); LoggerHelper.ErrorWithNotify(runningScope, $"工位 [{runningScope}] 异常流程执行出错: {ex.Message}");
} }
// 💡 异常测试结束停止计时 // 💡 异常测试结束停止计时
@@ -479,7 +480,7 @@ namespace ADP.ViewModels
{ {
CurrentConfig.DefaultProgramFilePath = targetContext.CurrentFilePath; CurrentConfig.DefaultProgramFilePath = targetContext.CurrentFilePath;
ConfigService.Save(CurrentConfig); ConfigService.Save(CurrentConfig);
LoggerHelper.SuccessWithNotify($"工位 [{runningScope}] 已成功将当前程序设为默认启动程序"); LoggerHelper.SuccessWithNotify(runningScope, $"工位 [{runningScope}] 已成功将当前程序设为默认启动程序");
} }
} }
@@ -505,7 +506,7 @@ namespace ADP.ViewModels
} }
targetContext.Program.Parameters.Add(item); targetContext.Program.Parameters.Add(item);
} }
LoggerHelper.InfoWithNotify($"工位 [{runningScope}] 创建了空程序文件"); LoggerHelper.InfoWithNotify(runningScope, $"工位 [{runningScope}] 创建了空程序文件");
// 如果当前正看着该工位,刷新 UI 显示 // 如果当前正看着该工位,刷新 UI 显示
if (_globalInfo.CurrentScope == runningScope) RefreshAllContextProperties(); if (_globalInfo.CurrentScope == runningScope) RefreshAllContextProperties();
@@ -539,7 +540,7 @@ namespace ADP.ViewModels
// 确认文件存在 // 确认文件存在
if (!File.Exists(filePath)) if (!File.Exists(filePath))
{ {
LoggerHelper.ErrorWithNotify($"文件不存在: {filePath}"); LoggerHelper.ErrorWithNotify(runningScope, $"文件不存在: {filePath}");
return; return;
} }
@@ -551,7 +552,7 @@ namespace ADP.ViewModels
if (program == null) if (program == null)
{ {
LoggerHelper.WarnWithNotify($"文件格式不正确或为空: {filePath}"); LoggerHelper.WarnWithNotify(runningScope, $"文件格式不正确或为空: {filePath}");
return; return;
} }
@@ -571,7 +572,7 @@ namespace ADP.ViewModels
} }
} }
LoggerHelper.SuccessWithNotify($"工位 [{runningScope}] 成功打开文件: {filePath}"); LoggerHelper.SuccessWithNotify(runningScope, $"工位 [{runningScope}] 成功打开文件: {filePath}");
// 💡 3. 安全调用异步复位,确保重置的是对应工位的数据 // 💡 3. 安全调用异步复位,确保重置的是对应工位的数据
// 注意:由于在 OnRestoration 内部第一行也做了快照拦截, // 注意:由于在 OnRestoration 内部第一行也做了快照拦截,
@@ -580,7 +581,7 @@ namespace ADP.ViewModels
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.ErrorWithNotify($"工位 [{runningScope}] 打开文件失败: {ex.Message}"); LoggerHelper.ErrorWithNotify(runningScope, $"工位 [{runningScope}] 打开文件失败: {ex.Message}");
} }
finally finally
{ {
@@ -619,7 +620,7 @@ namespace ADP.ViewModels
// 💡 3. 调用你的底层文件保存逻辑,传入快照工位的 Program 模型 // 💡 3. 调用你的底层文件保存逻辑,传入快照工位的 Program 模型
SaveProgramToFile(targetContext.CurrentFilePath, targetContext.Program); SaveProgramToFile(targetContext.CurrentFilePath, targetContext.Program);
LoggerHelper.InfoWithNotify($"{_globalInfo.UserName} 另存为文件成功: {saveFileDialog.FileName}"); LoggerHelper.InfoWithNotify(runningScope, $"{_globalInfo.UserName} 另存为文件成功: {saveFileDialog.FileName}");
if (_globalInfo.CurrentScope == runningScope) RefreshAllContextProperties(); if (_globalInfo.CurrentScope == runningScope) RefreshAllContextProperties();
} }
@@ -644,7 +645,7 @@ namespace ADP.ViewModels
// 💡 3. 持久化当前快照工位的 Program // 💡 3. 持久化当前快照工位的 Program
SaveProgramToFile(targetContext.CurrentFilePath, targetContext.Program); SaveProgramToFile(targetContext.CurrentFilePath, targetContext.Program);
LoggerHelper.SuccessWithNotify($"工位 [{runningScope}] 程序保存成功!"); LoggerHelper.SuccessWithNotify(_globalInfo.CurrentScope,$"工位 [{runningScope}] 程序保存成功!");
} }
// 💡 辅助方法:建议将你的通用序列化落盘代码调整为接收 ProgramVM 参数,提高复用性 // 💡 辅助方法:建议将你的通用序列化落盘代码调整为接收 ProgramVM 参数,提高复用性
@@ -657,7 +658,7 @@ namespace ADP.ViewModels
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.ErrorWithNotify($"写入程序文件失败: {ex.Message}"); LoggerHelper.ErrorWithNotify(_globalInfo.CurrentScope,$"写入程序文件失败: {ex.Message}");
} }
} }

View File

@@ -10,4 +10,10 @@
<PackageReference Include="NLog" Version="6.1.3" /> <PackageReference Include="NLog" Version="6.1.3" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Update="Nlog.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project> </Project>

View File

@@ -12,23 +12,23 @@ namespace Logger
{ {
public static readonly ILogger Logger = LogManager.GetLogger("InfoLogger"); public static readonly ILogger Logger = LogManager.GetLogger("InfoLogger");
public static readonly ILogger sqlLogger = LogManager.GetLogger("SqlLogger"); public static readonly ILogger sqlLogger = LogManager.GetLogger("SqlLogger");
public static IProgress<(string message, string color, int depth)> Progress { get; set; } public static IProgress<(string scope, string message, string color, int depth)> Progress { get; set; }
static LoggerHelper() static LoggerHelper()
{ {
Progress = new Progress<(string message, string color, int depth)>(); Progress = new Progress<(string scope, string message, string color, int depth)>();
} }
public static void InfoWithNotify(string message, int depth = 0) public static void InfoWithNotify(string scope, string message, int depth = 0)
{
Logger.Info(message); // 写入 NLog
NotifyUI(message, "blue", depth); // 触发UI显示
}
public static void SuccessWithNotify(string message, int depth = 0)
{ {
Logger.Info(message); Logger.Info(message);
NotifyUI(message, "lightgreen", depth); NotifyUI(scope, message, "blue", depth);
} }
public static void WarnWithNotify(string message, string stackTrace = null, int depth = 0)
public static void SuccessWithNotify(string scope, string message, int depth = 0)
{
Logger.Info(message);
NotifyUI(scope, message, "lightgreen", depth);
}
public static void WarnWithNotify(string scope, string message, string stackTrace = null, int depth = 0)
{ {
if (!string.IsNullOrEmpty(stackTrace)) if (!string.IsNullOrEmpty(stackTrace))
{ {
@@ -37,10 +37,10 @@ namespace Logger
} }
Logger.Warn(message); Logger.Warn(message);
NotifyUI(message, "orange", depth); NotifyUI(scope, message, "orange", depth);
} }
public static void ErrorWithNotify(string message, string stackTrace = null, int depth = 0) public static void ErrorWithNotify(string scope, string message, string stackTrace = null, int depth = 0)
{ {
if (!string.IsNullOrEmpty(stackTrace)) if (!string.IsNullOrEmpty(stackTrace))
{ {
@@ -49,11 +49,11 @@ namespace Logger
} }
Logger.Error(message); Logger.Error(message);
NotifyUI(message, "red", depth); NotifyUI(scope, message, "red", depth);
} }
private static void NotifyUI(string message, string color, int depth) private static void NotifyUI(string scope, string message, string color, int depth)
{ {
Progress.Report((message, color, depth)); Progress.Report((scope, message, color, depth));
} }
public static void Info(string message, int depth = 0) public static void Info(string message, int depth = 0)
@@ -95,20 +95,18 @@ namespace Logger
foreach (var line in lines) foreach (var line in lines)
{ {
// 匹配你项目的命名空间路径
if (line.Contains("ADP")) if (line.Contains("ADP"))
{ {
// 提取 "in 文件路径:line 行号"
var match = Regex.Match(line, @"in (.+?):line (\d+)"); var match = Regex.Match(line, @"in (.+?):line (\d+)");
if (match.Success) if (match.Success)
{ {
return match.Value; // 返回类似 C:\...\MainViewModel.cs:line 37 return match.Value;
} }
return line.Trim(); return line.Trim();
} }
} }
return lines[0].Trim(); // 如果找不到就返回第一条 return lines[0].Trim();
} }
} }
} }

View File

@@ -110,7 +110,7 @@ namespace MainModule.ViewModels
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LoggerHelper.ErrorWithNotify($"卸载机台 [{TestStatus}] 全局引用或资源失败: {ex.Message}"); Logger.LoggerHelper.ErrorWithNotify(TestStatus, $"卸载机台 [{TestStatus}] 全局引用或资源失败: {ex.Message}");
} }
finally finally
{ {
@@ -164,7 +164,7 @@ namespace MainModule.ViewModels
if (program == null) if (program == null)
{ {
LoggerHelper.WarnWithNotify($"文件格式不正确或为空: {filePath}"); LoggerHelper.WarnWithNotify(_globalInfo.CurrentScope, $"文件格式不正确或为空: {filePath}");
return; return;
} }

View File

@@ -217,7 +217,7 @@ namespace MonitorModule.ViewModels
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.ErrorWithNotify($"加载数据表失败:{ex.Message}"); LoggerHelper.ErrorWithNotify(_globalInfo.CurrentScope,$"加载数据表失败:{ex.Message}");
StatusMessage = $"加载失败:{ex.Message}"; StatusMessage = $"加载失败:{ex.Message}";
} }
} }
@@ -256,7 +256,7 @@ namespace MonitorModule.ViewModels
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.ErrorWithNotify($"查询失败:{ex.Message}"); LoggerHelper.ErrorWithNotify(TestStatus,$"查询失败:{ex.Message}");
StatusMessage = $"查询失败:{ex.Message}"; StatusMessage = $"查询失败:{ex.Message}";
ResultTable = new DataTable(); ResultTable = new DataTable();
TotalCount = 0; TotalCount = 0;
@@ -295,11 +295,11 @@ namespace MonitorModule.ViewModels
WriteCsv(dlg.FileName, dt); WriteCsv(dlg.FileName, dt);
StatusMessage = $"导出完成:{dlg.FileName}{dt.Rows.Count} 行)"; StatusMessage = $"导出完成:{dlg.FileName}{dt.Rows.Count} 行)";
LoggerHelper.InfoWithNotify($"工位 [{TestStatus}] 导出 [{SelectedTable}] 至 {dlg.FileName},共 {dt.Rows.Count} 行"); LoggerHelper.InfoWithNotify(TestStatus, $"工位 [{TestStatus}] 导出 [{SelectedTable}] 至 {dlg.FileName},共 {dt.Rows.Count} 行");
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.ErrorWithNotify($"导出失败:{ex.Message}"); LoggerHelper.ErrorWithNotify(TestStatus, $"导出失败:{ex.Message}");
StatusMessage = $"导出失败:{ex.Message}"; StatusMessage = $"导出失败:{ex.Message}";
} }
} }

View File

@@ -101,7 +101,7 @@ namespace SettingModule.ViewModels
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LoggerHelper.ErrorWithNotify($"释放配置管理组件SettingViewModel资源失败: {ex.Message}"); Logger.LoggerHelper.ErrorWithNotify(TestStatus,$"释放配置管理组件SettingViewModel资源失败: {ex.Message}");
} }
} }

View File

@@ -210,7 +210,7 @@ namespace TestingModule.ViewModels
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.WarnWithNotify($"无法加载程序集 {Path.GetFileName(dllPath)}: {ex.Message}"); LoggerHelper.WarnWithNotify(_globalInfo.CurrentScope, $"无法加载程序集 {Path.GetFileName(dllPath)}: {ex.Message}");
} }
} }
} }
@@ -237,7 +237,7 @@ namespace TestingModule.ViewModels
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.WarnWithNotify($"加载子程序错误: {filePath} - {ex.Message}"); LoggerHelper.WarnWithNotify(_globalInfo.CurrentScope, $"加载子程序错误: {filePath} - {ex.Message}");
} }
} }
} }
@@ -317,7 +317,7 @@ namespace TestingModule.ViewModels
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.ErrorWithNotify($"加载类型错误: {assembly.FullName} - {ex.Message}"); LoggerHelper.ErrorWithNotify(_globalInfo.CurrentScope, $"加载类型错误: {assembly.FullName} - {ex.Message}");
} }
if (validTypes.Count > 0) if (validTypes.Count > 0)
@@ -504,7 +504,7 @@ namespace TestingModule.ViewModels
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.ErrorWithNotify($"添加方法失败: {method.Name} - {ex.Message}"); LoggerHelper.ErrorWithNotify(_globalInfo.CurrentScope, $"添加方法失败: {method.Name} - {ex.Message}");
} }
} }
@@ -537,7 +537,7 @@ namespace TestingModule.ViewModels
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.ErrorWithNotify($"添加子程序失败: {subProgram.Name} - {ex.Message}"); LoggerHelper.ErrorWithNotify(_globalInfo.CurrentScope, $"添加子程序失败: {subProgram.Name} - {ex.Message}"); ;
} }
} }

View File

@@ -1,18 +1,20 @@
using UIShare.GlobalVariable; using UIShare.GlobalVariable;
using Logger; using Logger;
using Prism.Ioc;
using Prism.Mvvm; using Prism.Mvvm;
using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Reflection; using System.Reflection;
using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Threading;
using UIShare.ViewModelBase; using UIShare.ViewModelBase;
namespace TestingModule.ViewModels namespace TestingModule.ViewModels
{ {
public class LogAreaViewModel : NavigateViewModelBase, IDisposable public class LogAreaViewModel : NavigateViewModelBase, IDisposable
{ {
// 日志集合 // 日志集合
private ObservableCollection<LogItem> _logs = new(); private ObservableCollection<LogItem> _logs = new();
@@ -23,20 +25,23 @@ namespace TestingModule.ViewModels
} }
public ICommand ClearLogCommand { get; set; } public ICommand ClearLogCommand { get; set; }
private readonly ScopedContext _scopedContext;
private readonly GlobalInfo _globalInfo;
private IProgress<(string Message, Brush Color, int Depth)>? _logProgress;
public LogAreaViewModel(IContainerProvider containerProvider) : base(containerProvider) public LogAreaViewModel(IContainerProvider containerProvider) : base(containerProvider)
{ {
ClearLogCommand = new DelegateCommand(ClearLog); ClearLogCommand = new DelegateCommand(ClearLog);
_scopedContext = containerProvider.Resolve<ScopedContext>();
_globalInfo = containerProvider.Resolve<GlobalInfo>();
// 2. 保持原有逻辑,但请确保在 Dispose 中对其进行清理 // 创建本作用域专属的日志接收器并注册到 ScopedContext
LoggerHelper.Progress = new System.Progress<(string message, string color, int depth)>( _logProgress = new Progress<(string Message, Brush Color, int Depth)>(log =>
log => {
{ if (Logs == null) return;
// 增加防御性代码:防止进入销毁流程时异步回调引发空引用异常 Logs.Add(new LogItem(log.Message, log.Color, log.Depth));
if (Logs == null) return; });
_scopedContext.LogProgress = _logProgress;
var brush = (Brush)new BrushConverter().ConvertFromString(log.color);
Logs.Add(new LogItem(log.message, brush, log.depth));
});
} }
private void ClearLog() private void ClearLog()
@@ -51,7 +56,13 @@ namespace TestingModule.ViewModels
{ {
try try
{ {
LoggerHelper.Progress = null!; // 注销本作用域的日志接收器,避免 Dispose 后仍收到旧消息
if (_scopedContext != null && _scopedContext.LogProgress == _logProgress)
{
_scopedContext.LogProgress = null;
}
_logProgress = null;
if (Logs != null) if (Logs != null)
{ {
Logs.Clear(); Logs.Clear();
@@ -60,7 +71,7 @@ namespace TestingModule.ViewModels
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LoggerHelper.ErrorWithNotify($"释放日志组件LogAreaViewModel资源失败: {ex.Message}"); Logger.LoggerHelper.ErrorWithNotify(_scopedContext != null ? _globalInfo.CurrentScope : "", $"释放日志组件LogAreaViewModel资源失败: {ex.Message}");
} }
} }
} }

View File

@@ -175,7 +175,7 @@ namespace TestingModule.ViewModels
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.ErrorWithNotify($"打开设备编辑窗口 [{type}] 失败:{ex.Message}"); LoggerHelper.ErrorWithNotify(_globalInfo.CurrentScope, $"打开设备编辑窗口 [{type}] 失败:{ex.Message}");
} }
} }

View File

@@ -47,6 +47,7 @@ namespace TestingModule.ViewModels
} }
#endregion #endregion
private ScopedContext _ScopedContext; private ScopedContext _ScopedContext;
private GlobalInfo _globalInfo;
#region #region
public ICommand CancelEditCommand { get; set; } public ICommand CancelEditCommand { get; set; }
public ICommand SaveStepCommand { get; set; } public ICommand SaveStepCommand { get; set; }
@@ -54,6 +55,7 @@ namespace TestingModule.ViewModels
public SingleStepEditViewModel(IContainerProvider containerProvider, ScopedContext scopedContext) : base(containerProvider) public SingleStepEditViewModel(IContainerProvider containerProvider, ScopedContext scopedContext) : base(containerProvider)
{ {
_ScopedContext = scopedContext; _ScopedContext = scopedContext;
_globalInfo=containerProvider.Resolve<GlobalInfo>();
_eventAggregator.GetEvent<EditSetpEvent>().Subscribe(EditSingleStep); _eventAggregator.GetEvent<EditSetpEvent>().Subscribe(EditSingleStep);
CancelEditCommand = new DelegateCommand(CancelEdit); CancelEditCommand = new DelegateCommand(CancelEdit);
SaveStepCommand = new DelegateCommand(SaveStep); SaveStepCommand = new DelegateCommand(SaveStep);
@@ -100,7 +102,7 @@ namespace TestingModule.ViewModels
} }
catch catch
{ {
LoggerHelper.ErrorWithNotify("循环指令参数设置错误:类型转换失败"); LoggerHelper.ErrorWithNotify(_globalInfo.CurrentScope,"循环指令参数设置错误:类型转换失败");
} }
} }
else else

View File

@@ -62,7 +62,7 @@ namespace UIShare.GlobalVariable
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.ErrorWithNotify($"格子 [{title}] 配置加载失败: {ex.Message}"); LoggerHelper.ErrorWithNotify(title, $"格子 [{title}] 配置加载失败: {ex.Message}");
return new SystemConfig { Title = title }; return new SystemConfig { Title = title };
} }
} }
@@ -90,11 +90,11 @@ namespace UIShare.GlobalVariable
}); });
File.WriteAllText(configPath, json); File.WriteAllText(configPath, json);
LoggerHelper.InfoWithNotify($"配置 [{config.Title}] 已保存。"); LoggerHelper.InfoWithNotify(config.Title, $"配置 [{config.Title}] 已保存。");
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.ErrorWithNotify($"配置 [{config.Title}] 保存失败: {ex.Message}"); LoggerHelper.ErrorWithNotify(config.Title, $"配置 [{config.Title}] 保存失败: {ex.Message}");
} }
} }
} }

View File

@@ -128,7 +128,7 @@ namespace UIShare.GlobalVariable
catch (Exception ex) catch (Exception ex)
{ {
var inner = ex.InnerException?.Message ?? ex.Message; var inner = ex.InnerException?.Message ?? ex.Message;
LoggerHelper.ErrorWithNotify($"设备 [{config.DeviceName}] 实例化失败:{inner}"); LoggerHelper.ErrorWithNotify(_scopeName, $"设备 [{config.DeviceName}] 实例化失败:{inner}");
} }
} }
} }
@@ -288,7 +288,7 @@ namespace UIShare.GlobalVariable
{ {
if (info != null) info.IsConnected = false; if (info != null) info.IsConnected = false;
var inner = ex.InnerException?.Message ?? ex.Message; var inner = ex.InnerException?.Message ?? ex.Message;
LoggerHelper.ErrorWithNotify($"设备 [{name}/{conn}] 连接异常:{inner}"); LoggerHelper.ErrorWithNotify(_scopeName, $"设备 [{name}/{conn}] 连接异常:{inner}");
} }
} }

View File

@@ -0,0 +1,41 @@
using Logger;
using System;
using System.Windows.Media;
namespace UIShare.GlobalVariable
{
/// <summary>
/// 作用域日志分发器:根据显式传入的 scope 参数把日志路由到对应
/// <see cref="ScopedContext.LogProgress"/>,实现每个台架/作用域拥有独立 LogArea。
/// </summary>
public class ScopeLogDispatcher : IProgress<(string scope, string message, string color, int depth)>
{
private readonly GlobalInfo _globalInfo;
public ScopeLogDispatcher(GlobalInfo globalInfo)
{
_globalInfo = globalInfo ?? throw new ArgumentNullException(nameof(globalInfo));
}
public void Report((string scope, string message, string color, int depth) value)
{
var scope = value.scope;
if (string.IsNullOrEmpty(scope)) return;
if (!_globalInfo.ContextDic.TryGetValue(scope, out var context)) return;
if (context?.LogProgress == null) return;
Brush? brush = null;
try
{
brush = (Brush)new BrushConverter().ConvertFromString(value.color);
}
catch
{
brush = Brushes.Black;
}
context.LogProgress.Report((value.message, brush, value.depth));
}
}
}

View File

@@ -8,6 +8,7 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Media;
using UIShare.UIViewModel; using UIShare.UIViewModel;
namespace UIShare.GlobalVariable namespace UIShare.GlobalVariable
@@ -30,6 +31,10 @@ namespace UIShare.GlobalVariable
public ParameterVM SelectedParameter { get; set; } public ParameterVM SelectedParameter { get; set; }
public List<IBaseInterface> DeviceList { get; set; } = new(); public List<IBaseInterface> DeviceList { get; set; } = new();
/// <summary>当前作用域的日志接收器LogAreaViewModel 订阅此处实现按作用域隔离日志。</summary>
public IProgress<(string Message, Brush Color, int Depth)>? LogProgress { get; set; }
// 【新增测试属性】:每个实例被 new 出来时独一无二的随机身份 // 【新增测试属性】:每个实例被 new 出来时独一无二的随机身份
// 证 ID // 证 ID
public int DebugRandomId { get; private set; } public int DebugRandomId { get; private set; }

View File

@@ -88,7 +88,7 @@ namespace UIShare
} }
else else
{ {
LoggerHelper.ErrorWithNotify("程序循环指令未闭合,请检查后重试"); LoggerHelper.ErrorWithNotify(_systemConfig.Title, "程序循环指令未闭合,请检查后重试");
break; break;
} }
} }
@@ -108,7 +108,7 @@ namespace UIShare
}; };
loopStack.Push(context); loopStack.Push(context);
step.CurrentLoopCount = context.LoopCount; step.CurrentLoopCount = context.LoopCount;
LoggerHelper.InfoWithNotify($"循环开始,共{context.LoopCount}次", depth); LoggerHelper.InfoWithNotify(_systemConfig.Title, $"循环开始,共{context.LoopCount}次", depth);
index++; index++;
} }
@@ -117,7 +117,7 @@ namespace UIShare
{ {
if (loopStack.Count == 0) if (loopStack.Count == 0)
{ {
LoggerHelper.ErrorWithNotify("未匹配的循环结束指令", depth: depth); LoggerHelper.ErrorWithNotify(_systemConfig.Title, "未匹配的循环结束指令", depth: depth);
step.Result = 2; step.Result = 2;
index++; index++;
continue; continue;
@@ -133,7 +133,7 @@ namespace UIShare
{ {
// 继续循环:跳转到循环开始后的第一条指令 // 继续循环:跳转到循环开始后的第一条指令
index = context.StartIndex + 1; index = context.StartIndex + 1;
LoggerHelper.InfoWithNotify($"循环第{context.CurrentLoop}次结束,跳回开始,剩余{context.LoopCount - context.CurrentLoop}次", depth); LoggerHelper.InfoWithNotify(_systemConfig.Title, $"循环第{context.CurrentLoop}次结束,跳回开始,剩余{context.LoopCount - context.CurrentLoop}次", depth);
} }
else else
{ {
@@ -141,7 +141,7 @@ namespace UIShare
loopStack.Pop(); loopStack.Pop();
var loopStopwatch = loopStopwatchStack.Peek(); var loopStopwatch = loopStopwatchStack.Peek();
index++; index++;
LoggerHelper.InfoWithNotify($"循环结束,共执行{context.LoopCount}次", depth); LoggerHelper.InfoWithNotify(_systemConfig.Title, $"循环结束,共执行{context.LoopCount}次", depth);
if (depth == 0 && loopStopwatch.IsRunning) if (depth == 0 && loopStopwatch.IsRunning)
{ {
loopStopwatch.Stop(); loopStopwatch.Stop();
@@ -168,7 +168,7 @@ namespace UIShare
SubSingleStep = true; SubSingleStep = true;
_scopedContext.SingleStep = false; _scopedContext.SingleStep = false;
} }
LoggerHelper.InfoWithNotify($"开始执行子程序 [ {step.Index} ] [ {step.Name} ] ", depth); LoggerHelper.InfoWithNotify(_systemConfig.Title, $"开始执行子程序 [ {step.Index} ] [ {step.Name} ] ", depth);
stepSuccess = await ExecuteSteps(step.SubProgram, depth + 1, cancellationToken); stepSuccess = await ExecuteSteps(step.SubProgram, depth + 1, cancellationToken);
UpdateCurrentStepResult(step, true, stepSuccess, depth); UpdateCurrentStepResult(step, true, stepSuccess, depth);
if (SubSingleStep) if (SubSingleStep)
@@ -179,7 +179,7 @@ namespace UIShare
} }
else if (step.Method != null) else if (step.Method != null)
{ {
LoggerHelper.InfoWithNotify($"开始执行指令 [ {step.Index} ] [ {step.Method!.FullName}.{step.Method.Name} ] ", depth); LoggerHelper.InfoWithNotify(_systemConfig.Title, $"开始执行指令 [ {step.Index} ] [ {step.Method!.FullName}.{step.Method.Name} ] ", depth);
await ExecuteMethodStep(step, tmpParameters, depth, cancellationToken); await ExecuteMethodStep(step, tmpParameters, depth, cancellationToken);
stepSuccess = step.Result == 1; stepSuccess = step.Result == 1;
if (step.NGGotoStepID != null && !stepSuccess) if (step.NGGotoStepID != null && !stepSuccess)
@@ -188,7 +188,7 @@ namespace UIShare
if (tmp != null) if (tmp != null)
{ {
index = tmp.Index - 2; index = tmp.Index - 2;
LoggerHelper.InfoWithNotify($"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth); LoggerHelper.InfoWithNotify(_systemConfig.Title, $"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth);
} }
} }
if (step.OKGotoStepID != null && stepSuccess) if (step.OKGotoStepID != null && stepSuccess)
@@ -197,7 +197,7 @@ namespace UIShare
if (tmp != null) if (tmp != null)
{ {
index = tmp.Index - 2; index = tmp.Index - 2;
LoggerHelper.InfoWithNotify($"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth); LoggerHelper.InfoWithNotify(_systemConfig.Title, $"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth);
} }
} }
} }
@@ -257,7 +257,7 @@ namespace UIShare
} }
else else
{ {
LoggerHelper.ErrorWithNotify("程序循环指令未闭合,请检查后重试"); LoggerHelper.ErrorWithNotify(_systemConfig.Title, "程序循环指令未闭合,请检查后重试");
break; break;
} }
} }
@@ -277,7 +277,7 @@ namespace UIShare
}; };
loopStack.Push(context); loopStack.Push(context);
step.CurrentLoopCount = context.LoopCount; step.CurrentLoopCount = context.LoopCount;
LoggerHelper.InfoWithNotify($"循环开始({step.Name}),共{context.LoopCount}次", depth); LoggerHelper.InfoWithNotify(_systemConfig.Title, $"循环开始({step.Name}),共{context.LoopCount}次", depth);
index++; index++;
} }
@@ -286,7 +286,7 @@ namespace UIShare
{ {
if (loopStack.Count == 0) if (loopStack.Count == 0)
{ {
LoggerHelper.ErrorWithNotify("未匹配的循环结束指令", depth:depth); LoggerHelper.ErrorWithNotify(_systemConfig.Title, "未匹配的循环结束指令", depth:depth);
step.Result = 2; step.Result = 2;
index++; index++;
continue; continue;
@@ -302,7 +302,7 @@ namespace UIShare
{ {
// 继续循环:跳转到循环开始后的第一条指令 // 继续循环:跳转到循环开始后的第一条指令
index = context.StartIndex + 1; index = context.StartIndex + 1;
LoggerHelper.InfoWithNotify($"循环第{context.CurrentLoop}次结束,跳回开始,剩余{context.LoopCount - context.CurrentLoop}次", depth); LoggerHelper.InfoWithNotify(_systemConfig.Title, $"循环第{context.CurrentLoop}次结束,跳回开始,剩余{context.LoopCount - context.CurrentLoop}次", depth);
} }
else else
{ {
@@ -310,7 +310,7 @@ namespace UIShare
loopStack.Pop(); loopStack.Pop();
var loopStopwatch = loopStopwatchStack.Peek(); var loopStopwatch = loopStopwatchStack.Peek();
index++; index++;
LoggerHelper.InfoWithNotify($"循环结束,共执行{context.LoopCount}次", depth); LoggerHelper.InfoWithNotify(_systemConfig.Title, $"循环结束,共执行{context.LoopCount}次", depth);
if (depth == 0 && loopStopwatch.IsRunning) if (depth == 0 && loopStopwatch.IsRunning)
{ {
loopStopwatch.Stop(); loopStopwatch.Stop();
@@ -337,7 +337,7 @@ namespace UIShare
SubSingleStep = true; SubSingleStep = true;
_scopedContext.SingleStep = false; _scopedContext.SingleStep = false;
} }
LoggerHelper.InfoWithNotify($"开始执行子程序 [ {step.Index} ] [ {step.Name} ] ", depth); LoggerHelper.InfoWithNotify(_systemConfig.Title, $"开始执行子程序 [ {step.Index} ] [ {step.Name} ] ", depth);
stepSuccess = await ExecuteSteps(step.SubProgram, depth + 1, cancellationToken); stepSuccess = await ExecuteSteps(step.SubProgram, depth + 1, cancellationToken);
UpdateCurrentStepResult(step, true, stepSuccess, depth); UpdateCurrentStepResult(step, true, stepSuccess, depth);
if (SubSingleStep) if (SubSingleStep)
@@ -348,7 +348,7 @@ namespace UIShare
} }
else if (step.Method != null) else if (step.Method != null)
{ {
LoggerHelper.InfoWithNotify($"开始执行指令 [ {step.Index} ] [ {step.Method!.FullName}.{step.Method.Name} ] ", depth); LoggerHelper.InfoWithNotify(_systemConfig.Title, $"开始执行指令 [ {step.Index} ] [ {step.Method!.FullName}.{step.Method.Name} ] ", depth);
await ExecuteMethodStep(step, tmpParameters, depth, cancellationToken); await ExecuteMethodStep(step, tmpParameters, depth, cancellationToken);
stepSuccess = step.Result == 1; stepSuccess = step.Result == 1;
if (step.NGGotoStepID != null && !stepSuccess) if (step.NGGotoStepID != null && !stepSuccess)
@@ -357,7 +357,7 @@ namespace UIShare
if (tmp != null) if (tmp != null)
{ {
index = tmp.Index - 2; index = tmp.Index - 2;
LoggerHelper.InfoWithNotify($"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth); LoggerHelper.InfoWithNotify(_systemConfig.Title, $"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth);
} }
} }
if (step.OKGotoStepID != null && stepSuccess) if (step.OKGotoStepID != null && stepSuccess)
@@ -366,7 +366,7 @@ namespace UIShare
if (tmp != null) if (tmp != null)
{ {
index = tmp.Index - 2; index = tmp.Index - 2;
LoggerHelper.InfoWithNotify($"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth); LoggerHelper.InfoWithNotify(_systemConfig.Title, $"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth);
} }
} }
} }
@@ -408,7 +408,7 @@ namespace UIShare
} }
if (targetType == null) if (targetType == null)
{ {
LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:未找到类型 {step.Method!.FullName}", depth: depth); LoggerHelper.ErrorWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行错误:未找到类型 {step.Method!.FullName}", depth: depth);
step.Result = 2; step.Result = 2;
} }
@@ -522,7 +522,7 @@ namespace UIShare
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.WarnWithNotify($"指令 [ {step.Index} ] 执行错误:参数 {param.Name} 类型转换失败: {ex.Message}", depth: depth); LoggerHelper.WarnWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行错误:参数 {param.Name} 类型转换失败: {ex.Message}", depth: depth);
} }
} }
} }
@@ -546,7 +546,7 @@ namespace UIShare
if (method == null) if (method == null)
{ {
LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:未找到方法{step.Method.Name}", depth: depth); LoggerHelper.ErrorWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行错误:未找到方法{step.Method.Name}", depth: depth);
step.Result = 2; step.Result = 2;
} }
@@ -562,7 +562,7 @@ namespace UIShare
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:创建实例失败 - {ex.Message}", depth: depth); LoggerHelper.ErrorWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行错误:创建实例失败 - {ex.Message}", depth: depth);
step.Result = 2; step.Result = 2;
} }
} }
@@ -600,7 +600,7 @@ namespace UIShare
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth: depth); LoggerHelper.ErrorWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth: depth);
step.Result = 2; step.Result = 2;
return; return;
} }
@@ -619,7 +619,7 @@ namespace UIShare
paraResult = tmp.Item1; paraResult = tmp.Item1;
if (tmp.Item2 != null) if (tmp.Item2 != null)
{ {
LoggerHelper.WarnWithNotify(tmp.Item2); LoggerHelper.WarnWithNotify(_systemConfig.Title, tmp.Item2);
} }
} }
@@ -628,19 +628,19 @@ namespace UIShare
{ {
if (!returnType.IsArray) if (!returnType.IsArray)
{ {
LoggerHelper.SuccessWithNotify($"输出 [ {outputParam.Name} ] = {returnValue} ({returnType.Name})", depth); LoggerHelper.SuccessWithNotify(_systemConfig.Title, $"输出 [ {outputParam.Name} ] = {returnValue} ({returnType.Name})", depth);
} }
else else
{ {
if (returnValue is IEnumerable enumerable) if (returnValue is IEnumerable enumerable)
{ {
var elements = enumerable.Cast<object>().Select(item => item?.ToString() ?? "null"); var elements = enumerable.Cast<object>().Select(item => item?.ToString() ?? "null");
LoggerHelper.SuccessWithNotify($"输出 [ {outputParam.Name} ] = [ {string.Join(", ", elements)} ] ({returnType.Name})", depth); LoggerHelper.SuccessWithNotify(_systemConfig.Title, $"输出 [ {outputParam.Name} ] = [ {string.Join(", ", elements)} ] ({returnType.Name})", depth);
} }
} }
} }
} }
LoggerHelper.SuccessWithNotify($"指令 [ {step.Index} ] 执行成功", depth); LoggerHelper.SuccessWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行成功", depth);
UpdateCurrentStepResult(step, paraResult: paraResult, depth: depth); UpdateCurrentStepResult(step, paraResult: paraResult, depth: depth);
} }
catch (OperationCanceledException) catch (OperationCanceledException)
@@ -649,7 +649,7 @@ namespace UIShare
} }
catch (Exception ex) catch (Exception ex)
{ {
LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth: depth); LoggerHelper.ErrorWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth: depth);
step.Result = 2; step.Result = 2;
return; return;
} }
@@ -697,7 +697,7 @@ namespace UIShare
step.Result = re ? 1 : 2; step.Result = re ? 1 : 2;
if (step.Result == 2) if (step.Result == 2)
{ {
LoggerHelper.WarnWithNotify($"指令 [ {step.Index} ] NG:条件表达式验证失败", depth: depth); LoggerHelper.WarnWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] NG:条件表达式验证失败", depth: depth);
} }
} }
} }
@@ -705,7 +705,7 @@ namespace UIShare
{ {
if (!paraResult) if (!paraResult)
{ {
LoggerHelper.WarnWithNotify("参数限值校验失败", depth: depth); LoggerHelper.WarnWithNotify(_systemConfig.Title, "参数限值校验失败", depth: depth);
} }
step.Result = 2; step.Result = 2;
} }