diff --git a/src/core/host_interface.cpp b/src/core/host_interface.cpp index 071c3072f..734f5ca32 100644 --- a/src/core/host_interface.cpp +++ b/src/core/host_interface.cpp @@ -39,6 +39,9 @@ bool HostInterface::Initialize() SetUserDirectory(); InitializeUserDirectory(); LoadSettings(); + UpdateLogSettings(m_settings.log_level, m_settings.log_filter.empty() ? nullptr : m_settings.log_filter.c_str(), + m_settings.log_to_console, m_settings.log_to_debug, m_settings.log_to_window, + m_settings.log_to_file); m_game_list = std::make_unique(); m_game_list->SetCacheFilename(GetGameListCacheFileName()); m_game_list->SetDatabaseFilename(GetGameListDatabaseFileName()); @@ -621,6 +624,24 @@ void HostInterface::OnRunningGameChanged() {} void HostInterface::OnControllerTypeChanged(u32 slot) {} +void HostInterface::UpdateLogSettings(LOGLEVEL level, const char* filter, bool log_to_console, bool log_to_debug, + bool log_to_window, bool log_to_file) +{ + Log::SetFilterLevel(level); + Log::SetConsoleOutputParams(m_settings.log_to_console, filter, level); + Log::SetDebugOutputParams(m_settings.log_to_debug, filter, level); + + if (log_to_file) + { + Log::SetFileOutputParams(m_settings.log_to_file, GetUserDirectoryRelativePath("duckstation.log").c_str(), true, + filter, level); + } + else + { + Log::SetFileOutputParams(false, nullptr); + } +} + void HostInterface::SetUserDirectory() { if (!m_user_directory.empty()) @@ -628,13 +649,13 @@ void HostInterface::SetUserDirectory() const std::string program_path = FileSystem::GetProgramPath(); const std::string program_directory = FileSystem::GetPathDirectory(program_path.c_str()); - Log_InfoPrintf("Program path: \"%s\" (directory \"%s\")", program_path.c_str(), program_directory.c_str()); + std::fprintf(stdout, "Program path: \"%s\" (directory \"%s\")\n", program_path.c_str(), program_directory.c_str()); if (FileSystem::FileExists(StringUtil::StdStringFromFormat("%s%c%s", program_directory.c_str(), FS_OSPATH_SEPERATOR_CHARACTER, "portable.txt") .c_str())) { - Log_InfoPrintf("portable.txt found, using program directory as user directory."); + std::fprintf(stdout, "portable.txt found, using program directory as user directory.\n"); m_user_directory = program_directory; } else @@ -677,16 +698,16 @@ void HostInterface::SetUserDirectoryToProgramDirectory() void HostInterface::InitializeUserDirectory() { - Log_InfoPrintf("User directory: \"%s\"", m_user_directory.c_str()); + std::fprintf(stdout, "User directory: \"%s\"\n", m_user_directory.c_str()); if (m_user_directory.empty()) Panic("Cannot continue without user directory set."); if (!FileSystem::DirectoryExists(m_user_directory.c_str())) { - Log_WarningPrintf("User directory \"%s\" does not exist, creating.", m_user_directory.c_str()); + std::fprintf(stderr, "User directory \"%s\" does not exist, creating.\n", m_user_directory.c_str()); if (!FileSystem::CreateDirectory(m_user_directory.c_str(), true)) - Log_ErrorPrintf("Failed to create user directory \"%s\".", m_user_directory.c_str()); + std::fprintf(stderr, "Failed to create user directory \"%s\".\n", m_user_directory.c_str()); } bool result = true; @@ -905,9 +926,8 @@ void HostInterface::CheckSettings(SettingsInterface& si) if (settings_version == SETTINGS_VERSION) return; - // TODO: we probably should delete all the sections in the ini... - Log_WarningPrintf("Settings version %d does not match expected version %d, resetting", settings_version, - SETTINGS_VERSION); + ReportFormattedError("Settings version %d does not match expected version %d, resetting", settings_version, + SETTINGS_VERSION); si.Clear(); si.SetIntValue("Main", "SettingsVersion", SETTINGS_VERSION); SetDefaultSettings(si); @@ -964,6 +984,13 @@ void HostInterface::SetDefaultSettings(SettingsInterface& si) si.SetStringValue("MemoryCards", "Card2Type", "None"); si.SetStringValue("MemoryCards", "Card2Path", "memcards/shared_card_2.mcd"); + si.SetStringValue("Logging", "LogLevel", Settings::GetLogLevelName(LOGLEVEL_INFO)); + si.SetStringValue("Logging", "LogFilter", ""); + si.SetBoolValue("Logging", "LogToConsole", false); + si.SetBoolValue("Logging", "LogToDebug", false); + si.SetBoolValue("Logging", "LogToWindow", false); + si.SetBoolValue("Logging", "LogToFile", false); + si.SetBoolValue("Debug", "ShowVRAM", false); si.SetBoolValue("Debug", "DumpCPUToVRAMCopies", false); si.SetBoolValue("Debug", "DumpVRAMToCPUCopies", false); @@ -1002,6 +1029,12 @@ void HostInterface::UpdateSettings(const std::function& apply_callback) std::array old_memory_card_paths = std::move(m_settings.memory_card_paths); + const LOGLEVEL old_log_level = m_settings.log_level; + const std::string old_log_filter(std::move(m_settings.log_filter)); + const bool old_log_to_console = m_settings.log_to_console; + const bool old_log_to_window = m_settings.log_to_window; + const bool old_log_to_file = m_settings.log_to_file; + apply_callback(); if (m_system) @@ -1080,6 +1113,15 @@ void HostInterface::UpdateSettings(const std::function& apply_callback) if (m_display && m_settings.display_linear_filtering != old_display_linear_filtering) m_display->SetDisplayLinearFiltering(m_settings.display_linear_filtering); + + if (m_settings.log_level != old_log_level || m_settings.log_filter != old_log_filter || + m_settings.log_to_console != old_log_to_console || m_settings.log_to_window != old_log_to_window || + m_settings.log_to_file != old_log_to_file) + { + UpdateLogSettings(m_settings.log_level, m_settings.log_filter.empty() ? nullptr : m_settings.log_filter.c_str(), + m_settings.log_to_console, m_settings.log_to_debug, m_settings.log_to_window, + m_settings.log_to_file); + } } void HostInterface::ToggleSoftwareRendering() diff --git a/src/core/host_interface.h b/src/core/host_interface.h index c6c9d8a6b..873b59e57 100644 --- a/src/core/host_interface.h +++ b/src/core/host_interface.h @@ -12,6 +12,8 @@ #include #include +enum LOGLEVEL; + class AudioStream; class ByteStream; class CDImage; @@ -193,6 +195,10 @@ protected: /// Performs the initial load of settings. Should call CheckSettings() and m_settings.Load(). virtual void LoadSettings() = 0; + /// Updates logging settings. + virtual void UpdateLogSettings(LOGLEVEL level, const char* filter, bool log_to_console, bool log_to_debug, + bool log_to_window, bool log_to_file); + /// Returns the path of the settings file. std::string GetSettingsFileName() const; diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 8c5c68f5c..e15b984d1 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -79,6 +79,14 @@ void Settings::Load(SettingsInterface& si) .value_or(MemoryCardType::None); memory_card_paths[1] = si.GetStringValue("MemoryCards", "Card2Path", "memcards/shared_card_2.mcd"); + log_level = ParseLogLevelName(si.GetStringValue("Logging", "LogLevel", GetLogLevelName(LOGLEVEL_INFO)).c_str()) + .value_or(LOGLEVEL_INFO); + log_filter = si.GetStringValue("Logging", "LogFilter", ""); + log_to_console = si.GetBoolValue("Logging", "LogToConsole", false); + log_to_debug = si.GetBoolValue("Logging", "LogToDebug", false); + log_to_window = si.GetBoolValue("Logging", "LogToWindow", false); + log_to_file = si.GetBoolValue("Logging", "LogToFile", false); + debugging.show_vram = si.GetBoolValue("Debug", "ShowVRAM"); debugging.dump_cpu_to_vram_copies = si.GetBoolValue("Debug", "DumpCPUToVRAMCopies"); debugging.dump_vram_to_cpu_copies = si.GetBoolValue("Debug", "DumpVRAMToCPUCopies"); @@ -147,6 +155,13 @@ void Settings::Save(SettingsInterface& si) const si.SetStringValue("MemoryCards", "Card2Type", GetMemoryCardTypeName(memory_card_types[1])); si.SetStringValue("MemoryCards", "Card2Path", memory_card_paths[1].c_str()); + si.SetStringValue("Logging", "LogLevel", GetLogLevelName(log_level)); + si.SetStringValue("Logging", "LogFilter", log_filter.c_str()); + si.SetBoolValue("Logging", "LogToConsole", log_to_console); + si.SetBoolValue("Logging", "LogToDebug", log_to_debug); + si.SetBoolValue("Logging", "LogToWindow", log_to_window); + si.SetBoolValue("Logging", "LogToFile", log_to_file); + si.SetBoolValue("Debug", "ShowVRAM", debugging.show_vram); si.SetBoolValue("Debug", "DumpCPUToVRAMCopies", debugging.dump_cpu_to_vram_copies); si.SetBoolValue("Debug", "DumpVRAMToCPUCopies", debugging.dump_vram_to_cpu_copies); @@ -157,6 +172,35 @@ void Settings::Save(SettingsInterface& si) const si.SetBoolValue("Debug", "ShowMDECState", debugging.show_mdec_state); } +static std::array s_log_level_names = { + {"None", "Error", "Warning", "Perf", "Success", "Info", "Dev", "Profile", "Debug", "Trace"}}; +static std::array s_log_level_display_names = { + {"None", "Error", "Warning", "Performance", "Success", "Information", "Developer", "Profile", "Debug", "Trace"}}; + +std::optional Settings::ParseLogLevelName(const char* str) +{ + int index = 0; + for (const char* name : s_log_level_names) + { + if (StringUtil::Strcasecmp(name, str) == 0) + return static_cast(index); + + index++; + } + + return std::nullopt; +} + +const char* Settings::GetLogLevelName(LOGLEVEL level) +{ + return s_log_level_names[static_cast(level)]; +} + +const char* Settings::GetLogLevelDisplayName(LOGLEVEL level) +{ + return s_log_level_display_names[static_cast(level)]; +} + static std::array s_console_region_names = {{"Auto", "NTSC-J", "NTSC-U", "PAL"}}; static std::array s_console_region_display_names = { {"Auto-Detect", "NTSC-J (Japan)", "NTSC-U (US)", "PAL (Europe, Australia)"}}; diff --git a/src/core/settings.h b/src/core/settings.h index 389c672e6..8b0057751 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -1,4 +1,5 @@ #pragma once +#include "common/log.h" #include "types.h" #include #include @@ -99,6 +100,13 @@ struct Settings std::array memory_card_types{}; std::array memory_card_paths{}; + LOGLEVEL log_level = LOGLEVEL_INFO; + std::string log_filter; + bool log_to_console = false; + bool log_to_debug = false; + bool log_to_window = false; + bool log_to_file = false; + ALWAYS_INLINE bool HasAnyPerGameMemoryCards() const { return (memory_card_types[0] == MemoryCardType::PerGame || memory_card_types[1] == MemoryCardType::PerGame); @@ -107,6 +115,10 @@ struct Settings void Load(SettingsInterface& si); void Save(SettingsInterface& si) const; + static std::optional ParseLogLevelName(const char* str); + static const char* GetLogLevelName(LOGLEVEL level); + static const char* GetLogLevelDisplayName(LOGLEVEL level); + static std::optional ParseConsoleRegionName(const char* str); static const char* GetConsoleRegionName(ConsoleRegion region); static const char* GetConsoleRegionDisplayName(ConsoleRegion region);