summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2018-08-22 10:48:29 -0400
committerNat Goodspeed <nat@lindenlab.com>2018-08-22 10:48:29 -0400
commit7dc014474de0c2d83a3cd314acd9dc0882622299 (patch)
tree9f72ece0fde5764a41733d6853992dc0196bce78
parent302052700b4605605808b90bed8fb1c5a93ece22 (diff)
DRTVWR-447: Attempt to post BugSplat metadata with Mac crash reports.
Introduce CrashMetadata, an LLSingleton in llappviewermacosx.cpp, declared in llappviewermacosx-for-objc.h and accessed by the various BugsplatStartupManagerDelegate override methods. CrashMetadata is populated by reading the previous (presumably crashed) run's static_debug_info.log file. This replaces the previous getOldLogFilePathname(), getFatalMessage() and getAgentFullname() functions. To extend that suite for additional metadata, not only would we have to keep adding new free functions, but we'd have to keep rereading the static_debug_info.log file. Override the new applicationKeyForBugsplatStartupManager, defaultUserNameForBugsplatStartupManager, defaultUserEmailForBugsplatStartupManager methods to extract relevant fields from CrashMetadata. Change applicationLogForBugsplatStartupManager and attachmentForBugsplatStartupManager to do the same. Enhance llviewerregion.cpp to update the static_debug_info.log file every time we enter a new region.
-rw-r--r--indra/newview/llappdelegate-objc.mm43
-rw-r--r--indra/newview/llappviewermacosx-for-objc.h21
-rw-r--r--indra/newview/llappviewermacosx.cpp45
-rw-r--r--indra/newview/llviewerregion.cpp19
4 files changed, 109 insertions, 19 deletions
diff --git a/indra/newview/llappdelegate-objc.mm b/indra/newview/llappdelegate-objc.mm
index 82e49540a4..ba697d0f77 100644
--- a/indra/newview/llappdelegate-objc.mm
+++ b/indra/newview/llappdelegate-objc.mm
@@ -199,10 +199,34 @@
- (NSString *)applicationLogForBugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager
{
infos("Reached applicationLogForBugsplatStartupManager");
- // 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()
+ // This strangely-named override method contributes the User Description
+ // metadata field.
+ return [NSString stringWithCString:CrashMetadata_instance().fatalMessage.c_str()
+ encoding:NSUTF8StringEncoding];
+}
+
+- (NSString *)applicationKeyForBugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager signal:(NSString *)signal exceptionName:(NSString *)exceptionName exceptionReason:(NSString *)exceptionReason {
+ // TODO: exceptionName, exceptionReason
+
+ // Windows sends location within region as well, but that's because
+ // BugSplat for Windows intercepts crashes during the same run, and that
+ // information can be queried once. On the Mac, any metadata we have is
+ // written (and rewritten) to the static_debug_info.log file that we read
+ // at the start of the next viewer run. It seems ridiculously expensive to
+ // rewrite that file on every frame in which the avatar moves.
+ return [NSString stringWithCString:CrashMetadata_instance().regionName.c_str()
+ encoding:NSUTF8StringEncoding];
+}
+
+- (NSString *)defaultUserNameForBugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager {
+ return [NSString stringWithCString:CrashMetadata_instance().agentFullname.c_str()
+ encoding:NSUTF8StringEncoding];
+}
+
+- (NSString *)defaultUserEmailForBugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager {
+ // Use the email field for OS version, just as we do on Windows, until
+ // BugSplat provides more metadata fields.
+ return [NSString stringWithCString:CrashMetadata_instance().OSInfo.c_str()
encoding:NSUTF8StringEncoding];
}
@@ -212,11 +236,12 @@
}
- (BugsplatAttachment *)attachmentForBugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager {
- // We get the *old* log file pathname (for SecondLife.old) because it's on
- // the run *following* the crash that BugsplatStartupManager notices that
- // the previous run crashed and calls this override. By that time, we've
- // already renamed SecondLife.log to SecondLife.old.
- std::string logfile = getOldLogFilePathname();
+ std::string logfile = CrashMetadata_instance().logFilePathname;
+ // Still to do:
+ // userSettingsPathname
+ // staticDebugPathname
+ // but the BugsplatMac version 1.0.5 BugsplatStartupManagerDelegate API
+ // doesn't yet provide a way to attach more than one file.
NSString *ns_logfile = [NSString stringWithCString:logfile.c_str()
encoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithContentsOfFile:ns_logfile];
diff --git a/indra/newview/llappviewermacosx-for-objc.h b/indra/newview/llappviewermacosx-for-objc.h
index ac85d7e8c3..79da453cbe 100644
--- a/indra/newview/llappviewermacosx-for-objc.h
+++ b/indra/newview/llappviewermacosx-for-objc.h
@@ -29,9 +29,24 @@ void handleUrl(const char* url_utf8);
bool pumpMainLoop();
void handleQuit();
void cleanupViewer();
-std::string getOldLogFilePathname();
-std::string getFatalMessage();
-std::string getAgentFullname();
void infos(const std::string& message);
+// This struct is malleable; it only serves as a way to convey a number of
+// fields from llappviewermacosx.cpp's CrashMetadata_instance() function to the
+// consuming functions in llappdelegate-objc.mm. As long as both those sources
+// are compiled with this same header, the content and order of CrashMetadata
+// can change as needed.
+struct CrashMetadata
+{
+ std::string logFilePathname;
+ std::string userSettingsPathname;
+ std::string staticDebugPathname;
+ std::string OSInfo;
+ std::string agentFullname;
+ std::string regionName;
+ std::string fatalMessage;
+};
+
+CrashMetadata& CrashMetadata_instance();
+
#endif /* ! defined(LL_LLAPPVIEWERMACOSX_FOR_OBJC_H) */
diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp
index c3a3c3284a..7f7284a796 100644
--- a/indra/newview/llappviewermacosx.cpp
+++ b/indra/newview/llappviewermacosx.cpp
@@ -39,6 +39,7 @@
#include "llappviewermacosx-for-objc.h"
#include "llwindowmacosx-objc.h"
#include "llcommandlineparser.h"
+#include "llsdserialize.h"
#include "llviewernetwork.h"
#include "llviewercontrol.h"
@@ -53,6 +54,7 @@
#endif
#include <vector>
#include <exception>
+#include <fstream>
#include "lldir.h"
#include <signal.h>
@@ -150,19 +152,48 @@ void cleanupViewer()
gViewerAppPtr = NULL;
}
-std::string getOldLogFilePathname()
+// The BugsplatMac API is structured as a number of different method
+// overrides, each returning a different piece of metadata. But since we
+// obtain such metadata by opening and parsing a file, it seems ridiculous to
+// reopen and reparse it for every individual string desired. What we want is
+// to open and parse the file once, retaining the data for subsequent
+// requests. That's why this is an LLSingleton.
+// Another approach would be to provide a function that simply returns
+// CrashMetadata, storing the struct in LLAppDelegate, but nat doesn't know
+// enough Objective-C++ to code that. We'd still have to detect which of the
+// method overrides is called first so that the results are order-insensitive.
+class CrashMetadataSingleton: public CrashMetadata, public LLSingleton<CrashMetadataSingleton>
{
- return gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.old");
-}
+ LLSINGLETON(CrashMetadataSingleton);
+};
-std::string getFatalMessage()
+// Populate the fields of our public base-class struct.
+CrashMetadataSingleton::CrashMetadataSingleton()
{
- return LLError::getFatalMessage();
+ // Note: we depend on being able to read the static_debug_info.log file
+ // from the *previous* run before we overwrite it with the new one for
+ // *this* run. LLAppViewer initialization must happen in the Right Order.
+ staticDebugPathname = *gViewerAppPtr->getStaticDebugFile();
+ std::ifstream static_file(staticDebugPathname);
+ LLSD info;
+ if (static_file.is_open() &&
+ LLSDSerialize::deserialize(info, static_file, LLSDSerialize::SIZE_UNLIMITED))
+ {
+ logFilePathname = info["SLLog"].asString();
+ userSettingsPathname = info["SettingsFilename"].asString();
+ OSInfo = info["OSInfo"].asString();
+ agentFullname = info["LoginName"].asString();
+ // Translate underscores back to spaces
+ LLStringUtil::replaceChar(agentFullname, '_', ' ');
+ regionName = info["CurrentRegion"].asString();
+ fatalMessage = info["FatalMessage"].asString();
+ }
}
-std::string getAgentFullname()
+// Avoid having to compile all of our LLSingleton machinery in Objective-C++.
+CrashMetadata& CrashMetadata_instance()
{
- return gAgentAvatarp? gAgentAvatarp->getFullname() : std::string();
+ return CrashMetadataSingleton::instance();
}
void infos(const std::string& message)
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index b759c2a3ab..ca452fc766 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -44,6 +44,7 @@
#include "llagent.h"
#include "llagentcamera.h"
+#include "llappviewer.h"
#include "llavatarrenderinfoaccountant.h"
#include "llcallingcard.h"
#include "llcommandhandler.h"
@@ -104,6 +105,18 @@ typedef std::map<std::string, std::string> CapabilityMap;
static void log_capabilities(const CapabilityMap &capmap);
+namespace
+{
+
+void newRegionEntry(LLViewerRegion& region)
+{
+ LL_INFOS("LLViewerRegion") << "Entering region [" << region.getName() << "]" << LL_ENDL;
+ gDebugInfo["CurrentRegion"] = region.getName();
+ LLAppViewer::instance()->writeDebugInfo();
+}
+
+} // anonymous namespace
+
// support for secondlife:///app/region/{REGION} SLapps
// N.B. this is defined to work exactly like the classic secondlife://{REGION}
// However, the later syntax cannot support spaces in the region name because
@@ -249,6 +262,9 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)
return; // this error condition is not recoverable.
}
+ // record that we just entered a new region
+ newRegionEntry(*regionp);
+
// After a few attempts, continue login. But keep trying to get the caps:
if (mSeedCapAttempts >= mSeedCapMaxAttemptsBeforeLogin &&
STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
@@ -369,6 +385,9 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle)
break; // this error condition is not recoverable.
}
+ // record that we just entered a new region
+ newRegionEntry(*regionp);
+
LLSD capabilityNames = LLSD::emptyArray();
buildCapabilityNames(capabilityNames);