Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 5 additions & 15 deletions obs-studio-server/source/nodeobs_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down Expand Up @@ -885,7 +885,7 @@ void OBS_API::OBS_API_initAPI(void *data, const int64_t id, const std::vector<ip
before attempting to make a file there. */
if (os_mkdirs(log_path.c_str()) == MKDIR_ERROR) {
std::cerr << "Failed to open log file" << std::endl;
util::CrashManager::AddWarning("Error on log file, failed to create path: " + log_path);
util::CrashManager::AddServerWarning("Error on log file, failed to create path: " + log_path);
}

/* Delete oldest file in the folder to imitate rotating */
Expand All @@ -902,7 +902,7 @@ void OBS_API::OBS_API_initAPI(void *data, const int64_t id, const std::vector<ip
#endif
if (!logParam->logStream.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);
Expand Down Expand Up @@ -964,7 +964,7 @@ void OBS_API::OBS_API_initAPI(void *data, const int64_t id, const std::vector<ip
// when init API supports more return codes.
#ifdef WIN32
std::string userDataPath = std::string(userData.begin(), userData.end());
util::CrashManager::AddWarning("Failed to start OBS, locale: " + locale + " user data: " + userDataPath);
util::CrashManager::AddServerWarning("Failed to start OBS, locale: " + locale + " user data: " + userDataPath);
#endif
}

Expand Down Expand Up @@ -2048,17 +2048,7 @@ double OBS_API::getMemoryUsage()
return (double)os_get_proc_resident_size() / (1024.0 * 1024.0);
}

const std::vector<std::string> &OBS_API::getOBSLogErrors()
{
return logReport.errors;
}

const std::vector<std::string> &OBS_API::getOBSLogWarnings()
{
return logReport.warnings;
}

std::queue<std::string> &OBS_API::getOBSLogGeneral()
std::deque<std::string> &OBS_API::getOBSLogGeneral()
{
return logReport.general;
}
Expand Down
28 changes: 8 additions & 20 deletions obs-studio-server/source/nodeobs_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#include <string.h>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include "nodeobs_configManager.hpp"
#include "nodeobs_service.h"
#include "util-osx.hpp"
Expand All @@ -44,27 +44,17 @@ class OBS_API {

public:
struct LogReport {
static const int MaximumGeneralMessages = 150;
static const int MaximumMessages = 150;

void push(std::string message, int logLevel)
void push(std::string message)
{
general.push(message);
if (general.size() >= MaximumGeneralMessages) {
general.pop();
}

if (logLevel == LOG_ERROR) {
errors.push_back(message);
}

if (logLevel == LOG_WARNING) {
warnings.push_back(message);
general.push_back(message);
if (general.size() > MaximumMessages) {
general.pop_front();
}
}

std::vector<std::string> errors;
std::vector<std::string> warnings;
std::queue<std::string> general;
std::deque<std::string> general;
};

struct OutputStats {
Expand Down Expand Up @@ -130,9 +120,7 @@ class OBS_API {
static double getMemoryUsage();
static void getCurrentOutputStats(obs_output_t *output, OBS_API::OutputStats &outputStats);

static const std::vector<std::string> &getOBSLogErrors();
static const std::vector<std::string> &getOBSLogWarnings();
static std::queue<std::string> &getOBSLogGeneral();
static std::deque<std::string> &getOBSLogGeneral();

static std::string getCurrentVersion();
static std::string getUsername();
Expand Down
4 changes: 2 additions & 2 deletions obs-studio-server/source/nodeobs_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1203,7 +1203,7 @@ void OBS_service::setupRecordingAudioEncoder(void)
nameStream.str().c_str(), i)) {
std::ostringstream errorStream;
errorStream << "audio encoder failed id: " << id << nameStream.str();
util::CrashManager::AddWarning(errorStream.str());
util::CrashManager::AddServerWarning(errorStream.str());
throw std::runtime_error("Failed to create audio encoder (advanced output)");
}
obs_encoder_set_audio(AdvancedRecordingAudioTracks[i], obs_get_audio());
Expand Down Expand Up @@ -3577,7 +3577,7 @@ void WaitForAllOutputsToStop()
const std::string crashMessage = "Timed out waiting for outputs to stop during shutdown: " + busyOutputs;

blog(LOG_ERROR, "%s", crashMessage.c_str());
util::CrashManager::AddWarning(crashMessage);
util::CrashManager::AddServerWarning(crashMessage);
#ifdef WIN32
util::CrashManager::GetMetricsProvider()->BlameServer();
#endif
Expand Down
93 changes: 25 additions & 68 deletions obs-studio-server/source/util-crashmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <fstream>
#include <iostream>
#include <locale>
#include <deque>
#include <map>
#include <obs.h>
#include <queue>
Expand Down Expand Up @@ -73,9 +74,9 @@
//////////////////////
// STATIC VARIABLES //
//////////////////////
std::vector<nlohmann::json> breadcrumbs;
std::queue<std::pair<int, std::string>> lastActions;
std::vector<std::string> warnings;
std::deque<std::string> serverWarnings;
constexpr size_t MaximumServerWarnings = 50;
std::mutex messageMutex;
#ifdef WIN32
// Global/static variables
Expand Down Expand Up @@ -717,13 +718,16 @@ 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(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)}});
annotations.insert({{"Last actions", ComputeActions().dump(4)}});
annotations.insert({{"Warnings", ComputeWarnings().dump(4)}});
annotations.insert({{"Server warnings", ComputeServerWarnings().dump(4)}});
} catch (...) {
}

Expand Down Expand Up @@ -1021,51 +1025,21 @@ 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();
for (auto &msg : errors)
result.push_back(msg);
break;
}

case OBSLogType::Warnings: {
auto &warnings = OBS_API::getOBSLogWarnings();
for (auto &msg : warnings)
result.push_back(msg);
break;
}

case OBSLogType::General: {
auto &general = OBS_API::getOBSLogGeneral();
while (!general.empty()) {
result.push_back(general.front());
general.pop();
}

break;
}
auto &general = OBS_API::getOBSLogGeneral();
while (!general.empty()) {
result.push_back(general.front());
general.pop_front();
}
Comment on lines +1032 to 1036

std::reverse(result.begin(), result.end());

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();
Expand All @@ -1086,11 +1060,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<std::mutex> lock(messageMutex);
for (auto &msg : serverWarnings)
result.push_back(msg);
Comment on lines +1067 to 1069

return result;
Expand Down Expand Up @@ -1249,10 +1224,13 @@ void util::CrashManager::IPCValuesToData(const std::vector<ipc::value> &values,
}
}

void util::CrashManager::AddWarning(const std::string &warning)
void util::CrashManager::AddServerWarning(const std::string &warning)
{
std::lock_guard<std::mutex> lock(messageMutex);
warnings.push_back(warning);
serverWarnings.push_back(warning);
if (serverWarnings.size() > MaximumServerWarnings) {
serverWarnings.pop_front();
}
}

void RegisterAction(const std::string &message)
Expand All @@ -1271,27 +1249,6 @@ void RegisterAction(const std::string &message)
}
}

void util::CrashManager::AddBreadcrumb(const nlohmann::json &message)
{
std::lock_guard<std::mutex> 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<std::mutex> lock(messageMutex);
breadcrumbs.push_back(j);
}

void util::CrashManager::ClearBreadcrumbs()
{
std::lock_guard<std::mutex> lock(messageMutex);
breadcrumbs.clear();
}

void util::CrashManager::setAppState(const std::string &newState)
{
appState = newState;
Expand Down Expand Up @@ -1349,10 +1306,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<ipc::value> &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);
}
}

Expand Down
13 changes: 3 additions & 10 deletions obs-studio-server/source/util-crashmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,13 @@ 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();
void OpenConsole();

static void IPCValuesToData(const std::vector<ipc::value> &, nlohmann::json &);
static void AddWarning(const std::string &warning);
static void AddBreadcrumb(const nlohmann::json &message);
static void AddBreadcrumb(const std::string &message);
static void ClearBreadcrumbs();
static void AddServerWarning(const std::string &warning);
static void DisableReports();
static void setAppState(const std::string &newState);
static std::string getAppState();
Expand Down Expand Up @@ -84,10 +78,9 @@ class CrashManager {
#endif

private:
static nlohmann::json RequestOBSLog(OBSLogType type);
static nlohmann::json ComputeBreadcrumbs();
static nlohmann::json RequestOBSLog();
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;
Expand Down
Loading