From c5f618d096f05bdff91a5d384c46e26840f5a771 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 17 May 2018 06:53:42 -0400 Subject: SL-821: Move Windows BugSplat engagement from llcommon to newview. Use WSTRINGIZE(), LL_TO_WSTRING(), wstringize() to produce required wide strings. Use a lambda for callback that sends log file; use LLDir, if set, to find the log file. Introduce BUGSPLAT CMake variable to allow suppressing BugSplat. Make BUGSPLAT CMake variable set LL_BUGSPLAT for C++ compilations. Set viewer version macros on llappviewerwin32.cpp, llappviewerlinux.cpp and llappdelegate-objc.mm -- because BugSplat needs the viewer version data, and because the macOS BugSplat hook is engaged in an Objective-C++ function we override in the app delegate. --- indra/newview/llappviewerwin32.cpp | 49 ++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 48b3a1c485..8a014c55d7 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -66,8 +66,18 @@ #endif #include "stringize.h" +#include "lldir.h" #include + +// Bugsplat (http://bugsplat.com) crash reporting tool +#ifdef LL_BUGSPLAT +#include "BugSplat.h" + +// FIXME: need a production BugSplat database name +static const wchar_t *bugdb_name = L"second_life_callum_test"; +#endif + namespace { void (*gOldTerminateHandler)() = NULL; @@ -495,15 +505,46 @@ bool LLAppViewerWin32::init() LLWinDebug::instance(); #endif -#if LL_WINDOWS #if LL_SEND_CRASH_REPORTS - +#if ! defined(LL_BUGSPLAT) LLAppViewer* pApp = LLAppViewer::instance(); pApp->initCrashReporting(); -#endif -#endif +#else // LL_BUGSPLAT + + std::wstring version_string(WSTRINGIZE(LL_VIEWER_VERSION_MAJOR << '.' << + LL_VIEWER_VERSION_MINOR << '.' << + LL_VIEWER_VERSION_PATCH << '.' << + LL_VIEWER_VERSION_BUILD)); + + auto sender = new MiniDmpSender( + bugdb_name, LL_TO_WSTRING(LL_VIEWER_CHANNEL), version_string.c_str(), nullptr); + sender->setCallback( + [sender](unsigned int nCode, void* lpVal1, void* lpVal2) + { + // If we haven't yet initialized LLDir, don't bother trying to + // find our log file. + // Alternatively -- if we might encounter trouble trying to query + // LLDir during crash cleanup -- consider making gDirUtilp an + // LLPounceable, and attach a callback that stores the pathname to + // the log file here. + if (nCode == MDSCB_EXCEPTIONCODE && gDirUtilp) + { + // send the main viewer log file + // widen to wstring, then pass c_str() + sender->sendAdditionalFile( + wstringize(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log")).c_str()); + } + + return false; + }); + + LL_INFOS() << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) + << version_string << ')' << LL_ENDL; + +#endif // LL_BUGSPLAT +#endif // LL_SEND_CRASH_REPORTS bool success = LLAppViewer::init(); -- cgit v1.2.3 From cd21556aef547dbb031e363d3a9b9f1893be4d08 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 17 May 2018 10:58:59 -0400 Subject: SL-821: Convert wstrings to strings of __wchar_t for BugSplat API. --- indra/newview/llappviewerwin32.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 8a014c55d7..91c6f08000 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -76,7 +76,14 @@ // FIXME: need a production BugSplat database name static const wchar_t *bugdb_name = L"second_life_callum_test"; -#endif + +// MiniDmpSender's constructor is defined to accept __wchar_t* instead of +// plain wchar_t*. +inline std::basic_string<__wchar_t> wunder(const std::wstring& str) +{ + return { str.begin(), str.end() }; +} +#endif // LL_BUGSPLAT namespace { @@ -518,8 +525,12 @@ bool LLAppViewerWin32::init() LL_VIEWER_VERSION_PATCH << '.' << LL_VIEWER_VERSION_BUILD)); + // have to convert normal wide strings to strings of __wchar_t auto sender = new MiniDmpSender( - bugdb_name, LL_TO_WSTRING(LL_VIEWER_CHANNEL), version_string.c_str(), nullptr); + wunder(bugdb_name).c_str(), + wunder(LL_TO_WSTRING(LL_VIEWER_CHANNEL)).c_str(), + wunder(version_string).c_str(), + nullptr); sender->setCallback( [sender](unsigned int nCode, void* lpVal1, void* lpVal2) { @@ -532,16 +543,17 @@ bool LLAppViewerWin32::init() if (nCode == MDSCB_EXCEPTIONCODE && gDirUtilp) { // send the main viewer log file - // widen to wstring, then pass c_str() + // widen to wstring, convert to __wchar_t, then pass c_str() sender->sendAdditionalFile( - wstringize(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log")).c_str()); + wunder(wstringize(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log"))).c_str()); } return false; }); + // engage stringize() overload that converts from wstring LL_INFOS() << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) - << version_string << ')' << LL_ENDL; + << stringize(version_string) << ')' << LL_ENDL; #endif // LL_BUGSPLAT #endif // LL_SEND_CRASH_REPORTS -- cgit v1.2.3 From 800b47ec230d1d2a6781dce5ba9816d10a37e91e Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 17 May 2018 15:02:26 -0400 Subject: SL-821: Use classic-C BugSplat callback and static dumb pointer. BugSplat has no business introducing a new C++ API based on classic-C function pointers without even a generic pass-through user data pointer! --- indra/newview/llappviewerwin32.cpp | 65 ++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 27 deletions(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 91c6f08000..5f3bf14bc2 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -74,14 +74,43 @@ #ifdef LL_BUGSPLAT #include "BugSplat.h" -// FIXME: need a production BugSplat database name -static const wchar_t *bugdb_name = L"second_life_callum_test"; - -// MiniDmpSender's constructor is defined to accept __wchar_t* instead of -// plain wchar_t*. -inline std::basic_string<__wchar_t> wunder(const std::wstring& str) +namespace { - return { str.begin(), str.end() }; + // FIXME: need a production BugSplat database name + static const wchar_t *bugdb_name = L"second_life_callum_test"; + + // MiniDmpSender's constructor is defined to accept __wchar_t* instead of + // plain wchar_t*. + inline std::basic_string<__wchar_t> wunder(const std::wstring& str) + { + return { str.begin(), str.end() }; + } + + // Irritatingly, MiniDmpSender::setCallback() is defined to accept a + // classic-C function pointer instead of an arbitrary C++ callable. In the + // latter case, we could pass a lambda that binds our MiniDmpSender + // pointer. As things stand, we must define an actual function and store + // the pointer statically. + static MiniDmpSender *sBugSplatSender = nullptr; + + bool bugsplatSendLog(UINT nCode, LPVOID lpVal1, LPVOID lpVal2) + { + // If we haven't yet initialized LLDir, don't bother trying to + // find our log file. + // Alternatively -- if we might encounter trouble trying to query + // LLDir during crash cleanup -- consider making gDirUtilp an + // LLPounceable, and attach a callback that stores the pathname to + // the log file here. + if (nCode == MDSCB_EXCEPTIONCODE && gDirUtilp) + { + // send the main viewer log file + // widen to wstring, convert to __wchar_t, then pass c_str() + sBugSplatSender->sendAdditionalFile( + wunder(wstringize(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log"))).c_str()); + } + + return false; + } } #endif // LL_BUGSPLAT @@ -526,30 +555,12 @@ bool LLAppViewerWin32::init() LL_VIEWER_VERSION_BUILD)); // have to convert normal wide strings to strings of __wchar_t - auto sender = new MiniDmpSender( + sBugSplatSender = new MiniDmpSender( wunder(bugdb_name).c_str(), wunder(LL_TO_WSTRING(LL_VIEWER_CHANNEL)).c_str(), wunder(version_string).c_str(), nullptr); - sender->setCallback( - [sender](unsigned int nCode, void* lpVal1, void* lpVal2) - { - // If we haven't yet initialized LLDir, don't bother trying to - // find our log file. - // Alternatively -- if we might encounter trouble trying to query - // LLDir during crash cleanup -- consider making gDirUtilp an - // LLPounceable, and attach a callback that stores the pathname to - // the log file here. - if (nCode == MDSCB_EXCEPTIONCODE && gDirUtilp) - { - // send the main viewer log file - // widen to wstring, convert to __wchar_t, then pass c_str() - sender->sendAdditionalFile( - wunder(wstringize(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log"))).c_str()); - } - - return false; - }); + sBugSplatSender->setCallback(bugsplatSendLog); // engage stringize() overload that converts from wstring LL_INFOS() << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) -- cgit v1.2.3 From 63fe7d802aad177107ef8e3bc0c9b7ea5118ad61 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 25 May 2018 12:09:50 -0400 Subject: SL-821, SL-826: Use BUGSPLAT_DB from environment on Windows and Mac. On TeamCity, set BUGSPLAT_DB from build-secrets. Use the presence of $BUGSPLAT_DB, rather than a new CMake BUGSPLAT option, to control whether CMake searches for BugSplat -- and passes LL_BUGSPLAT into C++. When BUGSPLAT_DB is present, make viewer_manifest.py set "BugSplat DB" in build_data.json, and "BugsplatServerURL" in Mac Info.plist. Make llappviewerwin32.cpp read "BugSplat DB" from build_data.json. Add placeholders for Mac hooks to suppress BugSplat prompt and send SecondLife.log. --- indra/newview/llappviewerwin32.cpp | 87 +++++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 24 deletions(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 5f3bf14bc2..f9df2b88ed 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -68,29 +68,30 @@ #include "stringize.h" #include "lldir.h" +#include #include // Bugsplat (http://bugsplat.com) crash reporting tool #ifdef LL_BUGSPLAT #include "BugSplat.h" +#include "reader.h" // JsonCpp namespace { - // FIXME: need a production BugSplat database name - static const wchar_t *bugdb_name = L"second_life_callum_test"; - // MiniDmpSender's constructor is defined to accept __wchar_t* instead of - // plain wchar_t*. + // plain wchar_t*. 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 make exactly one call to initialize BugSplat. inline std::basic_string<__wchar_t> wunder(const std::wstring& str) { return { str.begin(), str.end() }; } // Irritatingly, MiniDmpSender::setCallback() is defined to accept a - // classic-C function pointer instead of an arbitrary C++ callable. In the - // latter case, we could pass a lambda that binds our MiniDmpSender - // pointer. As things stand, we must define an actual function and store - // the pointer statically. + // 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) @@ -549,22 +550,60 @@ bool LLAppViewerWin32::init() #else // LL_BUGSPLAT - std::wstring version_string(WSTRINGIZE(LL_VIEWER_VERSION_MAJOR << '.' << - LL_VIEWER_VERSION_MINOR << '.' << - LL_VIEWER_VERSION_PATCH << '.' << - LL_VIEWER_VERSION_BUILD)); - - // have to convert normal wide strings to strings of __wchar_t - sBugSplatSender = new MiniDmpSender( - wunder(bugdb_name).c_str(), - wunder(LL_TO_WSTRING(LL_VIEWER_CHANNEL)).c_str(), - wunder(version_string).c_str(), - nullptr); - sBugSplatSender->setCallback(bugsplatSendLog); - - // engage stringize() overload that converts from wstring - LL_INFOS() << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) - << stringize(version_string) << ')' << LL_ENDL; + if (gDirUtilp) + { + LL_WARNS() << "Can't initialize BugSplat, gDirUtilp not yet set" << LL_ENDL; + } + else + { + std::string build_data_fname( + gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "build_data.json")); + std::ifstream inf(build_data_fname.c_str()); + if (! inf.open()) + { + LL_WARNS() << "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 + { + LL_WARNS() << "Can't initialize BugSplat, can't parse '" << build_data_fname + << "': " << reader.getFormattedErrorMessages() << LL_ENDL; + } + else + { + Json::Value BugSplat_DB = build_data["BugSplat DB"]; + if (! BugSplat_DB) + { + LL_WARNS() << "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)); + + // have to convert normal wide strings to strings of __wchar_t + sBugSplatSender = new MiniDmpSender( + wunder(BugSplat_DB).c_str(), + wunder(LL_TO_WSTRING(LL_VIEWER_CHANNEL)).c_str(), + wunder(version_string).c_str(), + nullptr); + sBugSplatSender->setCallback(bugsplatSendLog); + + // engage stringize() overload that converts from wstring + LL_INFOS() << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) + << stringize(version_string) << ')' << LL_ENDL; + } // got BugSplat_DB + } // parsed build_data.json + } // opened build_data.json + } // gDirUtilp set #endif // LL_BUGSPLAT #endif // LL_SEND_CRASH_REPORTS -- cgit v1.2.3 From 3ca76065b0beeaf276078b4bc28b8e0c6295a4fc Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 25 May 2018 19:02:53 -0400 Subject: SL-823: Fix minor compile errors in code to read build_data.json. --- indra/newview/llappviewerwin32.cpp | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index f9df2b88ed..b7ad28448b 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -79,14 +79,29 @@ namespace { // MiniDmpSender's constructor is defined to accept __wchar_t* instead of - // plain wchar_t*. 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 make exactly one call to initialize BugSplat. + // 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. + + // 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 make exactly one call to initialize BugSplat. 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 @@ -107,7 +122,7 @@ namespace // send the main viewer log file // widen to wstring, convert to __wchar_t, then pass c_str() sBugSplatSender->sendAdditionalFile( - wunder(wstringize(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log"))).c_str()); + wunder(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log")).c_str()); } return false; @@ -559,7 +574,7 @@ bool LLAppViewerWin32::init() std::string build_data_fname( gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "build_data.json")); std::ifstream inf(build_data_fname.c_str()); - if (! inf.open()) + if (! inf.is_open()) { LL_WARNS() << "Can't initialize BugSplat, can't read '" << build_data_fname << "'" << LL_ENDL; @@ -570,8 +585,9 @@ bool LLAppViewerWin32::init() Json::Value build_data; if (! reader.parse(inf, build_data, false)) // don't collect comments { + // gah, the typo is baked into their API LL_WARNS() << "Can't initialize BugSplat, can't parse '" << build_data_fname - << "': " << reader.getFormattedErrorMessages() << LL_ENDL; + << "': " << reader.getFormatedErrorMessages() << LL_ENDL; } else { @@ -579,7 +595,7 @@ bool LLAppViewerWin32::init() if (! BugSplat_DB) { LL_WARNS() << "Can't initialize BugSplat, no 'BugSplat DB' entry in '" - << build_data_fname "'" << LL_ENDL; + << build_data_fname << "'" << LL_ENDL; } else { @@ -591,7 +607,7 @@ bool LLAppViewerWin32::init() // have to convert normal wide strings to strings of __wchar_t sBugSplatSender = new MiniDmpSender( - wunder(BugSplat_DB).c_str(), + wunder(BugSplat_DB.asString()).c_str(), wunder(LL_TO_WSTRING(LL_VIEWER_CHANNEL)).c_str(), wunder(version_string).c_str(), nullptr); -- cgit v1.2.3 From a5c17472fb3bbd2bc6fe188c450d2123963b5d6e Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Sat, 26 May 2018 08:44:57 -0400 Subject: SL-823: Fix typo in code that sets up BugSplat. --- indra/newview/llappviewerwin32.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index f9df2b88ed..c2cbce493c 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -550,7 +550,7 @@ bool LLAppViewerWin32::init() #else // LL_BUGSPLAT - if (gDirUtilp) + if (! gDirUtilp) { LL_WARNS() << "Can't initialize BugSplat, gDirUtilp not yet set" << LL_ENDL; } -- cgit v1.2.3 From bb757b937c6cde205c59a80e83d8f970523edeeb Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 15 Jun 2018 11:28:01 -0400 Subject: SL-820: gDirUtilp is never nullptr. It might point to an uninitialized LLDir, but that's a whole separate problem, one that wouldn't be detected by checking for nullptr. If we hit that, time to change to an LLSingleton. --- indra/newview/llappviewerwin32.cpp | 79 +++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 43 deletions(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 4701e7bbed..3efc94d7b5 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -565,61 +565,54 @@ bool LLAppViewerWin32::init() #else // LL_BUGSPLAT - if (! gDirUtilp) + std::string build_data_fname( + gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "build_data.json")); + std::ifstream inf(build_data_fname.c_str()); + if (! inf.is_open()) { - LL_WARNS() << "Can't initialize BugSplat, gDirUtilp not yet set" << LL_ENDL; + LL_WARNS() << "Can't initialize BugSplat, can't read '" << build_data_fname + << "'" << LL_ENDL; } else { - std::string build_data_fname( - gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "build_data.json")); - std::ifstream inf(build_data_fname.c_str()); - if (! inf.is_open()) + Json::Reader reader; + Json::Value build_data; + if (! reader.parse(inf, build_data, false)) // don't collect comments { - LL_WARNS() << "Can't initialize BugSplat, can't read '" << build_data_fname - << "'" << LL_ENDL; + // gah, the typo is baked into their API + LL_WARNS() << "Can't initialize BugSplat, can't parse '" << build_data_fname + << "': " << reader.getFormatedErrorMessages() << LL_ENDL; } else { - Json::Reader reader; - Json::Value build_data; - if (! reader.parse(inf, build_data, false)) // don't collect comments + Json::Value BugSplat_DB = build_data["BugSplat DB"]; + if (! BugSplat_DB) { - // gah, the typo is baked into their API - LL_WARNS() << "Can't initialize BugSplat, can't parse '" << build_data_fname - << "': " << reader.getFormatedErrorMessages() << LL_ENDL; + LL_WARNS() << "Can't initialize BugSplat, no 'BugSplat DB' entry in '" + << build_data_fname << "'" << LL_ENDL; } else { - Json::Value BugSplat_DB = build_data["BugSplat DB"]; - if (! BugSplat_DB) - { - LL_WARNS() << "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)); - - // have to convert normal wide strings to strings of __wchar_t - sBugSplatSender = new MiniDmpSender( - wunder(BugSplat_DB.asString()).c_str(), - wunder(LL_TO_WSTRING(LL_VIEWER_CHANNEL)).c_str(), - wunder(version_string).c_str(), - nullptr); - sBugSplatSender->setCallback(bugsplatSendLog); - - // engage stringize() overload that converts from wstring - LL_INFOS() << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) - << stringize(version_string) << ')' << LL_ENDL; - } // got BugSplat_DB - } // parsed build_data.json - } // opened build_data.json - } // gDirUtilp set + // 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)); + + // have to convert normal wide strings to strings of __wchar_t + sBugSplatSender = new MiniDmpSender( + wunder(BugSplat_DB.asString()).c_str(), + wunder(LL_TO_WSTRING(LL_VIEWER_CHANNEL)).c_str(), + wunder(version_string).c_str(), + nullptr); + sBugSplatSender->setCallback(bugsplatSendLog); + + // engage stringize() overload that converts from wstring + LL_INFOS() << "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 -- cgit v1.2.3 From f6e7893a6e34190e8080d289a5f89d7f9c47d583 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 28 Jun 2018 12:39:42 -0400 Subject: MAINT-8797: Resurrect BugSplat crash reporting on Windows. The Breakpad symbol-file upload in the viewer's build.sh was failing on BugSplat builds since we weren't generating Breakpad symbol files. That upload was conditional on RELEASE_CRASH_REPORTING, so my first approach was to set RELEASE_CRASH_REPORTING=OFF for BugSplat builds. Unfortunately that symbol also propagates down into C++ compiles, and in llappviewerwin32.cpp, both Breakpad and BugSplat crash reporting is conditional on it. So that change inadvertently turned off the C++ logic to engage BugSplat. Stop forcing RELEASE_CRASH_REPORTING=OFF for BugSplat builds. Instead, make the Breakpad symbol-file upload check the BUGSPLAT_DB variable as well. Add #pragma messages to llappviewerwin32.cpp so we can detect whether it's being built for Breakpad or BugSplat or neither. --- indra/newview/llappviewerwin32.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 3efc94d7b5..247b94db3e 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -559,11 +559,13 @@ bool LLAppViewerWin32::init() #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") std::string build_data_fname( gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "build_data.json")); @@ -579,7 +581,7 @@ bool LLAppViewerWin32::init() Json::Value build_data; if (! reader.parse(inf, build_data, false)) // don't collect comments { - // gah, the typo is baked into their API + // gah, the typo is baked into Json::Reader API LL_WARNS() << "Can't initialize BugSplat, can't parse '" << build_data_fname << "': " << reader.getFormatedErrorMessages() << LL_ENDL; } @@ -609,7 +611,7 @@ bool LLAppViewerWin32::init() // engage stringize() overload that converts from wstring LL_INFOS() << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) - << stringize(version_string) << ')' << LL_ENDL; + << ' ' << stringize(version_string) << ')' << LL_ENDL; } // got BugSplat_DB } // parsed build_data.json } // opened build_data.json -- cgit v1.2.3 From cd52724ef8f8a19ebe28c73f39a582b56fb58093 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 28 Jun 2018 21:49:07 -0400 Subject: DRTVWR-447: Suppress BugSplat UI; auto-fill certain BugSplat data. Direct BugSplat to send crash reports without prompting, on both Windows and Mac. Add a mechanism by which code called after LL_ERRS() can retrieve the fatal log message string. (How did the crash logger extract that for Linden crash logging?) Add that fatal message to crash reports on Windows. But as BugsplatMac is engaged only on the run _after_ the crash, we no longer have that message in memory. Also add user name and region location to Windows crash reports. On Mac, (a) we don't have the information from the previous run and (b) BugsplatMac doesn't provide an API to attach that information to the crash report. Add Mac logging to indicate the success or failure of sending the crash report. Add Windows logging to indicate we're about to send. --- indra/newview/llappviewerwin32.cpp | 53 +++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 15 deletions(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 247b94db3e..1e135fa229 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -67,6 +67,7 @@ #include "stringize.h" #include "lldir.h" +#include "llerrorcontrol.h" #include #include @@ -74,7 +75,10 @@ // Bugsplat (http://bugsplat.com) crash reporting tool #ifdef LL_BUGSPLAT #include "BugSplat.h" -#include "reader.h" // JsonCpp +#include "reader.h" // JsonCpp +#include "llagent.h" // for agent location +#include "llviewerregion.h" +#include "llvoavatarself.h" // for agent name namespace { @@ -85,7 +89,8 @@ namespace // 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. + // 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 @@ -111,19 +116,35 @@ namespace bool bugsplatSendLog(UINT nCode, LPVOID lpVal1, LPVOID lpVal2) { - // If we haven't yet initialized LLDir, don't bother trying to - // find our log file. - // Alternatively -- if we might encounter trouble trying to query - // LLDir during crash cleanup -- consider making gDirUtilp an - // LLPounceable, and attach a callback that stores the pathname to - // the log file here. - if (nCode == MDSCB_EXCEPTIONCODE && gDirUtilp) + if (nCode == MDSCB_EXCEPTIONCODE) { // send the main viewer log file // widen to wstring, convert to __wchar_t, then pass c_str() sBugSplatSender->sendAdditionalFile( - wunder(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log")).c_str()); - } + WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log"))); + + if (gAgentAvatarp) + { + // user name, when we have it + sBugSplatSender->setDefaultUserName(WCSTR(gAgentAvatarp->getFullname())); + } + + // 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]))); + } + + LL_INFOS() << "Sending crash report to BugSplat." << LL_ENDL; + } // MDSCB_EXCEPTIONCODE return false; } @@ -603,10 +624,12 @@ bool LLAppViewerWin32::init() // have to convert normal wide strings to strings of __wchar_t sBugSplatSender = new MiniDmpSender( - wunder(BugSplat_DB.asString()).c_str(), - wunder(LL_TO_WSTRING(LL_VIEWER_CHANNEL)).c_str(), - wunder(version_string).c_str(), - nullptr); + WCSTR(BugSplat_DB.asString()), + WCSTR(LL_TO_WSTRING(LL_VIEWER_CHANNEL)), + WCSTR(version_string), + nullptr, // szAppIdentifier -- set later + MDSF_NONINTERACTIVE | // automatically submit report without prompting + MDSF_PREVENTHIJACKING); // disallow swiping Exception filter sBugSplatSender->setCallback(bugsplatSendLog); // engage stringize() overload that converts from wstring -- cgit v1.2.3 From 62eecd87a5610aae41cff6dc6ebcc81e7bcb474f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 10 Jul 2018 17:47:00 -0400 Subject: SL-932: Attach user's settings.xml file to Windows crash reports. It is not obvious whether the BugsplatMac attachment API even supports multiple file attachments. I've contacted BugSplat support. --- indra/newview/llappviewerwin32.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 1e135fa229..adb3a2bbe2 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -123,6 +123,9 @@ namespace sBugSplatSender->sendAdditionalFile( WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log"))); + sBugSplatSender->sendAdditionalFile( + WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "settings.xml"))); + if (gAgentAvatarp) { // user name, when we have it -- cgit v1.2.3 From 66d083967ec25b5c46424689624b2aa366a2ae6b Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 11 Jul 2018 16:01:48 -0400 Subject: DRTVWR-447: Add more diagnostic logging to Windows BugSplat crash. --- indra/newview/llappviewerwin32.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index adb3a2bbe2..5c7cb5b9c6 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -116,24 +116,38 @@ namespace bool bugsplatSendLog(UINT nCode, LPVOID lpVal1, LPVOID lpVal2) { + // When BugSplat intercepts a crash, logging seems to stop?! + // Maybe because our test crashes use LL_ERROR(). Try writing a + // special log file "by hand." + std::ofstream log(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "BugSplat.log"), + std::ios_base::app); + log << "Entered bugsplatSendLog() callback\n"; 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, "SecondLife.log"))); + log << "Attached " << gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log") << '\n'; sBugSplatSender->sendAdditionalFile( WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "settings.xml"))); + log << "Attached " << gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "settings.xml") << '\n'; if (gAgentAvatarp) { // user name, when we have it sBugSplatSender->setDefaultUserName(WCSTR(gAgentAvatarp->getFullname())); + log << "Set default user name to '" << gAgentAvatarp->getFullname() << "'\n"; + } + else + { + log << "gAgentAvatarp is nullptr\n"; } // LL_ERRS message, when there is one sBugSplatSender->setDefaultUserDescription(WCSTR(LLError::getFatalMessage())); + log << "Set default user description to '" << LLError::getFatalMessage() << "'\n"; if (gAgent.getRegion()) { @@ -144,10 +158,25 @@ namespace << '/' << loc.mV[0] << '/' << loc.mV[1] << '/' << loc.mV[2]))); + log << "Set app identifier to '" + << gAgent.getRegion()->getName() + << '/' << loc.mV[0] + << '/' << loc.mV[1] + << '/' << log.mV[2] + << "'\n"; + } + else + { + log "gAgent.getRegion() is nullptr\n"; } LL_INFOS() << "Sending crash report to BugSplat." << LL_ENDL; + log << "Sending crash report to BugSplat.\n"; } // MDSCB_EXCEPTIONCODE + else + { + log << "nCode != MDSCB_EXCEPTIONCODE\n"; + } return false; } -- cgit v1.2.3 From 869d2f1fb2ed59e65dd9cb8b75a9ea560dbeab2d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 11 Jul 2018 18:26:27 -0400 Subject: DRTVWR-447: Fix silly typos --- indra/newview/llappviewerwin32.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 5c7cb5b9c6..43b25699ca 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -162,12 +162,12 @@ namespace << gAgent.getRegion()->getName() << '/' << loc.mV[0] << '/' << loc.mV[1] - << '/' << log.mV[2] + << '/' << loc.mV[2] << "'\n"; } else { - log "gAgent.getRegion() is nullptr\n"; + log << "gAgent.getRegion() is nullptr\n"; } LL_INFOS() << "Sending crash report to BugSplat." << LL_ENDL; -- cgit v1.2.3 From c7616af624f784e6226f530f6a21b3541ba730cc Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 11 Jul 2018 21:52:03 -0400 Subject: DRTVWR-447: Diagnostically try naively widening BugSplat metadata. --- indra/newview/llappviewerwin32.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 43b25699ca..b78d6bdc62 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -104,7 +104,11 @@ namespace // specific wstringize() overload inline std::basic_string<__wchar_t> wunder(const std::string& str) { - return wunder(wstringize(str)); +// return wunder(wstringize(str)); + // Is wstringize(const std::string&) doing the right thing? Try + // widening each character individually -- which works only for 8-bit + // characters, of course -- just diagnostically. + return { str.begin(), str.end() }; } // Irritatingly, MiniDmpSender::setCallback() is defined to accept a -- cgit v1.2.3 From b883ffaa750630ce15bd133c3ddd1f39896fee02 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 12 Jul 2018 14:45:14 -0400 Subject: DRTVWR-447: More diagnostic logging for BugSplat metadata strings. --- indra/newview/llappviewerwin32.cpp | 55 ++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 11 deletions(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index b78d6bdc62..43a61c3857 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -70,6 +70,7 @@ #include "llerrorcontrol.h" #include +#include #include // Bugsplat (http://bugsplat.com) crash reporting tool @@ -111,6 +112,38 @@ namespace return { str.begin(), str.end() }; } + // can only be used in a context in which 'log' is a valid std::ostream + #define WVCSTR(string) wview(log, WCSTR(string)) + + const __wchar_t* wview(std::ostream& out, const __wchar_t* wstr) + { + const size_t maxlen = 50; + char buffer[maxlen]; + size_t size; + // Classic-C loop to calculate size; also forcibly narrow each + // __wchar_t to plain char into 'buffer'. + for (size = 0; size < (maxlen - 1) && wstr[size]; ++size) + buffer[size] = char(wstr[size]); + buffer[size] = '\0'; + // Log the length, show the plain chars + out << "(length " << size << ") '" << buffer << "' "; + // Now dump the memory pointed to by wstr as raw bytes. + char oldfill = out.fill(); + out << std::hex << std::setfill('0') << std::setw(2); + unsigned char* bytes = reinterpret_cast(wstr); + // Increment by one __wchar_t so we display the final nul character; + // remember to multiply by the number of bytes in a __wchar_t. + for (size_t b = 0; b < ((size + 1) * sizeof(__wchar_t)); ++b) + { + // To display as hex, need to convert each byte to int -- if we engage + // the operator<<(ostream&, char) overload, we'll just get characters. + out << int(bytes[b]); + } + out << std::dec << std::setfill(oldfill) << std::setw(0); + out << '\n'; + return wstr; + } + // 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 @@ -131,18 +164,18 @@ namespace // 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, "SecondLife.log"))); - log << "Attached " << gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log") << '\n'; + WVCSTR(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log"))); + log << "sendAdditionalFile('" << gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log") << "')\n"; sBugSplatSender->sendAdditionalFile( - WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "settings.xml"))); - log << "Attached " << gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "settings.xml") << '\n'; + WVCSTR(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "settings.xml"))); + log << "sendAdditionalFile('" << gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "settings.xml") << "')\n"; if (gAgentAvatarp) { // user name, when we have it - sBugSplatSender->setDefaultUserName(WCSTR(gAgentAvatarp->getFullname())); - log << "Set default user name to '" << gAgentAvatarp->getFullname() << "'\n"; + sBugSplatSender->setDefaultUserName(WVCSTR(gAgentAvatarp->getFullname())); + log << "setDefaultUserName('" << gAgentAvatarp->getFullname() << "')\n"; } else { @@ -150,24 +183,24 @@ namespace } // LL_ERRS message, when there is one - sBugSplatSender->setDefaultUserDescription(WCSTR(LLError::getFatalMessage())); - log << "Set default user description to '" << LLError::getFatalMessage() << "'\n"; + sBugSplatSender->setDefaultUserDescription(WVCSTR(LLError::getFatalMessage())); + log << "setDefaultUserDescription('" << LLError::getFatalMessage() << "')\n"; if (gAgent.getRegion()) { // region location, when we have it LLVector3 loc = gAgent.getPositionAgent(); sBugSplatSender->resetAppIdentifier( - WCSTR(STRINGIZE(gAgent.getRegion()->getName() + WVCSTR(STRINGIZE(gAgent.getRegion()->getName() << '/' << loc.mV[0] << '/' << loc.mV[1] << '/' << loc.mV[2]))); - log << "Set app identifier to '" + log << "resetAppIdentifier('" << gAgent.getRegion()->getName() << '/' << loc.mV[0] << '/' << loc.mV[1] << '/' << loc.mV[2] - << "'\n"; + << "')\n"; } else { -- cgit v1.2.3 From 3888d1862a79ab927d118087b2ce662f15e27f41 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 12 Jul 2018 16:07:06 -0400 Subject: DRTVWR-447: For want of a 'const', the build was lost. --- indra/newview/llappviewerwin32.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 43a61c3857..d2854c6b47 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -130,7 +130,7 @@ namespace // Now dump the memory pointed to by wstr as raw bytes. char oldfill = out.fill(); out << std::hex << std::setfill('0') << std::setw(2); - unsigned char* bytes = reinterpret_cast(wstr); + const unsigned char* bytes = reinterpret_cast(wstr); // Increment by one __wchar_t so we display the final nul character; // remember to multiply by the number of bytes in a __wchar_t. for (size_t b = 0; b < ((size + 1) * sizeof(__wchar_t)); ++b) -- cgit v1.2.3 From 234ca77f19e53de1c02f8a641530ba89c90f1298 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Sat, 14 Jul 2018 08:52:58 -0400 Subject: DRTVWR-447: Revert BugSplat diagnostic logging; add platform tag. --- indra/newview/llappviewerwin32.cpp | 86 +++++--------------------------------- 1 file changed, 11 insertions(+), 75 deletions(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index d2854c6b47..adb340d40e 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -70,7 +70,6 @@ #include "llerrorcontrol.h" #include -#include #include // Bugsplat (http://bugsplat.com) crash reporting tool @@ -95,7 +94,7 @@ namespace // 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 make exactly one call to initialize BugSplat. + // to the BugSplat API -- a handful of calls. inline std::basic_string<__wchar_t> wunder(const std::wstring& str) { return { str.begin(), str.end() }; @@ -105,43 +104,7 @@ namespace // specific wstringize() overload inline std::basic_string<__wchar_t> wunder(const std::string& str) { -// return wunder(wstringize(str)); - // Is wstringize(const std::string&) doing the right thing? Try - // widening each character individually -- which works only for 8-bit - // characters, of course -- just diagnostically. - return { str.begin(), str.end() }; - } - - // can only be used in a context in which 'log' is a valid std::ostream - #define WVCSTR(string) wview(log, WCSTR(string)) - - const __wchar_t* wview(std::ostream& out, const __wchar_t* wstr) - { - const size_t maxlen = 50; - char buffer[maxlen]; - size_t size; - // Classic-C loop to calculate size; also forcibly narrow each - // __wchar_t to plain char into 'buffer'. - for (size = 0; size < (maxlen - 1) && wstr[size]; ++size) - buffer[size] = char(wstr[size]); - buffer[size] = '\0'; - // Log the length, show the plain chars - out << "(length " << size << ") '" << buffer << "' "; - // Now dump the memory pointed to by wstr as raw bytes. - char oldfill = out.fill(); - out << std::hex << std::setfill('0') << std::setw(2); - const unsigned char* bytes = reinterpret_cast(wstr); - // Increment by one __wchar_t so we display the final nul character; - // remember to multiply by the number of bytes in a __wchar_t. - for (size_t b = 0; b < ((size + 1) * sizeof(__wchar_t)); ++b) - { - // To display as hex, need to convert each byte to int -- if we engage - // the operator<<(ostream&, char) overload, we'll just get characters. - out << int(bytes[b]); - } - out << std::dec << std::setfill(oldfill) << std::setw(0); - out << '\n'; - return wstr; + return wunder(wstringize(str)); } // Irritatingly, MiniDmpSender::setCallback() is defined to accept a @@ -153,67 +116,40 @@ namespace bool bugsplatSendLog(UINT nCode, LPVOID lpVal1, LPVOID lpVal2) { - // When BugSplat intercepts a crash, logging seems to stop?! - // Maybe because our test crashes use LL_ERROR(). Try writing a - // special log file "by hand." - std::ofstream log(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "BugSplat.log"), - std::ios_base::app); - log << "Entered bugsplatSendLog() callback\n"; if (nCode == MDSCB_EXCEPTIONCODE) { // send the main viewer log file // widen to wstring, convert to __wchar_t, then pass c_str() sBugSplatSender->sendAdditionalFile( - WVCSTR(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log"))); - log << "sendAdditionalFile('" << gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log") << "')\n"; + WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log"))); sBugSplatSender->sendAdditionalFile( - WVCSTR(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "settings.xml"))); - log << "sendAdditionalFile('" << gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "settings.xml") << "')\n"; + WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "settings.xml"))); + + // We don't have an email address for any user. Hijack this + // metadata field for the platform identifier. + sBugSplatSender->setDefaultUserEmail(WCSTR(STRINGIZE("Windows" << ADDRESS_SIZE))); if (gAgentAvatarp) { // user name, when we have it - sBugSplatSender->setDefaultUserName(WVCSTR(gAgentAvatarp->getFullname())); - log << "setDefaultUserName('" << gAgentAvatarp->getFullname() << "')\n"; - } - else - { - log << "gAgentAvatarp is nullptr\n"; + sBugSplatSender->setDefaultUserName(WCSTR(gAgentAvatarp->getFullname())); } // LL_ERRS message, when there is one - sBugSplatSender->setDefaultUserDescription(WVCSTR(LLError::getFatalMessage())); - log << "setDefaultUserDescription('" << LLError::getFatalMessage() << "')\n"; + sBugSplatSender->setDefaultUserDescription(WCSTR(LLError::getFatalMessage())); if (gAgent.getRegion()) { // region location, when we have it LLVector3 loc = gAgent.getPositionAgent(); sBugSplatSender->resetAppIdentifier( - WVCSTR(STRINGIZE(gAgent.getRegion()->getName() + WCSTR(STRINGIZE(gAgent.getRegion()->getName() << '/' << loc.mV[0] << '/' << loc.mV[1] << '/' << loc.mV[2]))); - log << "resetAppIdentifier('" - << gAgent.getRegion()->getName() - << '/' << loc.mV[0] - << '/' << loc.mV[1] - << '/' << loc.mV[2] - << "')\n"; - } - else - { - log << "gAgent.getRegion() is nullptr\n"; } - - LL_INFOS() << "Sending crash report to BugSplat." << LL_ENDL; - log << "Sending crash report to BugSplat.\n"; } // MDSCB_EXCEPTIONCODE - else - { - log << "nCode != MDSCB_EXCEPTIONCODE\n"; - } return false; } -- cgit v1.2.3