From ac56512dc5d5ed75d886198a193b7c20459ab9cb Mon Sep 17 00:00:00 2001 From: JT <297250+joshuatam@users.noreply.github.com> Date: Mon, 10 Jun 2024 16:12:42 +0800 Subject: [PATCH] Add Sentry.io Integration (#309) * add sentry integration * Update App.xaml.cs * update sentry integration remove bat file, put the command inside csproj add SentryConfig.cs to git enable Sentry debug only on debug build * update prebuild and postbuild command * code style * Use default %localappdata%\HandheldCompanion folder * Push all crash Exception(s) to Sentry --------- Co-authored-by: Lesueur Benjamin --- .gitignore | 2 +- HandheldCompanion/App.xaml.cs | 85 ++++++++++++++++++++-- HandheldCompanion/HandheldCompanion.csproj | 14 +++- HandheldCompanion/SentryConfig.cs | 7 ++ 4 files changed, 98 insertions(+), 10 deletions(-) create mode 100644 HandheldCompanion/SentryConfig.cs diff --git a/.gitignore b/.gitignore index 3856a7096..719dda13c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,4 @@ install/ *.user *Backup.csproj *tmp.csproj -.idea/ +.idea/ \ No newline at end of file diff --git a/HandheldCompanion/App.xaml.cs b/HandheldCompanion/App.xaml.cs index abf0abfda..efb261e4c 100644 --- a/HandheldCompanion/App.xaml.cs +++ b/HandheldCompanion/App.xaml.cs @@ -7,6 +7,9 @@ using System.Reflection; using System.Threading; using System.Windows; +using System.Windows.Threading; +using Sentry; +using Sentry.Profiling; using static HandheldCompanion.WinAPI; namespace HandheldCompanion; @@ -24,6 +27,7 @@ public partial class App : Application /// public App() { + InitializeSentry(); InitializeComponent(); } @@ -108,6 +112,8 @@ protected override void OnStartup(StartupEventArgs args) currentDomain.UnhandledException += CurrentDomain_UnhandledException; // Handler for exceptions in threads behind forms. System.Windows.Forms.Application.ThreadException += Application_ThreadException; + // Handler for exceptions in dispatcher. + DispatcherUnhandledException += App_DispatcherUnhandledException; MainWindow = new MainWindow(fileVersionInfo, CurrentAssembly); MainWindow.Show(); @@ -115,23 +121,86 @@ protected override void OnStartup(StartupEventArgs args) private void Application_ThreadException(object sender, ThreadExceptionEventArgs e) { - var ex = default(Exception); - ex = (Exception)e.Exception; + Exception ex = (Exception)e.Exception; + + // send to sentry + if (SentrySdk.IsEnabled) + SentrySdk.CaptureException(ex); + if (ex.InnerException != null) - { LogManager.LogCritical(ex.InnerException.Message + "\t" + ex.InnerException.StackTrace); - } + LogManager.LogCritical(ex.Message + "\t" + ex.StackTrace); } private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { - var ex = default(Exception); - ex = (Exception)e.ExceptionObject; + Exception ex = (Exception)e.ExceptionObject; + + // send to sentry + if (SentrySdk.IsEnabled) + SentrySdk.CaptureException(ex); + if (ex.InnerException != null) - { LogManager.LogCritical(ex.InnerException.Message + "\t" + ex.InnerException.StackTrace); - } + + LogManager.LogCritical(ex.Message + "\t" + ex.StackTrace); + } + + private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) + { + Exception ex = (Exception)e.Exception; + + // send to sentry + if (SentrySdk.IsEnabled) + SentrySdk.CaptureException(ex); + + if (ex.InnerException != null) + LogManager.LogCritical(ex.InnerException.Message + "\t" + ex.InnerException.StackTrace); + LogManager.LogCritical(ex.Message + "\t" + ex.StackTrace); + + // If you want to avoid the application from crashing: + e.Handled = true; + } + + private void InitializeSentry() + { + string url = SentryConfig.DSN_URL; + + if (!string.IsNullOrEmpty(url)) + { + SentrySdk.Init(options => + { + // Tells which project in Sentry to send events to: + options.Dsn = url; + + #if DEBUG + // When configuring for the first time, to see what the SDK is doing: + options.Debug = true; + #else + options.Debug = false; + #endif + + // Enable Global Mode since this is a client app + options.IsGlobalModeEnabled = true; + + // Set traces_sample_rate to 1.0 to capture 100% of transactions for performance monitoring. + // We recommend adjusting this value in production. + options.TracesSampleRate = 1.0; + + // Sample rate for profiling, applied on top of othe TracesSampleRate, + // e.g. 0.2 means we want to profile 20 % of the captured transactions. + // We recommend adjusting this value in production. + options.ProfilesSampleRate = 1.0; + + // Requires NuGet package: Sentry.Profiling + // Note: By default, the profiler is initialized asynchronously. This can be tuned by passing a desired initialization timeout to the constructor. + options.AddIntegration(new ProfilingIntegration( + // During startup, wait up to 500ms to profile the app startup code. This could make launching the app a bit slower so comment it out if your prefer profiling to start asynchronously + TimeSpan.FromMilliseconds(500) + )); + }); + } } } \ No newline at end of file diff --git a/HandheldCompanion/HandheldCompanion.csproj b/HandheldCompanion/HandheldCompanion.csproj index 3af30ee94..08289a164 100644 --- a/HandheldCompanion/HandheldCompanion.csproj +++ b/HandheldCompanion/HandheldCompanion.csproj @@ -1,4 +1,4 @@ - + WinExe @@ -16,6 +16,7 @@ app.manifest AnyCPU;x64;x86 true + Always @@ -51,6 +52,7 @@ True Designer + @@ -171,6 +173,8 @@ + + @@ -2351,4 +2355,12 @@ + + + + + + + + diff --git a/HandheldCompanion/SentryConfig.cs b/HandheldCompanion/SentryConfig.cs new file mode 100644 index 000000000..d100446cd --- /dev/null +++ b/HandheldCompanion/SentryConfig.cs @@ -0,0 +1,7 @@ +namespace HandheldCompanion; + +public static class SentryConfig +{ + // Register at Sentry.io and paste the DSN url here + public static string DSN_URL = ""; +} \ No newline at end of file