Nlog

在App中设置Nlog日志记录,并实现全局异常处理。

public partial class App{
  protected override async void OnInitialized()
  {
      _logger = Container.Resolve<ILogger<App>>();
      _logger?.LogInformation("应用启动...");
      RegisterGlobalExceptionHandling();
      base.OnInitialized();
  }
  protected override void RegisterTypes(IContainerRegistry containerRegistry)
  {
    // 项目中注册的服务
    // 注册 ILoggerFactory 并配置 NLog
    containerRegistry.RegisterSingleton<ILoggerFactory>(() =>
    {
      var loggerFactory = LoggerFactory.Create(builder =>
      {
          builder.ClearProviders(); // 清除默认的日志提供程序
          builder.AddNLog();        // 添加 NLog 支持
          builder.SetMinimumLevel(LogLevel.Debug); // 设置最小日志级别
      });
      // 加载 NLog 配置(禁用 ASP.NET Core 扩展扫描)
      LogManager.Setup()
          .SetupExtensions(ext => { }) // 禁用自动加载扩展
          .LoadConfigurationFromFile("nlog.config");
      return loggerFactory;
    });
    //var allTargets = LogManager.Configuration.AllTargets;
    //foreach (var target in allTargets)
    //{
    //    Debug.WriteLine(target.GetType().Name + "********************************");
    //}
    // 注册泛型 ILogger<T>,便于依赖注入
    containerRegistry.Register(typeof(ILogger<>), typeof(Logger<>));
  }
      private void RegisterGlobalExceptionHandling()
    {
        DispatcherUnhandledException += OnDispatcherUnhandledException;
        AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
        TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
    }
    /// <summary>
    /// UI线程异常处理
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
    {
        var exception = e.Exception;
        _logger?.LogError(exception, $"UI线程异常:{exception.Message}");
        e.Handled = true;
    }
    /// <summary>
    /// 非UI线程异常处理
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        var exception = e.ExceptionObject as Exception;
        _logger?.LogError(exception, $"非UI线程异常,IsTerminating: {e.IsTerminating},Message: {exception.Message}");
    }
    /// <summary>
    /// 未观察到的任务异常处理
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
    {
        _logger?.LogError(e.Exception, "未观察到的任务异常");
        e.SetObserved();
    }
  }
}

nlog.config文件内容如下:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true"
      internalLogLevel="Error"
      internalLogFile="logs/internal-nlog.txt"
	    internalLogMaxFileSize="5242880">
 <targets>
		<!-- 优化后的文件Target -->
		<target name="file" xsi:type="File"
				fileName="logs/${shortdate}.log"
				layout="${longdate}|${level:uppercase=true}|${logger:shortName=true}|${message:withException=true}${newline}${exception:format=Message,StackTrace:separator= : }${newline}" />

		<!-- 控制台输出 -->
		<target name="console" xsi:type="Console"
				layout="${time} | ${level:uppercase=true:padding=5} | ${logger:shortName=true:padding=20} | ${message:withException=true}" />

		<!-- 可选:添加一个调试用的简洁格式 -->
		<target name="debugFile" xsi:type="File"
				fileName="logs/debug-${shortdate}.log"
				layout="${longdate} | ${level:uppercase=true} | ${logger:shortName=true} | ${message}${onexception:${newline}EXCEPTION: ${exception:format=Message}}" />
	</targets>

	<rules>
		<!-- 默认规则 -->
		<logger name="*" minlevel="Debug" writeTo="file,console" />

		<!-- 减少Microsoft.*的日志噪音 -->
		<logger name="Microsoft.*" minlevel="Warn" final="true" />
		<logger name="System.*" minlevel="Warn" final="true" />
	</rules>
</nlog>

异常类型

  1. UI线程异常:DispatcherUnhandledException
    • 特点:发生在与用户界面直接相关的操作中
     // 这些都是UI线程操作
     private void Button_Click(object sender, RoutedEventArgs e)
     {
         // 以下操作都在UI线程执行
         textBox.Text = "Hello";          // 更新UI控件
         this.Title = "新标题";           // 修改窗口属性
         throw new Exception("UI线程异常"); // 这里抛出的是UI线程异常
     }
    
     // 典型的UI线程异常场景:
     private void UpdateUI()
     {
         // 直接操作UI控件 - 在UI线程执行
         button.Content = "点击我";
         progressBar.Value = 50;
            
         // 如果这里抛出异常,就是UI线程异常
         var invalidData = someArray[999]; // 可能越界
     }
    
  2. 非UI线程异常:UnhandledException
    • 特点:发生在后台任务、计算、IO操作中
     // 这些是非UI线程操作
     private void StartBackgroundWork()
            
         // Thread 创建新线程
         var thread = new Thread(() =>
         {
             ReadFileContent();   // 文件操作
             throw new Exception("线程异常");
         });
         thread.Start();
     }
    
     // 定时器也在非UI线程
     private void SetupTimer()
     {
         var timer = new Timer(_ =>
         {
             // 这里是非UI线程
             CheckSystemStatus();
             throw new Exception("定时器异常");
         }, null, 1000, 1000);
     }
    
  3. 未观察到的任务异常:UnobservedTaskException

     private void StartTask()
     {
         Task.Run(() => throw new Exception("任务异常")); 
         // 没有 await,没有检查 Result,异常被"忽略"
         // → TaskScheduler.UnobservedTaskException
     }