From 84d6e8d121a1b329d26cc0e462aadd1108d99a04 Mon Sep 17 00:00:00 2001 From: jcm Date: Sat, 10 Feb 2024 19:17:19 -0600 Subject: [PATCH] Standardize logging locations across desktop platforms (#6238) * Standardize logging locations across desktop platforms * Return null instead of empty literal on exceptions * Remove LogDirectoryPath from LoggerModule * Catch exception when creating DirectoryInfo in FileLogTarget * Remove redundant log path vars, handle exception better, add null check * Address styling issues * Remove extra newline, quote file path in log, move directory check to OpenHelper * Add GetOrCreateLogsDir to get/create log directory during runtime * misc format changes * Update src/Ryujinx.Common/Configuration/AppDataManager.cs --------- Co-authored-by: jcm Co-authored-by: TSR Berry <20988865+TSRBerry@users.noreply.github.com> Co-authored-by: Ac_K --- .../UI/ViewModels/MainWindowViewModel.cs | 11 +- .../Configuration/AppDataManager.cs | 129 ++++++++++++++++-- .../Logging/Targets/FileLogTarget.cs | 13 +- src/Ryujinx.Headless.SDL2/Program.cs | 16 +-- .../Configuration/LoggerModule.cs | 26 ++-- src/Ryujinx/Ui/MainWindow.cs | 11 +- 6 files changed, 156 insertions(+), 50 deletions(-) diff --git a/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs index 2caee16c..243d870a 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs @@ -1350,16 +1350,11 @@ namespace Ryujinx.Ava.UI.ViewModels public void OpenLogsFolder() { - string logPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"); - - if (LoggerModule.LogDirectoryPath != null) + string logPath = AppDataManager.GetOrCreateLogsDir(); + if (!string.IsNullOrEmpty(logPath)) { - logPath = LoggerModule.LogDirectoryPath; + OpenHelper.OpenFolder(logPath); } - - new DirectoryInfo(logPath).Create(); - - OpenHelper.OpenFolder(logPath); } public void ToggleDockMode() diff --git a/src/Ryujinx.Common/Configuration/AppDataManager.cs b/src/Ryujinx.Common/Configuration/AppDataManager.cs index 35aea3c2..f3df0fc9 100644 --- a/src/Ryujinx.Common/Configuration/AppDataManager.cs +++ b/src/Ryujinx.Common/Configuration/AppDataManager.cs @@ -30,6 +30,8 @@ namespace Ryujinx.Common.Configuration public static string KeysDirPath { get; private set; } public static string KeysDirPathUser { get; } + public static string LogsDirPath { get; private set; } + public const string DefaultNandDir = "bis"; public const string DefaultSdcardDir = "sdcard"; private const string DefaultModsDir = "mods"; @@ -46,15 +48,7 @@ namespace Ryujinx.Common.Configuration public static void Initialize(string baseDirPath) { - string appDataPath; - if (OperatingSystem.IsMacOS()) - { - appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support"); - } - else - { - appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); - } + string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); if (appDataPath.Length == 0) { @@ -118,9 +112,126 @@ namespace Ryujinx.Common.Configuration SetupBasePaths(); } + public static string GetOrCreateLogsDir() + { + if (Directory.Exists(LogsDirPath)) + { + return LogsDirPath; + } + + Logger.Notice.Print(LogClass.Application, "Logging directory not found; attempting to create new logging directory."); + LogsDirPath = SetUpLogsDir(); + + return LogsDirPath; + } + + private static string SetUpLogsDir() + { + string logDir = ""; + + if (Mode == LaunchMode.Portable) + { + logDir = Path.Combine(BaseDirPath, "Logs"); + try + { + Directory.CreateDirectory(logDir); + } + catch + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'"); + + return null; + } + } + else + { + if (OperatingSystem.IsMacOS()) + { + // NOTE: Should evaluate to "~/Library/Logs/Ryujinx/". + logDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Logs", DefaultBaseDir); + try + { + Directory.CreateDirectory(logDir); + } + catch + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'"); + logDir = ""; + } + + if (string.IsNullOrEmpty(logDir)) + { + // NOTE: Should evaluate to "~/Library/Application Support/Ryujinx/Logs". + logDir = Path.Combine(BaseDirPath, "Logs"); + + try + { + Directory.CreateDirectory(logDir); + } + catch + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'"); + + return null; + } + } + } + else if (OperatingSystem.IsWindows()) + { + // NOTE: Should evaluate to a "Logs" directory in whatever directory Ryujinx was launched from. + logDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"); + try + { + Directory.CreateDirectory(logDir); + } + catch + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'"); + logDir = ""; + } + + if (string.IsNullOrEmpty(logDir)) + { + // NOTE: Should evaluate to "C:\Users\user\AppData\Roaming\Ryujinx\Logs". + logDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), DefaultBaseDir, "Logs"); + + try + { + Directory.CreateDirectory(logDir); + } + catch + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'"); + + return null; + } + } + } + else if (OperatingSystem.IsLinux()) + { + // NOTE: Should evaluate to "~/.config/Ryujinx/Logs". + logDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), DefaultBaseDir, "Logs"); + + try + { + Directory.CreateDirectory(logDir); + } + catch + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'"); + + return null; + } + } + } + + return logDir; + } + private static void SetupBasePaths() { Directory.CreateDirectory(BaseDirPath); + LogsDirPath = SetUpLogsDir(); Directory.CreateDirectory(GamesDirPath = Path.Combine(BaseDirPath, GamesDir)); Directory.CreateDirectory(ProfilesDirPath = Path.Combine(BaseDirPath, ProfilesDir)); Directory.CreateDirectory(KeysDirPath = Path.Combine(BaseDirPath, KeysDir)); diff --git a/src/Ryujinx.Common/Logging/Targets/FileLogTarget.cs b/src/Ryujinx.Common/Logging/Targets/FileLogTarget.cs index a4e8f714..8d4ede96 100644 --- a/src/Ryujinx.Common/Logging/Targets/FileLogTarget.cs +++ b/src/Ryujinx.Common/Logging/Targets/FileLogTarget.cs @@ -23,7 +23,18 @@ namespace Ryujinx.Common.Logging.Targets public static FileStream PrepareLogFile(string path) { // Ensure directory is present - DirectoryInfo logDir = new(path); + DirectoryInfo logDir; + try + { + logDir = new DirectoryInfo(path); + } + catch (ArgumentException exception) + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory path ('{path}') was invalid: {exception}"); + + return null; + } + try { logDir.Create(); diff --git a/src/Ryujinx.Headless.SDL2/Program.cs b/src/Ryujinx.Headless.SDL2/Program.cs index c2300275..85aff671 100644 --- a/src/Ryujinx.Headless.SDL2/Program.cs +++ b/src/Ryujinx.Headless.SDL2/Program.cs @@ -427,16 +427,12 @@ namespace Ryujinx.Headless.SDL2 if (!option.DisableFileLog) { - FileStream logFile = FileLogTarget.PrepareLogFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs")); + string logDir = AppDataManager.LogsDirPath; + FileStream logFile = null; - if (logFile == null) + if (!string.IsNullOrEmpty(logDir)) { - logFile = FileLogTarget.PrepareLogFile(Path.Combine(AppDataManager.BaseDirPath, "Logs")); - - if (logFile == null) - { - Logger.Error?.Print(LogClass.Application, "No writable log directory available. Make sure either the application directory or the Ryujinx directory is writable."); - } + logFile = FileLogTarget.PrepareLogFile(logDir); } if (logFile != null) @@ -447,6 +443,10 @@ namespace Ryujinx.Headless.SDL2 AsyncLogTargetOverflowAction.Block )); } + else + { + Logger.Error?.Print(LogClass.Application, "No writable log directory available. Make sure either the Logs directory, Application Data, or the Ryujinx directory is writable."); + } } // Setup graphics configuration diff --git a/src/Ryujinx.Ui.Common/Configuration/LoggerModule.cs b/src/Ryujinx.Ui.Common/Configuration/LoggerModule.cs index f22ee83a..2edcd07f 100644 --- a/src/Ryujinx.Ui.Common/Configuration/LoggerModule.cs +++ b/src/Ryujinx.Ui.Common/Configuration/LoggerModule.cs @@ -9,8 +9,6 @@ namespace Ryujinx.Ui.Common.Configuration { public static class LoggerModule { - public static string LogDirectoryPath { get; private set; } - public static void Initialize() { ConfigurationState.Instance.Logger.EnableDebug.Event += ReloadEnableDebug; @@ -84,26 +82,22 @@ namespace Ryujinx.Ui.Common.Configuration { if (e.NewValue) { - string logDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"); - FileStream logFile = FileLogTarget.PrepareLogFile(logDir); + string logDir = AppDataManager.LogsDirPath; + FileStream logFile = null; + + if (!string.IsNullOrEmpty(logDir)) + { + logFile = FileLogTarget.PrepareLogFile(logDir); + } if (logFile == null) { - logDir = Path.Combine(AppDataManager.BaseDirPath, "Logs"); - logFile = FileLogTarget.PrepareLogFile(logDir); + Logger.Error?.Print(LogClass.Application, "No writable log directory available. Make sure either the Logs directory, Application Data, or the Ryujinx directory is writable."); + Logger.RemoveTarget("file"); - if (logFile == null) - { - Logger.Error?.Print(LogClass.Application, "No writable log directory available. Make sure either the application directory or the Ryujinx directory is writable."); - LogDirectoryPath = null; - Logger.RemoveTarget("file"); - - return; - } + return; } - LogDirectoryPath = logDir; - Logger.AddTarget(new AsyncLogTargetWrapper( new FileLogTarget("file", logFile), 1000, diff --git a/src/Ryujinx/Ui/MainWindow.cs b/src/Ryujinx/Ui/MainWindow.cs index 1ecbb9ea..8bfe09cf 100644 --- a/src/Ryujinx/Ui/MainWindow.cs +++ b/src/Ryujinx/Ui/MainWindow.cs @@ -1376,16 +1376,11 @@ namespace Ryujinx.Ui private void OpenLogsFolder_Pressed(object sender, EventArgs args) { - string logPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"); - - if (LoggerModule.LogDirectoryPath != null) + string logPath = AppDataManager.GetOrCreateLogsDir(); + if (!string.IsNullOrEmpty(logPath)) { - logPath = LoggerModule.LogDirectoryPath; + OpenHelper.OpenFolder(logPath); } - - new DirectoryInfo(logPath).Create(); - - OpenHelper.OpenFolder(logPath); } private void Exit_Pressed(object sender, EventArgs args)