From 94deba08f4e64705dc96f8880b1de915d399f415 Mon Sep 17 00:00:00 2001 From: Bagus Nur Listiyono Date: Tue, 12 Nov 2024 21:38:31 +0700 Subject: [PATCH] Some improvements 1. Only uploads log file when exception is unhandled 2. Add cache dir path using Collapse's LocalLow data path 3. Dispose _loopToken before creating a new one to prevent memory leak 4. Reordered LogWriteLine on initialization 5. Release exception redirect event when feature is disabled --- CollapseLauncher/Program.cs | 2 +- .../Classes/SentryHelper/SentryHelper.cs | 87 ++++++++++++------- 2 files changed, 56 insertions(+), 33 deletions(-) diff --git a/CollapseLauncher/Program.cs b/CollapseLauncher/Program.cs index 81186636d..65912fde4 100644 --- a/CollapseLauncher/Program.cs +++ b/CollapseLauncher/Program.cs @@ -87,9 +87,9 @@ public static void Main(params string[] args) try { // Sentry SDK Entry - LogWriteLine("Setting up global exception handler redirection", LogType.Scheme, true); LogWriteLine("Loading Sentry SDK...", LogType.Sentry, true); SentryHelper.InitializeSentrySdk(); + LogWriteLine("Setting up global exception handler redirection", LogType.Scheme, true); SentryHelper.InitializeExceptionRedirect(); } catch (Exception ex) diff --git a/Hi3Helper.Core/Classes/SentryHelper/SentryHelper.cs b/Hi3Helper.Core/Classes/SentryHelper/SentryHelper.cs index 2f84f1e34..212222103 100644 --- a/Hi3Helper.Core/Classes/SentryHelper/SentryHelper.cs +++ b/Hi3Helper.Core/Classes/SentryHelper/SentryHelper.cs @@ -72,6 +72,7 @@ public static void InitializeSentrySdk() { o.Dsn = SentryDsn; o.AddEventProcessor(new SentryEventProcessor()); + o.CacheDirectoryPath = LauncherConfig.AppDataFolder; #if DEBUG o.Debug = true; @@ -97,13 +98,6 @@ public static void InitializeSentrySdk() o.MaxAttachmentSize = SentryMaxAttachmentSize; o.DeduplicateMode = DeduplicateMode.All; }); - - SentrySdk.ConfigureScope(s => - { - // Broken atm due to length = 0 - // dunno why - s.AddAttachment(LoggerBase.LogPath, AttachmentType.Default, "text/plain"); - }); } /// @@ -115,6 +109,7 @@ public static void StopSentrySdk() { SentrySdk.Flush(TimeSpan.FromSeconds(5)); SentrySdk.EndSession(); + ReleaseExceptionRedirect(); } catch (Exception ex) { @@ -128,25 +123,34 @@ public static void StopSentrySdk() } public static void InitializeExceptionRedirect() + { + AppDomain.CurrentDomain.UnhandledException += AppDomain_UnhandledExceptionEvent; + TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; + } + + private static void ReleaseExceptionRedirect() + { + AppDomain.CurrentDomain.UnhandledException -= AppDomain_UnhandledExceptionEvent; + TaskScheduler.UnobservedTaskException -= TaskScheduler_UnobservedTaskException; + } + + private static void AppDomain_UnhandledExceptionEvent(object sender, UnhandledExceptionEventArgs a) { // Handle any unhandled errors in app domain // https://learn.microsoft.com/en-us/dotnet/api/system.appdomain?view=net-9.0 - AppDomain.CurrentDomain.UnhandledException += (_, args) => - { - var ex = args.ExceptionObject as Exception; - if (ex == null) return; - ex.Data[Mechanism.HandledKey] = false; - ex.Data[Mechanism.MechanismKey] = "Application.UnhandledException"; - ExceptionHandler(ex, ExceptionType.UnhandledOther); + var ex = a.ExceptionObject as Exception; + if (ex == null) return; + ex.Data[Mechanism.HandledKey] = false; + ex.Data[Mechanism.MechanismKey] = "Application.UnhandledException"; + ExceptionHandler(ex, ExceptionType.UnhandledOther); - throw ex; - }; - - TaskScheduler.UnobservedTaskException += (_, args) => - { - args.Exception.Data[Mechanism.HandledKey] = false; - ExceptionHandler(args.Exception, ExceptionType.UnhandledOther); - }; + throw ex; + } + + private static void TaskScheduler_UnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e) + { + e.Exception.Data[Mechanism.HandledKey] = false; + ExceptionHandler(e.Exception, ExceptionType.UnhandledOther); } /// @@ -157,13 +161,18 @@ public static void InitializeExceptionRedirect() public static void ExceptionHandler(Exception ex, ExceptionType exT = ExceptionType.Handled) { if (!IsEnabled) return; - ex.Data[Mechanism.HandledKey] = exT == ExceptionType.Handled; + ex.Data[Mechanism.HandledKey] ??= exT == ExceptionType.Handled; if (exT == ExceptionType.UnhandledXaml) ex.Data[Mechanism.MechanismKey] = "Application.XamlUnhandledException"; else if (exT == ExceptionType.UnhandledOther) ex.Data[Mechanism.MechanismKey] = "Application.UnhandledException"; - SentrySdk.CaptureException(ex); - SentrySdk.Flush(TimeSpan.FromSeconds(5)); + if ((bool)(ex.Data[Mechanism.HandledKey] ?? false)) + SentrySdk.CaptureException(ex); + else + SentrySdk.CaptureException(ex, s => + { + s.AddAttachment(LoggerBase.LogPath, AttachmentType.Default, "text/plain"); + }); } /// @@ -179,8 +188,15 @@ public static async Task ExceptionHandlerAsync(Exception ex, ExceptionType exT = ex.Data[Mechanism.MechanismKey] = "Application.XamlUnhandledException"; else if (exT == ExceptionType.UnhandledOther) ex.Data[Mechanism.MechanismKey] = "Application.UnhandledException"; - SentrySdk.CaptureException(ex); - await SentrySdk.FlushAsync(TimeSpan.FromSeconds(1)); + if ((bool)(ex.Data[Mechanism.HandledKey] ?? false)) + SentrySdk.CaptureException(ex); + else + SentrySdk.CaptureException(ex, s => + { + s.AddAttachment(LoggerBase.LogPath, AttachmentType.Default, "text/plain"); + }); + + await SentrySdk.FlushAsync(TimeSpan.FromSeconds(10)); } private static Exception? _exHLoopLastEx; @@ -227,14 +243,21 @@ public static void ExceptionHandler_ForLoop(Exception ex, ExceptionType exT = Ex public static async Task ExceptionHandler_ForLoopAsync(Exception ex, ExceptionType exT = ExceptionType.Handled) { if (!IsEnabled) return; - if (ex == _exHLoopLastEx) return; - await _loopToken.CancelAsync(); - _loopToken = new CancellationTokenSource(); + if (ex == _exHLoopLastEx) return; // If exception pointer is the same as the last one, ignore it. + await _loopToken.CancelAsync(); // Cancel the previous loop + _loopToken.Dispose(); + _loopToken = new CancellationTokenSource(); // Create new token _exHLoopLastEx = ex; - ExHLoopLastEx_AutoClean(); + ExHLoopLastEx_AutoClean(); // Start auto clean loop ex.Data[Mechanism.HandledKey] = exT == ExceptionType.Handled; - SentrySdk.CaptureException(ex); + if ((bool)(ex.Data[Mechanism.HandledKey] ?? false)) + SentrySdk.CaptureException(ex); + else + SentrySdk.CaptureException(ex, s => + { + s.AddAttachment(LoggerBase.LogPath, AttachmentType.Default, "text/plain"); + }); } } } \ No newline at end of file