From f841e18bd55eadecd85e2c53b2447081cffc9e26 Mon Sep 17 00:00:00 2001 From: Vladimir Sumarov Date: Mon, 9 Feb 2026 17:11:31 -0800 Subject: [PATCH 1/6] put limit on log lines app keeps for Sentry --- obs-studio-server/source/nodeobs_api.cpp | 6 ++-- obs-studio-server/source/nodeobs_api.h | 28 +++++++++++-------- .../source/util-crashmanager.cpp | 14 ++++++---- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/obs-studio-server/source/nodeobs_api.cpp b/obs-studio-server/source/nodeobs_api.cpp index 570081273..741fc1604 100644 --- a/obs-studio-server/source/nodeobs_api.cpp +++ b/obs-studio-server/source/nodeobs_api.cpp @@ -2048,17 +2048,17 @@ double OBS_API::getMemoryUsage() return (double)os_get_proc_resident_size() / (1024.0 * 1024.0); } -const std::vector &OBS_API::getOBSLogErrors() +std::deque &OBS_API::getOBSLogErrors() { return logReport.errors; } -const std::vector &OBS_API::getOBSLogWarnings() +std::deque &OBS_API::getOBSLogWarnings() { return logReport.warnings; } -std::queue &OBS_API::getOBSLogGeneral() +std::deque &OBS_API::getOBSLogGeneral() { return logReport.general; } diff --git a/obs-studio-server/source/nodeobs_api.h b/obs-studio-server/source/nodeobs_api.h index bfcd189a5..5563179ad 100644 --- a/obs-studio-server/source/nodeobs_api.h +++ b/obs-studio-server/source/nodeobs_api.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include "nodeobs_configManager.hpp" #include "nodeobs_service.h" #include "util-osx.hpp" @@ -44,27 +44,33 @@ class OBS_API { public: struct LogReport { - static const int MaximumGeneralMessages = 150; + static const int MaximumMessages = 150; void push(std::string message, int logLevel) { - general.push(message); - if (general.size() >= MaximumGeneralMessages) { - general.pop(); + general.push_back(message); + if (general.size() > MaximumMessages) { + general.pop_front(); } if (logLevel == LOG_ERROR) { errors.push_back(message); + if (errors.size() > MaximumMessages) { + errors.pop_front(); + } } if (logLevel == LOG_WARNING) { warnings.push_back(message); + if (warnings.size() > MaximumMessages) { + warnings.pop_front(); + } } } - std::vector errors; - std::vector warnings; - std::queue general; + std::deque errors; + std::deque warnings; + std::deque general; }; struct OutputStats { @@ -130,9 +136,9 @@ class OBS_API { static double getMemoryUsage(); static void getCurrentOutputStats(obs_output_t *output, OBS_API::OutputStats &outputStats); - static const std::vector &getOBSLogErrors(); - static const std::vector &getOBSLogWarnings(); - static std::queue &getOBSLogGeneral(); + static std::deque &getOBSLogErrors(); + static std::deque &getOBSLogWarnings(); + static std::deque &getOBSLogGeneral(); static std::string getCurrentVersion(); static std::string getUsername(); diff --git a/obs-studio-server/source/util-crashmanager.cpp b/obs-studio-server/source/util-crashmanager.cpp index cde3e2a3a..725295a8e 100644 --- a/obs-studio-server/source/util-crashmanager.cpp +++ b/obs-studio-server/source/util-crashmanager.cpp @@ -1028,15 +1028,19 @@ nlohmann::json util::CrashManager::RequestOBSLog(OBSLogType type) switch (type) { case OBSLogType::Errors: { auto &errors = OBS_API::getOBSLogErrors(); - for (auto &msg : errors) - result.push_back(msg); + while (!errors.empty()) { + result.push_back(errors.front()); + errors.pop_front(); + } break; } case OBSLogType::Warnings: { auto &warnings = OBS_API::getOBSLogWarnings(); - for (auto &msg : warnings) - result.push_back(msg); + while (!warnings.empty()) { + result.push_back(warnings.front()); + warnings.pop_front(); + } break; } @@ -1044,7 +1048,7 @@ nlohmann::json util::CrashManager::RequestOBSLog(OBSLogType type) auto &general = OBS_API::getOBSLogGeneral(); while (!general.empty()) { result.push_back(general.front()); - general.pop(); + general.pop_front(); } break; From bca97f5aafe7f6b73f57b4744e683a7bb7d130cf Mon Sep 17 00:00:00 2001 From: Vladimir Sumarov Date: Fri, 22 May 2026 10:36:37 -0700 Subject: [PATCH 2/6] Drop unused LogReport errors/warnings buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Errors and Warnings branches of RequestOBSLog were never invoked — HandleCrash only requests General. The backing deques were filled on every blog() call but never read, just kept around as dead state. Collapse the OBSLogType enum, drop getOBSLogErrors/getOBSLogWarnings, simplify LogReport::push to a single deque, and reduce RequestOBSLog to its one real path. --- obs-studio-server/source/nodeobs_api.cpp | 12 +------ obs-studio-server/source/nodeobs_api.h | 20 +---------- .../source/util-crashmanager.cpp | 36 ++++--------------- obs-studio-server/source/util-crashmanager.h | 5 +-- 4 files changed, 9 insertions(+), 64 deletions(-) diff --git a/obs-studio-server/source/nodeobs_api.cpp b/obs-studio-server/source/nodeobs_api.cpp index 741fc1604..6233b64fb 100644 --- a/obs-studio-server/source/nodeobs_api.cpp +++ b/obs-studio-server/source/nodeobs_api.cpp @@ -543,7 +543,7 @@ static void node_obs_log(int log_level, const char *msg, va_list args, void *par } // Internal Log - logReport.push(newmsg, log_level); + logReport.push(newmsg); // Std Out / Std Err /// Why fwrite and not std::cout and std::cerr? @@ -2048,16 +2048,6 @@ double OBS_API::getMemoryUsage() return (double)os_get_proc_resident_size() / (1024.0 * 1024.0); } -std::deque &OBS_API::getOBSLogErrors() -{ - return logReport.errors; -} - -std::deque &OBS_API::getOBSLogWarnings() -{ - return logReport.warnings; -} - std::deque &OBS_API::getOBSLogGeneral() { return logReport.general; diff --git a/obs-studio-server/source/nodeobs_api.h b/obs-studio-server/source/nodeobs_api.h index 5563179ad..310a20f74 100644 --- a/obs-studio-server/source/nodeobs_api.h +++ b/obs-studio-server/source/nodeobs_api.h @@ -46,30 +46,14 @@ class OBS_API { struct LogReport { static const int MaximumMessages = 150; - void push(std::string message, int logLevel) + void push(std::string message) { general.push_back(message); if (general.size() > MaximumMessages) { general.pop_front(); } - - if (logLevel == LOG_ERROR) { - errors.push_back(message); - if (errors.size() > MaximumMessages) { - errors.pop_front(); - } - } - - if (logLevel == LOG_WARNING) { - warnings.push_back(message); - if (warnings.size() > MaximumMessages) { - warnings.pop_front(); - } - } } - std::deque errors; - std::deque warnings; std::deque general; }; @@ -136,8 +120,6 @@ class OBS_API { static double getMemoryUsage(); static void getCurrentOutputStats(obs_output_t *output, OBS_API::OutputStats &outputStats); - static std::deque &getOBSLogErrors(); - static std::deque &getOBSLogWarnings(); static std::deque &getOBSLogGeneral(); static std::string getCurrentVersion(); diff --git a/obs-studio-server/source/util-crashmanager.cpp b/obs-studio-server/source/util-crashmanager.cpp index 725295a8e..320b21596 100644 --- a/obs-studio-server/source/util-crashmanager.cpp +++ b/obs-studio-server/source/util-crashmanager.cpp @@ -718,7 +718,7 @@ void util::CrashManager::HandleCrash(const std::string &_crashInfo, bool callAbo } try { - annotations.insert({{"OBS log general", RequestOBSLog(OBSLogType::General).dump(4)}}); + annotations.insert({{"OBS log general", RequestOBSLog().dump(4)}}); annotations.insert({{"Crash reason", _crashInfo}}); annotations.insert({{"Computer name", computerName}}); annotations.insert({{"Breadcrumbs", ComputeBreadcrumbs().dump(4)}}); @@ -1021,38 +1021,14 @@ void RewindCallStack() return; } -nlohmann::json util::CrashManager::RequestOBSLog(OBSLogType type) +nlohmann::json util::CrashManager::RequestOBSLog() { nlohmann::json result; - switch (type) { - case OBSLogType::Errors: { - auto &errors = OBS_API::getOBSLogErrors(); - while (!errors.empty()) { - result.push_back(errors.front()); - errors.pop_front(); - } - break; - } - - case OBSLogType::Warnings: { - auto &warnings = OBS_API::getOBSLogWarnings(); - while (!warnings.empty()) { - result.push_back(warnings.front()); - warnings.pop_front(); - } - break; - } - - case OBSLogType::General: { - auto &general = OBS_API::getOBSLogGeneral(); - while (!general.empty()) { - result.push_back(general.front()); - general.pop_front(); - } - - break; - } + auto &general = OBS_API::getOBSLogGeneral(); + while (!general.empty()) { + result.push_back(general.front()); + general.pop_front(); } std::reverse(result.begin(), result.end()); diff --git a/obs-studio-server/source/util-crashmanager.h b/obs-studio-server/source/util-crashmanager.h index 5efbd94eb..fa4307b5a 100644 --- a/obs-studio-server/source/util-crashmanager.h +++ b/obs-studio-server/source/util-crashmanager.h @@ -40,9 +40,6 @@ namespace util { class MetricsProvider; class CrashManager { -public: - enum OBSLogType { General, Errors, Warnings }; - public: bool Initialize(char *path, const std::string &app_state_path); void Configure(); @@ -84,7 +81,7 @@ class CrashManager { #endif private: - static nlohmann::json RequestOBSLog(OBSLogType type); + static nlohmann::json RequestOBSLog(); static nlohmann::json ComputeBreadcrumbs(); static nlohmann::json ComputeActions(); static nlohmann::json ComputeWarnings(); From e00965b3903cbf468ba4f85cd982b9e4d2b7b965 Mon Sep 17 00:00:00 2001 From: Vladimir Sumarov Date: Fri, 22 May 2026 10:38:12 -0700 Subject: [PATCH 3/6] Rename crashmanager warnings to serverWarnings and cap to 50 The static "warnings" vector and AddWarning/ComputeWarnings shared a name with libOBS LogReport::warnings (now removed) but held a different thing: programmatic notes from the server about file-open failures, encoder failures, and IPC error returns. Rename them to serverWarnings/AddServerWarning/ComputeServerWarnings and the Sentry annotation key from "Warnings" to "Server warnings" so a reader can tell at a glance these are server-detected anomalies, not log lines. Cap the deque at 50. ProcessPostServerCall fires AddServerWarning on every IPC error return, so a noisy session could previously grow it without bound. --- obs-studio-server/source/nodeobs_api.cpp | 6 ++--- obs-studio-server/source/nodeobs_service.cpp | 4 ++-- .../source/util-crashmanager.cpp | 24 ++++++++++++------- obs-studio-server/source/util-crashmanager.h | 4 ++-- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/obs-studio-server/source/nodeobs_api.cpp b/obs-studio-server/source/nodeobs_api.cpp index 6233b64fb..b7e5815d1 100644 --- a/obs-studio-server/source/nodeobs_api.cpp +++ b/obs-studio-server/source/nodeobs_api.cpp @@ -885,7 +885,7 @@ void OBS_API::OBS_API_initAPI(void *data, const int64_t id, const std::vectorlogStream.is_open()) { logParam.reset(); - util::CrashManager::AddWarning("Error on log file, failed to open: " + log_path); + util::CrashManager::AddServerWarning("Error on log file, failed to open: " + log_path); std::cerr << "Failed to open log file" << std::endl; } base_set_log_handler(node_obs_log, (logParam) ? logParam.release() : nullptr); @@ -964,7 +964,7 @@ void OBS_API::OBS_API_initAPI(void *data, const int64_t id, const std::vectorBlameServer(); #endif diff --git a/obs-studio-server/source/util-crashmanager.cpp b/obs-studio-server/source/util-crashmanager.cpp index 320b21596..bf9dc1854 100644 --- a/obs-studio-server/source/util-crashmanager.cpp +++ b/obs-studio-server/source/util-crashmanager.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -75,7 +76,8 @@ ////////////////////// std::vector breadcrumbs; std::queue> lastActions; -std::vector warnings; +std::deque serverWarnings; +constexpr size_t MaximumServerWarnings = 50; std::mutex messageMutex; #ifdef WIN32 // Global/static variables @@ -723,7 +725,7 @@ void util::CrashManager::HandleCrash(const std::string &_crashInfo, bool callAbo annotations.insert({{"Computer name", computerName}}); annotations.insert({{"Breadcrumbs", ComputeBreadcrumbs().dump(4)}}); annotations.insert({{"Last actions", ComputeActions().dump(4)}}); - annotations.insert({{"Warnings", ComputeWarnings().dump(4)}}); + annotations.insert({{"Server warnings", ComputeServerWarnings().dump(4)}}); } catch (...) { } @@ -1066,11 +1068,12 @@ nlohmann::json util::CrashManager::ComputeActions() return result; } -nlohmann::json util::CrashManager::ComputeWarnings() +nlohmann::json util::CrashManager::ComputeServerWarnings() { nlohmann::json result; - for (auto &msg : warnings) + std::lock_guard lock(messageMutex); + for (auto &msg : serverWarnings) result.push_back(msg); return result; @@ -1229,10 +1232,13 @@ void util::CrashManager::IPCValuesToData(const std::vector &values, } } -void util::CrashManager::AddWarning(const std::string &warning) +void util::CrashManager::AddServerWarning(const std::string &warning) { std::lock_guard lock(messageMutex); - warnings.push_back(warning); + serverWarnings.push_back(warning); + if (serverWarnings.size() > MaximumServerWarnings) { + serverWarnings.pop_front(); + } } void RegisterAction(const std::string &message) @@ -1329,10 +1335,10 @@ void util::CrashManager::ProcessPreServerCall(const std::string &cname, const st void util::CrashManager::ProcessPostServerCall(const std::string &cname, const std::string &fname, const std::vector &args) { if (args.size() == 0) { - AddWarning(std::string("No return params on method ") + fname + std::string(" for class ") + cname); + AddServerWarning(std::string("No return params on method ") + fname + std::string(" for class ") + cname); } else if ((ErrorCode)args[0].value_union.ui64 != ErrorCode::Ok) { - AddWarning(std::string("Server call returned error number ") + std::to_string(args[0].value_union.ui64) + " on method " + fname + - std::string(" for class ") + cname); + AddServerWarning(std::string("Server call returned error number ") + std::to_string(args[0].value_union.ui64) + " on method " + fname + + std::string(" for class ") + cname); } } diff --git a/obs-studio-server/source/util-crashmanager.h b/obs-studio-server/source/util-crashmanager.h index fa4307b5a..78f7527f9 100644 --- a/obs-studio-server/source/util-crashmanager.h +++ b/obs-studio-server/source/util-crashmanager.h @@ -46,7 +46,7 @@ class CrashManager { void OpenConsole(); static void IPCValuesToData(const std::vector &, nlohmann::json &); - static void AddWarning(const std::string &warning); + static void AddServerWarning(const std::string &warning); static void AddBreadcrumb(const nlohmann::json &message); static void AddBreadcrumb(const std::string &message); static void ClearBreadcrumbs(); @@ -84,7 +84,7 @@ class CrashManager { static nlohmann::json RequestOBSLog(); static nlohmann::json ComputeBreadcrumbs(); static nlohmann::json ComputeActions(); - static nlohmann::json ComputeWarnings(); + static nlohmann::json ComputeServerWarnings(); static bool SetupCrashpad(); static bool TryHandleCrash(const std::string &format, const std::string &crashMessage); static void HandleExit() noexcept; From f7d63cad54877eeca9834d8b17a9942cc7212cd7 Mon Sep 17 00:00:00 2001 From: Vladimir Sumarov Date: Fri, 22 May 2026 10:39:06 -0700 Subject: [PATCH 4/6] Remove dead breadcrumbs code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AddBreadcrumb, ClearBreadcrumbs, ComputeBreadcrumbs, and the breadcrumbs static vector were public but never called anywhere — the "Breadcrumbs" Sentry annotation was always an empty list. Drop the unused functions, the vector, and the empty annotation. --- .../source/util-crashmanager.cpp | 33 ------------------- obs-studio-server/source/util-crashmanager.h | 4 --- 2 files changed, 37 deletions(-) diff --git a/obs-studio-server/source/util-crashmanager.cpp b/obs-studio-server/source/util-crashmanager.cpp index bf9dc1854..fd2fef66c 100644 --- a/obs-studio-server/source/util-crashmanager.cpp +++ b/obs-studio-server/source/util-crashmanager.cpp @@ -74,7 +74,6 @@ ////////////////////// // STATIC VARIABLES // ////////////////////// -std::vector breadcrumbs; std::queue> lastActions; std::deque serverWarnings; constexpr size_t MaximumServerWarnings = 50; @@ -723,7 +722,6 @@ void util::CrashManager::HandleCrash(const std::string &_crashInfo, bool callAbo annotations.insert({{"OBS log general", RequestOBSLog().dump(4)}}); annotations.insert({{"Crash reason", _crashInfo}}); annotations.insert({{"Computer name", computerName}}); - annotations.insert({{"Breadcrumbs", ComputeBreadcrumbs().dump(4)}}); annotations.insert({{"Last actions", ComputeActions().dump(4)}}); annotations.insert({{"Server warnings", ComputeServerWarnings().dump(4)}}); } catch (...) { @@ -1038,16 +1036,6 @@ nlohmann::json util::CrashManager::RequestOBSLog() return result; } -nlohmann::json util::CrashManager::ComputeBreadcrumbs() -{ - nlohmann::json result = nlohmann::json::array(); - - for (auto &msg : breadcrumbs) - result.push_back(msg); - - return result; -} - nlohmann::json util::CrashManager::ComputeActions() { nlohmann::json result = nlohmann::json::array(); @@ -1257,27 +1245,6 @@ void RegisterAction(const std::string &message) } } -void util::CrashManager::AddBreadcrumb(const nlohmann::json &message) -{ - std::lock_guard lock(messageMutex); - breadcrumbs.push_back(message); -} - -void util::CrashManager::AddBreadcrumb(const std::string &message) -{ - nlohmann::json j = nlohmann::json::array(); - j.push_back({{message}}); - - std::lock_guard lock(messageMutex); - breadcrumbs.push_back(j); -} - -void util::CrashManager::ClearBreadcrumbs() -{ - std::lock_guard lock(messageMutex); - breadcrumbs.clear(); -} - void util::CrashManager::setAppState(const std::string &newState) { appState = newState; diff --git a/obs-studio-server/source/util-crashmanager.h b/obs-studio-server/source/util-crashmanager.h index 78f7527f9..b421c2661 100644 --- a/obs-studio-server/source/util-crashmanager.h +++ b/obs-studio-server/source/util-crashmanager.h @@ -47,9 +47,6 @@ class CrashManager { static void IPCValuesToData(const std::vector &, nlohmann::json &); static void AddServerWarning(const std::string &warning); - static void AddBreadcrumb(const nlohmann::json &message); - static void AddBreadcrumb(const std::string &message); - static void ClearBreadcrumbs(); static void DisableReports(); static void setAppState(const std::string &newState); static std::string getAppState(); @@ -82,7 +79,6 @@ class CrashManager { private: static nlohmann::json RequestOBSLog(); - static nlohmann::json ComputeBreadcrumbs(); static nlohmann::json ComputeActions(); static nlohmann::json ComputeServerWarnings(); static bool SetupCrashpad(); From 8886ac549aef0b0b67fc15077ee52504de315835 Mon Sep 17 00:00:00 2001 From: Vladimir Sumarov Date: Fri, 22 May 2026 10:39:34 -0700 Subject: [PATCH 5/6] Document Sentry annotations attached in HandleCrash Spell out what each "log-shaped" annotation represents and where its cap lives, so a future reader doesn't need to chase three files to understand what ends up in a crash report. --- obs-studio-server/source/util-crashmanager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/obs-studio-server/source/util-crashmanager.cpp b/obs-studio-server/source/util-crashmanager.cpp index fd2fef66c..9d156db02 100644 --- a/obs-studio-server/source/util-crashmanager.cpp +++ b/obs-studio-server/source/util-crashmanager.cpp @@ -718,6 +718,10 @@ void util::CrashManager::HandleCrash(const std::string &_crashInfo, bool callAbo } catch (...) { } + // Annotations attached to the Sentry minidump: + // "OBS log general" — rolling tail of the libOBS log (capped at LogReport::MaximumMessages lines) + // "Last actions" — recent IPC calls received by the server (capped at MaximumActionsRegistered) + // "Server warnings" — server-detected anomalies recorded via AddServerWarning (capped at MaximumServerWarnings) try { annotations.insert({{"OBS log general", RequestOBSLog().dump(4)}}); annotations.insert({{"Crash reason", _crashInfo}}); From c0b274ec15e68ebeea925f4222d0fb1a101677c9 Mon Sep 17 00:00:00 2001 From: Vladimir Sumarov Date: Mon, 1 Jun 2026 13:38:08 -0700 Subject: [PATCH 6/6] Address review: bound actions, lock-safe crash-time reads - RegisterAction: pop on size() > Maximum so it truly retains 50 (was >=, capping at 49); matches AddServerWarning and the PR description. - ComputeServerWarnings: try_to_lock messageMutex instead of a blocking lock_guard. The crashing thread may already hold it (crashed inside AddServerWarning/RegisterAction); a blocking acquire would hang crash reporting. Return empty if it can't be acquired. - Replace OBS_API::getOBSLogGeneral() (returned a mutable deque ref that RequestOBSLog drained with no synchronization, racing node_obs_log()) with snapshotOBSLogGeneral(): copies and clears logReport.general under logMutex via try_to_lock. RequestOBSLog now consumes the snapshot, reverse-iterating to keep the newest-first ordering. - Include explicitly (std::transform was relying on a transitive include). Co-Authored-By: Claude Opus 4.8 (1M context) --- obs-studio-server/source/nodeobs_api.cpp | 10 +++++++-- obs-studio-server/source/nodeobs_api.h | 5 ++++- .../source/util-crashmanager.cpp | 21 +++++++++++-------- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/obs-studio-server/source/nodeobs_api.cpp b/obs-studio-server/source/nodeobs_api.cpp index b7e5815d1..527b2868e 100644 --- a/obs-studio-server/source/nodeobs_api.cpp +++ b/obs-studio-server/source/nodeobs_api.cpp @@ -2048,9 +2048,15 @@ double OBS_API::getMemoryUsage() return (double)os_get_proc_resident_size() / (1024.0 * 1024.0); } -std::deque &OBS_API::getOBSLogGeneral() +std::deque OBS_API::snapshotOBSLogGeneral() { - return logReport.general; + std::unique_lock lock(logMutex, std::try_to_lock); + if (!lock.owns_lock()) + return {}; + + std::deque snapshot = std::move(logReport.general); + logReport.general.clear(); + return snapshot; } std::string OBS_API::getCurrentVersion() diff --git a/obs-studio-server/source/nodeobs_api.h b/obs-studio-server/source/nodeobs_api.h index 310a20f74..30a92eb58 100644 --- a/obs-studio-server/source/nodeobs_api.h +++ b/obs-studio-server/source/nodeobs_api.h @@ -120,7 +120,10 @@ class OBS_API { static double getMemoryUsage(); static void getCurrentOutputStats(obs_output_t *output, OBS_API::OutputStats &outputStats); - static std::deque &getOBSLogGeneral(); + // Snapshot (and clear) the general log tail under logMutex. Uses try_lock — the crash + // handler calls this and must never block on the logging thread. Returns oldest-first, + // empty if the lock can't be acquired. + static std::deque snapshotOBSLogGeneral(); static std::string getCurrentVersion(); static std::string getUsername(); diff --git a/obs-studio-server/source/util-crashmanager.cpp b/obs-studio-server/source/util-crashmanager.cpp index 9d156db02..04f7be3ca 100644 --- a/obs-studio-server/source/util-crashmanager.cpp +++ b/obs-studio-server/source/util-crashmanager.cpp @@ -19,6 +19,7 @@ #include "util-crashmanager.h" #include "util-metricsprovider.h" +#include #include #include #include @@ -1029,13 +1030,10 @@ nlohmann::json util::CrashManager::RequestOBSLog() { nlohmann::json result; - auto &general = OBS_API::getOBSLogGeneral(); - while (!general.empty()) { - result.push_back(general.front()); - general.pop_front(); - } - - std::reverse(result.begin(), result.end()); + // snapshotOBSLogGeneral returns oldest-first under logMutex; emit newest-first. + std::deque general = OBS_API::snapshotOBSLogGeneral(); + for (auto it = general.rbegin(); it != general.rend(); ++it) + result.push_back(*it); return result; } @@ -1064,7 +1062,12 @@ nlohmann::json util::CrashManager::ComputeServerWarnings() { nlohmann::json result; - std::lock_guard lock(messageMutex); + // try_lock — the crashing thread may already hold messageMutex (e.g. it crashed inside + // AddServerWarning/RegisterAction); a blocking lock would hang crash reporting. + std::unique_lock lock(messageMutex, std::try_to_lock); + if (!lock.owns_lock()) + return result; + for (auto &msg : serverWarnings) result.push_back(msg); @@ -1243,7 +1246,7 @@ void RegisterAction(const std::string &message) lastActions.back().first++; } else { lastActions.push({0, message}); - if (lastActions.size() >= MaximumActionsRegistered) { + if (lastActions.size() > MaximumActionsRegistered) { lastActions.pop(); } }