Files
dusklight/src/dusk/crash_reporting.cpp
T
Pieter-Jan Briers 977ad16806 GCN PAL support (#533)
* Basic PAL ISO & language support

Probably still needs much more work

* Add language selector to pre-launch

* Store DVDDiskID in a global

Can use this later for things

* More version system API improvements

* d_name mostly region switching fully

JPN doesn't work yet cuz it'll be a nightmare, probably.

* More version switching support

* Mark GCN PAL as supported ROM

* Fix remaining REL assets to have PAL offsets

* d_a_mg_fish PAL

* d_a_mg_fshop PAL

* isRegionUsa helper

* d_menu_fishing PAL

* d_msg_class PAL

* m_Do_MemCardRWmng PAL

* Update CARDInit call & remove DUSK_TP_VERSION

* Fix Ganon cape

Missed this one.

* Remove tp_version from Sentry

---------

Co-authored-by: Luke Street <luke@street.dev>
2026-04-25 15:46:12 -06:00

188 lines
4.7 KiB
C++

#include "dusk/crash_reporting.h"
#include "dusk/app_info.hpp"
#include "dusk/dusk.h"
#include "dusk/logging.h"
#include "dusk/main.h"
#include "dusk/settings.h"
#include "version.h"
#include <cstdlib>
#include <filesystem>
#include <string>
#include <string_view>
#include <system_error>
#include "SDL3/SDL_filesystem.h"
#if DUSK_ENABLE_SENTRY_NATIVE
#include <sentry.h>
#endif
namespace dusk {
namespace {
#if DUSK_ENABLE_SENTRY_NATIVE
bool g_sentryInitialized = false;
bool IsTruthy(std::string_view value) {
return value == "1" || value == "true" || value == "TRUE" || value == "yes"
|| value == "YES" || value == "on" || value == "ON";
}
std::string GetEnvOrEmpty(const char* name) {
if (const char* value = std::getenv(name)) {
return value;
}
return {};
}
bool GetEffectiveEnabled() {
const std::string env = GetEnvOrEmpty("DUSK_SENTRY_ENABLED");
if (!env.empty()) {
return IsTruthy(env);
}
return getSettings().backend.enableCrashReporting;
}
std::string GetEffectiveDsn() {
const std::string env = GetEnvOrEmpty("DUSK_SENTRY_DSN");
if (!env.empty()) {
return env;
}
return DUSK_SENTRY_DSN;
}
bool GetEffectiveDebug() {
const std::string env = GetEnvOrEmpty("DUSK_SENTRY_DEBUG");
if (!env.empty()) {
return IsTruthy(env);
}
return false;
}
std::string GetReleaseName() {
return std::string(AppName) + "@" DUSK_WC_DESCRIBE;
}
std::filesystem::path GetSentryDatabasePath() {
return dusk::ConfigPath / "sentry";
}
std::filesystem::path GetLogAttachmentPath() {
if (const char* logPath = GetLogFilePath()) {
return logPath;
}
return {};
}
std::filesystem::path GetCrashpadHandlerPath() {
const char* basePath = SDL_GetBasePath();
if (!basePath) {
return {};
}
const std::filesystem::path handlerDir(basePath);
#if _WIN32
return handlerDir / "crashpad_handler.exe";
#else
return handlerDir / "crashpad_handler";
#endif
}
void ConfigurePathOptions(sentry_options_t* options) {
const auto databasePath = GetSentryDatabasePath();
std::error_code ec;
std::filesystem::create_directories(databasePath, ec);
if (ec) {
DuskLog.warn("Unable to create Sentry database path '{}': {}",
databasePath.string(), ec.message());
}
#if _WIN32
const std::wstring databasePathWide = databasePath.wstring();
sentry_options_set_database_pathw(options, databasePathWide.c_str());
const auto handlerPath = GetCrashpadHandlerPath();
if (!handlerPath.empty()) {
const std::wstring handlerPathWide = handlerPath.wstring();
sentry_options_set_handler_pathw(options, handlerPathWide.c_str());
}
#else
const std::string databasePathUtf8 = databasePath.string();
sentry_options_set_database_path(options, databasePathUtf8.c_str());
const auto handlerPath = GetCrashpadHandlerPath();
if (!handlerPath.empty()) {
const std::string handlerPathUtf8 = handlerPath.string();
sentry_options_set_handler_path(options, handlerPathUtf8.c_str());
}
#endif
const auto logPath = GetLogAttachmentPath();
if (!logPath.empty()) {
#if _WIN32
sentry_options_add_attachmentw(options, logPath.wstring().c_str());
#else
sentry_options_add_attachment(options, logPath.string().c_str());
#endif
}
}
#endif
} // namespace
void InitializeCrashReporting() {
#if DUSK_ENABLE_SENTRY_NATIVE
if (g_sentryInitialized) {
return;
}
if (!GetEffectiveEnabled()) {
return;
}
const std::string dsn = GetEffectiveDsn();
if (dsn.empty()) {
DuskLog.warn("Crash reporting is enabled but no Sentry DSN is configured");
return;
}
const std::string release = GetReleaseName();
sentry_options_t* options = sentry_options_new();
sentry_options_set_dsn(options, dsn.c_str());
sentry_options_set_release(options, release.c_str());
sentry_options_set_environment(options, DUSK_SENTRY_ENVIRONMENT);
sentry_options_set_debug(options, GetEffectiveDebug() ? 1 : 0);
sentry_options_set_cache_keep(options, 1);
sentry_options_set_max_breadcrumbs(options, 100);
ConfigurePathOptions(options);
if (sentry_init(options) != 0) {
DuskLog.warn("Failed to initialize Sentry crash reporting");
return;
}
sentry_set_tag("git_branch", DUSK_WC_BRANCH);
sentry_set_tag("build_type", DUSK_BUILD_TYPE);
g_sentryInitialized = true;
DuskLog.info("Initialized Sentry crash reporting");
#endif
}
void ShutdownCrashReporting() {
#if DUSK_ENABLE_SENTRY_NATIVE
if (!g_sentryInitialized) {
return;
}
sentry_close();
g_sentryInitialized = false;
#endif
}
} // namespace dusk