Skip to content

Commit

Permalink
Some improvements
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bagusnl committed Nov 12, 2024
1 parent 325e4d7 commit 94deba0
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 33 deletions.
2 changes: 1 addition & 1 deletion CollapseLauncher/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
87 changes: 55 additions & 32 deletions Hi3Helper.Core/Classes/SentryHelper/SentryHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public static void InitializeSentrySdk()
{
o.Dsn = SentryDsn;
o.AddEventProcessor(new SentryEventProcessor());
o.CacheDirectoryPath = LauncherConfig.AppDataFolder;

#if DEBUG
o.Debug = true;
Expand All @@ -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");
});
}

/// <summary>
Expand All @@ -115,6 +109,7 @@ public static void StopSentrySdk()
{
SentrySdk.Flush(TimeSpan.FromSeconds(5));
SentrySdk.EndSession();
ReleaseExceptionRedirect();
}
catch (Exception ex)
{
Expand All @@ -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()

Check warning on line 131 in Hi3Helper.Core/Classes/SentryHelper/SentryHelper.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Method return value is never used (private accessibility)

Method 'ReleaseExceptionRedirect' return value is never used

Check warning

Code scanning / QDNET

Method return value is never used (private accessibility) Warning

Method 'ReleaseExceptionRedirect' return value is never used
{
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);
}

/// <summary>
Expand All @@ -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");
});
}

/// <summary>
Expand All @@ -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;
Expand Down Expand Up @@ -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

Check warning on line 251 in Hi3Helper.Core/Classes/SentryHelper/SentryHelper.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Async method invocation without await expression

Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

Check warning

Code scanning / QDNET

Async method invocation without await expression Warning

Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

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");
});
}
}
}

0 comments on commit 94deba0

Please sign in to comment.