From 66c34a1348d20e586a4bd1b189b37342b9ae21dd Mon Sep 17 00:00:00 2001 From: Vladimir Sumarov Date: Mon, 9 Feb 2026 17:11:31 -0800 Subject: [PATCH 1/5] 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 71ca5b37b47f60ebaf497593034b614ebb50a272 Mon Sep 17 00:00:00 2001 From: Vladimir Sumarov Date: Fri, 22 May 2026 10:36:37 -0700 Subject: [PATCH 2/5] 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 1f6c4e80cf2360cd291aea50027ec179a7a3bc91 Mon Sep 17 00:00:00 2001 From: Vladimir Sumarov Date: Fri, 22 May 2026 10:38:12 -0700 Subject: [PATCH 3/5] 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 99692ed14be081759e82360ac13d5c294af8767a Mon Sep 17 00:00:00 2001 From: Vladimir Sumarov Date: Fri, 22 May 2026 10:39:06 -0700 Subject: [PATCH 4/5] 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 fd021b8eea4de4ea66e8453281c885162ee3f0d4 Mon Sep 17 00:00:00 2001 From: Vladimir Sumarov Date: Fri, 22 May 2026 10:39:34 -0700 Subject: [PATCH 5/5] 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}});