From 323204014c702051012dd2adb0e2327174b15068 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Sat, 3 Aug 2024 11:18:46 +0100 Subject: [PATCH] Flush logs when crashing. When the process is running, we use a finally block to call Log.Dispose and flush any outstanding logs to disk before the process exits. This works when we handle any exception in a matching catch block. When the exception is unhandled, then the finally block will not run and instead the process will just exit. To fix this, flush the logs inside a catch block instead before rethrowing the error. This ensures we get logs even when crashing. --- OpenRA.Launcher/Program.cs | 32 ++++++++++++++++++++++--------- OpenRA.Server/Program.cs | 7 +++++++ OpenRA.Utility/Program.cs | 8 ++++++++ OpenRA.WindowsLauncher/Program.cs | 1 + 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/OpenRA.Launcher/Program.cs b/OpenRA.Launcher/Program.cs index a9cc5cae02..b49d0b9eb0 100644 --- a/OpenRA.Launcher/Program.cs +++ b/OpenRA.Launcher/Program.cs @@ -20,25 +20,39 @@ namespace OpenRA.Launcher [STAThread] static int Main(string[] args) { - try + if (Debugger.IsAttached || args.Contains("--just-die")) { - if (Debugger.IsAttached || args.Contains("--just-die")) - return (int)Game.InitializeAndRun(args); - - AppDomain.CurrentDomain.UnhandledException += (_, e) => ExceptionHandler.HandleFatalError((Exception)e.ExceptionObject); - try { return (int)Game.InitializeAndRun(args); } - catch (Exception e) + catch { - ExceptionHandler.HandleFatalError(e); - return (int)RunStatus.Error; + // Flush logs before rethrowing, i.e. allowing the exception to go unhandled. + // try-finally won't work - an unhandled exception kills our process without running the finally block! + Log.Dispose(); + throw; } + finally + { + Log.Dispose(); + } + } + + AppDomain.CurrentDomain.UnhandledException += (_, e) => ExceptionHandler.HandleFatalError((Exception)e.ExceptionObject); + + try + { + return (int)Game.InitializeAndRun(args); + } + catch (Exception e) + { + ExceptionHandler.HandleFatalError(e); + return (int)RunStatus.Error; } finally { + // Flushing logs in finally block is okay here, as the catch block handles the exception. Log.Dispose(); } } diff --git a/OpenRA.Server/Program.cs b/OpenRA.Server/Program.cs index 7f7191f5ce..55d4ca66d2 100644 --- a/OpenRA.Server/Program.cs +++ b/OpenRA.Server/Program.cs @@ -27,6 +27,13 @@ namespace OpenRA.Server { Run(args); } + catch + { + // Flush logs before rethrowing, i.e. allowing the exception to go unhandled. + // try-finally won't work - an unhandled exception kills our process without running the finally block! + Log.Dispose(); + throw; + } finally { Log.Dispose(); diff --git a/OpenRA.Utility/Program.cs b/OpenRA.Utility/Program.cs index 3de0a5f9bf..8c2e37db1b 100644 --- a/OpenRA.Utility/Program.cs +++ b/OpenRA.Utility/Program.cs @@ -44,6 +44,13 @@ namespace OpenRA { Run(args); } + catch + { + // Flush logs before rethrowing, i.e. allowing the exception to go unhandled. + // try-finally won't work - an unhandled exception kills our process without running the finally block! + Log.Dispose(); + throw; + } finally { Log.Dispose(); @@ -133,6 +140,7 @@ namespace OpenRA if (e is NoSuchCommandException) { Console.WriteLine(e.Message); + Log.Dispose(); // Flush logs before we terminate the process. Environment.Exit(1); } else diff --git a/OpenRA.WindowsLauncher/Program.cs b/OpenRA.WindowsLauncher/Program.cs index 6c2220cf2d..29e4f6553f 100644 --- a/OpenRA.WindowsLauncher/Program.cs +++ b/OpenRA.WindowsLauncher/Program.cs @@ -80,6 +80,7 @@ namespace OpenRA.WindowsLauncher } finally { + // Flushing logs in finally block is okay here, as the catch block handles the exception. Log.Dispose(); } }