From c6061aebca01bc32bb091f976888eb784ec5776e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 14 Aug 2026 20:17:27 +0200 Subject: [PATCH] Debugger: don't persist log.channel.set changes to the saved config log.channel.set is meant for temporary, session-only diagnostic tweaks (e.g. quieting a noisy channel while investigating something over the WebSocket debugger). It was going through the same SetLogLevel/SetEnabled calls the UI settings use, so a normal app exit would persist whatever channels/levels the debugger last left set, silently overwriting the user's real saved log preferences for future runs - discovered when a later session's default logging looked "off" for no apparent reason. LogManager now tracks whether the debugger has touched channel config this run and skips SaveConfig() entirely if so, leaving whatever's already on disk untouched. --- Common/File/FileUtil.cpp | 5 +++++ Common/Log/LogManager.cpp | 21 ++++++++++++------- Common/Log/LogManager.h | 6 ++++++ .../WebSocket/LogConfigSubscriber.cpp | 3 +++ Core/HLE/sceKernelModule.cpp | 2 +- Core/HLE/sceUsbMic.cpp | 2 +- 6 files changed, 30 insertions(+), 9 deletions(-) diff --git a/Common/File/FileUtil.cpp b/Common/File/FileUtil.cpp index 5a0734b436..ea1e25c795 100644 --- a/Common/File/FileUtil.cpp +++ b/Common/File/FileUtil.cpp @@ -729,6 +729,11 @@ bool CreateFullPath(const Path &path) { return true; } + if (path.empty()) { + ERROR_LOG(Log::IO, "Can't create an empty path"); + return false; + } + switch (path.Type()) { case PathType::NATIVE: case PathType::CONTENT_URI: diff --git a/Common/Log/LogManager.cpp b/Common/Log/LogManager.cpp index f08eb757ef..20a3569f47 100644 --- a/Common/Log/LogManager.cpp +++ b/Common/Log/LogManager.cpp @@ -208,19 +208,26 @@ void LogManager::SetFileLogPath(const Path &filename) { fp_ = nullptr; } - logFilename_ = Path(filename); + if (!filename.empty()) { + logFilename_ = Path(filename); - if (outputs_ & LogOutput::File) { - File::CreateFullPath(logFilename_.NavigateUp()); - fp_ = File::OpenCFile(logFilename_, "at"); - logFileOpenFailed_ = fp_ == nullptr; - if (logFileOpenFailed_) { - printf("Failed to open log file %s\n", logFilename_.c_str()); + if (outputs_ & LogOutput::File) { + File::CreateFullPath(logFilename_.NavigateUp()); + fp_ = File::OpenCFile(logFilename_, "at"); + logFileOpenFailed_ = fp_ == nullptr; + if (logFileOpenFailed_) { + printf("Failed to open log file %s\n", logFilename_.c_str()); + } } } } void LogManager::SaveConfig(Section *section) { + if (channelsChangedByDebugger_) { + // Leave the section as whatever was already on disk - see the doc comment on + // NotifyChannelsChangedByDebugger(). + return; + } for (int i = 0; i < (int)Log::NUMBER_OF_LOGS; i++) { section->Set((std::string(g_logTypeNames[i]) + "Enabled"), g_log[i].enabled); section->Set((std::string(g_logTypeNames[i]) + "Level"), (int)g_log[i].level); diff --git a/Common/Log/LogManager.h b/Common/Log/LogManager.h index da371efcb3..85b393d9de 100644 --- a/Common/Log/LogManager.h +++ b/Common/Log/LogManager.h @@ -169,6 +169,11 @@ public: void SaveConfig(Section *section); void LoadConfig(const Section *section); + // Channel level/enabled changes made through the WebSocket debugger (log.channel.set) are + // meant as temporary, session-only diagnostic tweaks - call this so SaveConfig() skips + // writing (and thus permanently overwriting) the user's real saved settings with them. + void NotifyChannelsChangedByDebugger() { channelsChangedByDebugger_ = true; } + static const char *GetLogTypeName(Log type); static u32 GetLevelColor(LogLevel level) { @@ -189,6 +194,7 @@ private: void operator=(const LogManager &) = delete; bool initialized_ = false; + bool channelsChangedByDebugger_ = false; #if PPSSPP_PLATFORM(WINDOWS) ConsoleListener *consoleLog_ = nullptr; diff --git a/Core/Debugger/WebSocket/LogConfigSubscriber.cpp b/Core/Debugger/WebSocket/LogConfigSubscriber.cpp index 96acf51304..f3c6d4abe7 100644 --- a/Core/Debugger/WebSocket/LogConfigSubscriber.cpp +++ b/Core/Debugger/WebSocket/LogConfigSubscriber.cpp @@ -119,6 +119,9 @@ void WebSocketLogChannelSet(DebuggerRequest &req) { if (channelName != LogManager::GetLogTypeName(type)) continue; + // These are meant as temporary, session-only diagnostic tweaks - make sure they never + // get written back over the user's actual saved log settings. + g_logManager.NotifyChannelsChangedByDebugger(); if (hasLevel) g_logManager.SetLogLevel(type, level); if (hasEnabled) diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index efd32b3638..f2bd0baad7 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -2199,7 +2199,7 @@ int __KernelStartModule(SceUID moduleId, u32 argsize, u32 argAddr, u32 returnVal // TODO: Why do we skip smoption->attribute here? SceUID threadID = __KernelCreateThread(module->nm.name, moduleId, entryAddr, priority, stacksize, attribute, 0, (module->nm.attribute & 0x1000) != 0); - _dbg_assert_(threadID > 0); + _dbg_assert_msg_(threadID > 0, "__KernelCreateThread returned %08x", threadID); // TOOD: Check the return value and bail? __KernelStartThreadValidate(threadID, argsize, argAddr); __KernelSetThreadRA(threadID, NID_MODULERETURN); diff --git a/Core/HLE/sceUsbMic.cpp b/Core/HLE/sceUsbMic.cpp index 4ff841e620..7db1fe5a9b 100644 --- a/Core/HLE/sceUsbMic.cpp +++ b/Core/HLE/sceUsbMic.cpp @@ -299,7 +299,7 @@ static int sceUsbMicInputInit(int unknown1, int inputVolume, int unknown2) { } static int sceUsbMicWaitInputEnd() { - ERROR_LOG(Log::HLE, "UNIMPL sceUsbMicWaitInputEnd"); + WARN_LOG(Log::HLE, "UNIMPL sceUsbMicWaitInputEnd"); // Hack: Just task switch so other threads get to do work. Helps Beaterator (although recording does not appear to work correctly). return hleDelayResult(0, "MicWait", 100); }