GlobalProcessExceptionHandlers.cs 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
  2. //
  3. // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
  4. //
  5. // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
  6. namespace Admin.NET.Web.Entry;
  7. /// <summary>
  8. /// 进程级未处理异常:在 DI/日志管道就绪前尽量落盘到控制台,便于容器与本地排障。
  9. /// 说明:.NET 中 <see cref="AppDomain.UnhandledException"/> 在 <c>IsTerminating</c> 时无法阻止进程退出,仅能最后记录。
  10. /// </summary>
  11. public static class GlobalProcessExceptionHandlers
  12. {
  13. private static int _registered;
  14. public static void Register()
  15. {
  16. if (Interlocked.Exchange(ref _registered, 1) != 0)
  17. return;
  18. AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
  19. TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
  20. }
  21. private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
  22. {
  23. try
  24. {
  25. var terminating = e.IsTerminating ? "即将终止进程" : "非终止";
  26. var ex = e.ExceptionObject as Exception;
  27. var headline = $"[{DateTime.UtcNow:O}] AppDomain 未处理异常 ({terminating})";
  28. Console.Error.WriteLine(headline);
  29. if (ex != null)
  30. Console.Error.WriteLine(ex);
  31. else
  32. Console.Error.WriteLine(e.ExceptionObject);
  33. }
  34. catch
  35. {
  36. // 避免回调内再抛导致二次崩溃
  37. }
  38. }
  39. private static void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
  40. {
  41. try
  42. {
  43. Console.Error.WriteLine($"[{DateTime.UtcNow:O}] TaskScheduler 未观察到的任务异常:");
  44. Console.Error.WriteLine(e.Exception);
  45. e.SetObserved();
  46. }
  47. catch
  48. {
  49. try
  50. {
  51. e.SetObserved();
  52. }
  53. catch
  54. {
  55. // ignore
  56. }
  57. }
  58. }
  59. }