Skip to content
Snippets Groups Projects
Commit cd52724e authored by Nat Goodspeed's avatar Nat Goodspeed
Browse files

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.
parent f6e7893a
No related branches found
No related tags found
No related merge requests found
......@@ -377,6 +377,7 @@ namespace
public:
std::ostringstream messageStream;
bool messageStreamInUse;
std::string mFatalMessage;
void addCallSite(LLError::CallSite&);
void invalidateCallSites();
......@@ -670,11 +671,16 @@ namespace LLError
s->mCrashFunction = f;
}
FatalFunction getFatalFunction()
{
FatalFunction getFatalFunction()
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
return s->mCrashFunction;
}
return s->mCrashFunction;
}
std::string getFatalMessage()
{
return Globals::getInstance()->mFatalMessage;
}
void setTimeFunction(TimeFunction f)
{
......@@ -1194,7 +1200,7 @@ namespace LLError
{
writeToRecorders(site, "error", true, true, true, false, false);
}
std::ostringstream message_stream;
if (site.mPrintOnce)
......@@ -1219,14 +1225,19 @@ namespace LLError
s->mUniqueLogMessages[message] = 1;
}
}
message_stream << message;
writeToRecorders(site, message_stream.str());
if (site.mLevel == LEVEL_ERROR && s->mCrashFunction)
std::string message_line(message_stream.str());
writeToRecorders(site, message_line);
if (site.mLevel == LEVEL_ERROR)
{
s->mCrashFunction(message_stream.str());
g->mFatalMessage = message_line;
if (s->mCrashFunction)
{
s->mCrashFunction(message_line);
}
}
}
}
......
......@@ -102,6 +102,9 @@ namespace LLError
LL_COMMON_API FatalFunction getFatalFunction();
// Retrieve the previously-set FatalFunction
LL_COMMON_API std::string getFatalMessage();
// Retrieve the message last passed to FatalFunction, if any
/// temporarily override the FatalFunction for the duration of a
/// particular scope, e.g. for unit tests
class LL_COMMON_API OverrideFatalFunction
......
......@@ -74,9 +74,9 @@
#if defined(LL_BUGSPLAT)
// https://www.bugsplat.com/docs/platforms/os-x#initialization
// [BugsplatStartupManager sharedManager].autoSubmitCrashReport = YES;
// [BugsplatStartupManager sharedManager].askUserDetails = NO;
[BugsplatStartupManager sharedManager].delegate = self;
[BugsplatStartupManager sharedManager].autoSubmitCrashReport = YES;
[BugsplatStartupManager sharedManager].askUserDetails = NO;
[BugsplatStartupManager sharedManager].delegate = self;
[[BugsplatStartupManager sharedManager] start];
#endif
}
......@@ -196,17 +196,20 @@
#if defined(LL_BUGSPLAT)
#if 0
// Apparently this override method only contributes the User Description field
// of BugSplat's All Crashes table. Despite the method name, it would seem to
// be a bad place to try to stuff all of SecondLife.log.
- (NSString *)applicationLogForBugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager
{
// return NSStringFromSelector(_cmd);
infos("Reached applicationLogForBugsplatStartupManager");
return @"[contents of SecondLife.log]";
// Apparently this override method only contributes the User Description
// field of BugSplat's All Crashes table. Despite the method name, it
// would seem to be a bad place to try to stuff all of SecondLife.log.
return [NSString stringWithCString:getFatalMessage().c_str()
encoding:NSUTF8StringEncoding];
}
- (void)bugsplatStartupManagerWillSendCrashReport:(BugsplatStartupManager *)bugsplatStartupManager
{
infos("Reached bugsplatStartupManagerWillSendCrashReport");
}
#endif
- (BugsplatAttachment *)attachmentForBugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager {
// We get the *old* log file pathname (for SecondLife.old) because it's on
......@@ -228,6 +231,17 @@
return attachment;
}
- (void)bugsplatStartupManagerDidFinishSendingCrashReport:(BugsplatStartupManager *)bugsplatStartupManager
{
infos("Sent crash report to BugSplat");
}
- (void)bugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager didFailWithError:(NSError *)error
{
// TODO: message string from NSError
infos("Could not send crash report to BugSplat");
}
#endif // LL_BUGSPLAT
@end
......@@ -30,6 +30,8 @@ bool pumpMainLoop();
void handleQuit();
void cleanupViewer();
std::string getOldLogFilePathname();
std::string getFatalMessage();
std::string getAgentFullname();
void infos(const std::string& message);
#endif /* ! defined(LL_LLAPPVIEWERMACOSX_FOR_OBJC_H) */
......@@ -45,6 +45,8 @@
#include "llmd5.h"
#include "llfloaterworldmap.h"
#include "llurldispatcher.h"
#include "llerrorcontrol.h"
#include "llvoavatarself.h" // for gAgentAvatarp->getFullname()
#include <ApplicationServices/ApplicationServices.h>
#ifdef LL_CARBON_CRASH_HANDLER
#include <Carbon/Carbon.h>
......@@ -153,6 +155,16 @@ std::string getOldLogFilePathname()
return gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.old");
}
std::string getFatalMessage()
{
return LLError::getFatalMessage();
}
std::string getAgentFullname()
{
return gAgentAvatarp? gAgentAvatarp->getFullname() : std::string();
}
void infos(const std::string& message)
{
LL_INFOS() << message << LL_ENDL;
......
......@@ -67,6 +67,7 @@
#include "stringize.h"
#include "lldir.h"
#include "llerrorcontrol.h"
#include <fstream>
#include <exception>
......@@ -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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment