diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index df3b03d12381b8394d508b6a2a614a063f74cbc5..cc0e57dd328cb69853be199063ab2cadc77d63ff 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -76,96 +76,11 @@ #include <fstream> #include <exception> -// Bugsplat (http://bugsplat.com) crash reporting tool -#ifdef LL_BUGSPLAT -#include "BugSplat.h" -#include "llagent.h" // for agent location -#include "llviewerregion.h" -#include "llvoavatarself.h" // for agent name - -namespace -{ - // MiniDmpSender's constructor is defined to accept __wchar_t* instead of - // plain wchar_t*. That said, wunder() returns std::basic_string<__wchar_t>, - // NOT plain __wchar_t*, despite the apparent convenience. Calling - // wunder(something).c_str() as an argument expression is fine: that - // std::basic_string instance will survive until the function returns. - // Calling c_str() on a std::basic_string local to wunder() would be - // Undefined Behavior: we'd be left with a pointer into a destroyed - // std::basic_string instance. But we can do that with a macro... - #define WCSTR(string) wunder(string).c_str() - - // It would be nice if, when wchar_t is the same as __wchar_t, this whole - // function would optimize away. However, we use it only for the arguments - // to the BugSplat API -- a handful of calls. - inline std::basic_string<__wchar_t> wunder(const std::wstring& str) - { - return { str.begin(), str.end() }; - } - - // when what we have in hand is a std::string, convert from UTF-8 using - // specific wstringize() overload - inline std::basic_string<__wchar_t> wunder(const std::string& str) - { - return wunder(wstringize(str)); - } - - // Irritatingly, MiniDmpSender::setCallback() is defined to accept a - // classic-C function pointer instead of an arbitrary C++ callable. If it - // did accept a modern callable, we could pass a lambda that binds our - // MiniDmpSender pointer. As things stand, though, we must define an - // actual function and store the pointer statically. - static MiniDmpSender *sBugSplatSender = nullptr; - - bool bugsplatSendLog(UINT nCode, LPVOID lpVal1, LPVOID lpVal2) - { - if (nCode == MDSCB_EXCEPTIONCODE) - { - // send the main viewer log file - // widen to wstring, convert to __wchar_t, then pass c_str() - sBugSplatSender->sendAdditionalFile( - WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "Alchemy.log"))); - - sBugSplatSender->sendAdditionalFile( - WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "settings.xml"))); - - sBugSplatSender->sendAdditionalFile( - WCSTR(*LLAppViewer::instance()->getStaticDebugFile())); - - // We don't have an email address for any user. Hijack this - // metadata field for the platform identifier. - sBugSplatSender->setDefaultUserEmail( - WCSTR(STRINGIZE(LLOSInfo::instance().getOSStringSimple() << " (" - << ADDRESS_SIZE << "-bit)"))); - - if (gAgentAvatarp) - { - // user name, when we have it - sBugSplatSender->setDefaultUserName(WCSTR(gAgentAvatarp->getFullname())); - - sBugSplatSender->sendAdditionalFile( - WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "settings_per_account.xml"))); - } - - // LL_ERRS message, when there is one - sBugSplatSender->setDefaultUserDescription(WCSTR(LLError::getFatalMessage())); - - if (gAgent.getRegion()) - { - // region location, when we have it - LLVector3 loc = gAgent.getPositionAgent(); - sBugSplatSender->resetAppIdentifier( - WCSTR(STRINGIZE(gAgent.getRegion()->getName() - << '/' << loc.mV[0] - << '/' << loc.mV[1] - << '/' << loc.mV[2]))); - } - } // MDSCB_EXCEPTIONCODE - - return false; - } -} -#endif // LL_BUGSPLAT +// Sentry (https://sentry.io) crash reporting tool +#if defined(USE_SENTRY) +#include <sentry.h> +#include "llviewerbuildconfig.h" +#endif namespace { @@ -464,6 +379,10 @@ int APIENTRY WINMAIN(HINSTANCE hInstance, } #endif +#if defined(USE_SENTRY) + sentry_close(); +#endif + return 0; } @@ -599,96 +518,9 @@ bool LLAppViewerWin32::init() LLWinDebug::instance(); #endif -#if LL_SEND_CRASH_REPORTS -#if ! defined(LL_BUGSPLAT) -#pragma message("Building without BugSplat") - LLAppViewer* pApp = LLAppViewer::instance(); pApp->initCrashReporting(); -#else // LL_BUGSPLAT -#pragma message("Building with BugSplat") - - if (!isSecondInstance()) - { - // Cleanup previous session - std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "bugsplat.log"); - LLFile::remove(log_file, ENOENT); - } - - std::string build_data_fname( - gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "build_data.json")); - // Use llifstream instead of std::ifstream because LL_PATH_EXECUTABLE - // could contain non-ASCII characters, which std::ifstream doesn't handle. - llifstream inf(build_data_fname.c_str()); - if (! inf.is_open()) - { - LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, can't read '" << build_data_fname - << "'" << LL_ENDL; - } - else - { - Json::Reader reader; - Json::Value build_data; - if (! reader.parse(inf, build_data, false)) // don't collect comments - { - // gah, the typo is baked into Json::Reader API - LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, can't parse '" << build_data_fname - << "': " << reader.getFormatedErrorMessages() << LL_ENDL; - } - else - { - Json::Value BugSplat_DB = build_data["BugSplat DB"]; - if (! BugSplat_DB) - { - LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, no 'BugSplat DB' entry in '" - << build_data_fname << "'" << LL_ENDL; - } - else - { - // Got BugSplat_DB, onward! - std::wstring version_string(WSTRINGIZE(LL_VIEWER_VERSION_MAJOR << '.' << - LL_VIEWER_VERSION_MINOR << '.' << - LL_VIEWER_VERSION_PATCH << '.' << - LL_VIEWER_VERSION_BUILD)); - - DWORD dwFlags = MDSF_NONINTERACTIVE | // automatically submit report without prompting - MDSF_PREVENTHIJACKING; // disallow swiping Exception filter - - bool needs_log_file = !isSecondInstance() && debugLoggingEnabled("BUGSPLAT"); - if (needs_log_file) - { - // Startup only! - LL_INFOS("BUGSPLAT") << "Engaged BugSplat logging to bugsplat.log" << LL_ENDL; - dwFlags |= MDSF_LOGFILE | MDSF_LOG_VERBOSE; - } - - // have to convert normal wide strings to strings of __wchar_t - sBugSplatSender = new MiniDmpSender( - WCSTR(BugSplat_DB.asString()), - WCSTR(LL_TO_WSTRING(LL_VIEWER_CHANNEL)), - WCSTR(version_string), - nullptr, // szAppIdentifier -- set later - dwFlags); - sBugSplatSender->setCallback(bugsplatSendLog); - - if (needs_log_file) - { - // Log file will be created in %TEMP%, but it will be moved into logs folder in case of crash - std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "bugsplat.log"); - sBugSplatSender->setLogFilePath(WCSTR(log_file)); - } - - // engage stringize() overload that converts from wstring - LL_INFOS("BUGSPLAT") << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) - << ' ' << stringize(version_string) << ')' << LL_ENDL; - } // got BugSplat_DB - } // parsed build_data.json - } // opened build_data.json - -#endif // LL_BUGSPLAT -#endif // LL_SEND_CRASH_REPORTS - bool success = LLAppViewer::init(); return success; @@ -711,12 +543,14 @@ bool LLAppViewerWin32::cleanup() void LLAppViewerWin32::reportCrashToBugsplat(void* pExcepInfo) { -#if defined(LL_BUGSPLAT) - if (sBugSplatSender) - { - sBugSplatSender->createReport((EXCEPTION_POINTERS*)pExcepInfo); - } -#endif // LL_BUGSPLAT +#if defined(USE_SENTRY) + if (mSentryInitialized) + { + sentry_ucontext_s exc_context = {}; + exc_context.exception_ptrs = *(EXCEPTION_POINTERS*)pExcepInfo; + sentry_handle_exception(&exc_context); + } +#endif } void LLAppViewerWin32::setCrashUserMetadata(const LLUUID& user_id, const std::string& avatar_name) @@ -836,6 +670,27 @@ bool LLAppViewerWin32::restoreErrorTrap() void LLAppViewerWin32::initCrashReporting(bool reportFreeze) { +#if defined(USE_SENTRY) + sentry_options_t* options = sentry_options_new(); + sentry_options_set_dsn(options, SENTRY_DSN); + sentry_options_set_release(options, LL_VIEWER_CHANNEL_AND_VERSION); + + std::string crashpad_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "crashpad_handler.exe"); + sentry_options_set_handler_pathw(options, ll_convert_string_to_wide(crashpad_path).c_str()); + + std::string database_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "sentry"); + sentry_options_set_database_pathw(options, ll_convert_string_to_wide(database_path).c_str()); + + mSentryInitialized = (sentry_init(options) == 0); + if (mSentryInitialized) + { + LL_INFOS() << "Successfully initialized Sentry" << LL_ENDL; + } + else + { + LL_WARNS() << "Failed to initialize Sentry" << LL_ENDL; + } +#endif } //virtual