Rework crash reporting UI

* Encourage users running dev code to submit reports
* Change from "Disable" to "Enable"
* Always initialize Crashpad and just prevent uploads if disabled
* Fix menu not being in sync
* Add documentation
* Keep track of whether Crashpad initialized successfully
This commit is contained in:
Dale Glass 2023-06-25 20:14:13 +02:00
parent 179fe79168
commit de706ab458
12 changed files with 262 additions and 39 deletions

View file

@ -21,5 +21,7 @@ Q_DECLARE_LOGGING_CATEGORY(crash_handler)
bool startCrashHandler(std::string appPath); bool startCrashHandler(std::string appPath);
void setCrashAnnotation(std::string name, std::string value); void setCrashAnnotation(std::string name, std::string value);
void startCrashHookMonitor(QCoreApplication* app); void startCrashHookMonitor(QCoreApplication* app);
void setCrashReportingEnabled(bool value);
#endif // hifi_CrashHandler_h #endif // hifi_CrashHandler_h

View file

@ -81,6 +81,11 @@ void setCrashAnnotation(std::string name, std::string value) {
flushAnnotations(); flushAnnotations();
} }
void setCrashReportingEnabled(bool value) {
qCritical() << "Can't set crash reporting status on Breakpad.";
qCritical() << "Breakpad is deprecated and needs replacing!";
}
void startCrashHookMonitor(QCoreApplication* app) { void startCrashHookMonitor(QCoreApplication* app) {
} }

View file

@ -43,6 +43,8 @@ Q_LOGGING_CATEGORY(crash_handler, "overte.crash_handler")
#include <BuildInfo.h> #include <BuildInfo.h>
#include <FingerprintUtils.h> #include <FingerprintUtils.h>
#include <UUID.h> #include <UUID.h>
#include <UserActivityLogger.h>
static const std::string BACKTRACE_URL{ CMAKE_BACKTRACE_URL }; static const std::string BACKTRACE_URL{ CMAKE_BACKTRACE_URL };
static const std::string BACKTRACE_TOKEN{ CMAKE_BACKTRACE_TOKEN }; static const std::string BACKTRACE_TOKEN{ CMAKE_BACKTRACE_TOKEN };
@ -134,6 +136,9 @@ bool SpinLockLocker::relock(int msecs /* = -1 */ ) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
crashpad::CrashpadClient* client{ nullptr }; crashpad::CrashpadClient* client{ nullptr };
std::unique_ptr< crashpad::CrashReportDatabase > crashpadDatabase;
SpinLock crashpadAnnotationsProtect; SpinLock crashpadAnnotationsProtect;
crashpad::SimpleStringDictionary* crashpadAnnotations{ nullptr }; crashpad::SimpleStringDictionary* crashpadAnnotations{ nullptr };
@ -409,14 +414,20 @@ bool startCrashHandler(std::string appPath) {
base::FilePath handler(handlerPath); base::FilePath handler(handlerPath);
qCDebug(crash_handler) << "Opening crashpad database" << QString::fromStdString(crashpadDbPath); qCDebug(crash_handler) << "Opening crashpad database" << QString::fromStdString(crashpadDbPath);
auto database = crashpad::CrashReportDatabase::Initialize(db); crashpadDatabase = crashpad::CrashReportDatabase::Initialize(db);
if (database == nullptr || database->GetSettings() == nullptr) { if (crashpadDatabase == nullptr || crashpadDatabase->GetSettings() == nullptr) {
qCCritical(crash_handler) << "Failed to open crashpad database" << QString::fromStdString(crashpadDbPath); qCCritical(crash_handler) << "Failed to open crashpad database" << QString::fromStdString(crashpadDbPath);
return false; return false;
} }
// Enable automated uploads. // Enable automated uploads.
database->GetSettings()->SetUploadsEnabled(true); QObject::connect(&UserActivityLogger::getInstance(), &UserActivityLogger::crashReportingEnabledChanged, []() {
auto &ual = UserActivityLogger::getInstance();
setCrashReportingEnabled(ual.isCrashReportingEnabled());
});
crashpadDatabase->GetSettings()->SetUploadsEnabled(UserActivityLogger::getInstance().isCrashReportingEnabled());
if (!client->StartHandler(handler, db, db, BACKTRACE_URL, annotations, arguments, true, true)) { if (!client->StartHandler(handler, db, db, BACKTRACE_URL, annotations, arguments, true, true)) {
qCCritical(crash_handler) << "Failed to start crashpad handler"; qCCritical(crash_handler) << "Failed to start crashpad handler";
@ -432,6 +443,36 @@ bool startCrashHandler(std::string appPath) {
return true; return true;
} }
void setCrashReportingEnabled(bool enabled) {
auto settings = crashpadDatabase->GetSettings();
settings->SetUploadsEnabled(enabled);
if (enabled) {
// Enabled now, was disabled before
//
// Reports are generated while uploads are disabled, so if we didn't do this we could
// send something the user doesn't want sent. So if reporting was disabled then enabled,
// remove any pending reports.
qCDebug(crash_handler) << "Removing any pending crash reports";
std::vector<crashpad::CrashReportDatabase::Report> pendingReports;
crashpad::CrashReportDatabase::OperationStatus status;
status = crashpadDatabase->GetPendingReports(&pendingReports);
if (status != crashpad::CrashReportDatabase::kNoError) {
qCWarning(crash_handler) << "Failed to get pending reports";
} else {
for (const auto& report : pendingReports) {
qCDebug(crash_handler) << "Deleted crash report" << QString::fromStdString(report.uuid.ToString());
crashpadDatabase->DeleteReport(report.uuid);
}
}
}
qCInfo(crash_handler) << "Crashpad uploads " << (enabled ? QString("enabled") : QString("disabled"));
}
void setCrashAnnotation(std::string name, std::string value) { void setCrashAnnotation(std::string name, std::string value) {
if (client) { if (client) {
SpinLockLocker guard(crashpadAnnotationsProtect); SpinLockLocker guard(crashpadAnnotationsProtect);

View file

@ -31,4 +31,7 @@ void setCrashAnnotation(std::string name, std::string value) {
void startCrashHookMonitor(QCoreApplication* app) { void startCrashHookMonitor(QCoreApplication* app) {
} }
void setCrashReportingEnabled(bool value) {
}
#endif #endif

View file

@ -27,15 +27,22 @@
#include "Menu.h" #include "Menu.h"
#include <RunningMarker.h> #include <RunningMarker.h>
#include <SettingHandle.h> #include <SettingHandle.h>
#include <SettingHelpers.h> #include <SettingHelpers.h>
#include <SettingManager.h> #include <SettingManager.h>
#include <DependencyManager.h> #include <DependencyManager.h>
#include <UserActivityLogger.h> #include <UserActivityLogger.h>
#include <BuildInfo.h>
static const QString BACKTRACE_URL{ CMAKE_BACKTRACE_URL };
bool CrashRecoveryHandler::checkForResetSettings(bool wasLikelyCrash, bool suppressPrompt) { bool CrashRecoveryHandler::checkForResetSettings(bool wasLikelyCrash, bool suppressPrompt) {
Setting::Handle<bool> crashReportingAsked { "CrashReportingAsked", false };
Settings settings; Settings settings;
settings.beginGroup("Developer"); settings.beginGroup("Developer");
QVariant displayCrashOptions = settings.value(MenuOption::DisplayCrashOptions); QVariant displayCrashOptions = settings.value(MenuOption::DisplayCrashOptions);
@ -47,6 +54,7 @@ bool CrashRecoveryHandler::checkForResetSettings(bool wasLikelyCrash, bool suppr
// If option does not exist in Interface.ini so assume default behavior. // If option does not exist in Interface.ini so assume default behavior.
bool displaySettingsResetOnCrash = !displayCrashOptions.isValid() || displayCrashOptions.toBool(); bool displaySettingsResetOnCrash = !displayCrashOptions.isValid() || displayCrashOptions.toBool();
bool userPrompted = false;
if (suppressPrompt) { if (suppressPrompt) {
return wasLikelyCrash; return wasLikelyCrash;
@ -54,18 +62,106 @@ bool CrashRecoveryHandler::checkForResetSettings(bool wasLikelyCrash, bool suppr
if (wasLikelyCrash || askToResetSettings) { if (wasLikelyCrash || askToResetSettings) {
if (displaySettingsResetOnCrash || askToResetSettings) { if (displaySettingsResetOnCrash || askToResetSettings) {
userPrompted = true;
Action action = promptUserForAction(wasLikelyCrash); Action action = promptUserForAction(wasLikelyCrash);
if (action != DO_NOTHING) { if (action != DO_NOTHING) {
handleCrash(action); handleCrash(action);
} }
} }
} }
if (!userPrompted) {
// Both dialogs share a purpose -- if we already showed the full dialog, no need to show this one.
if (BuildInfo::BUILD_TYPE != BuildInfo::BuildType::Stable) {
// We didn't crash but are running a development build -- we'd like reports if possible.
if (suggestCrashReporting()) {
// If suggestCrashReporting returns false, we didn't ask the user.
crashReportingAsked.set(true);
}
}
}
return wasLikelyCrash; return wasLikelyCrash;
} }
bool CrashRecoveryHandler::suggestCrashReporting() {
QDialog crashDialog;
crashDialog.setWindowTitle("You are running an experimental version of Overte");
QVBoxLayout* layout = new QVBoxLayout;
QString explainText;
auto &ual = UserActivityLogger::getInstance();
switch(BuildInfo::BUILD_TYPE) {
case BuildInfo::BuildType::Dev:
explainText = "You're running a pre-release version. This is an official release, but the code\n"
"is not yet considered to be fully stable. We'd highly appreciate it if you enabled\n"
"crash reporting to help us test the upcoming release.";
break;
case BuildInfo::BuildType::PR:
// TODO: It would be nice to have here the PR number, and who submitted it. This would require GHA support.
explainText = "You're running a PR version. This is experimental code contributed by a third party\n"
"and not yet part of the official code. We'd highly appreciate it if you enabled\n"
"crash reporting to help us test this potential addition.";
break;
case BuildInfo::BuildType::Master:
explainText = "You're running a pre-release version. This is an official release, but the code\n"
"is not yet considered to be fully stable. We'd highly appreciate it if you enabled\n"
"crash reporting to help us test the upcoming release.";
break;
case BuildInfo::BuildType::Stable:
explainText = "You're running a stable version. This is an official release, and should perform\n"
"correctly. Nevertheless, we'd highly appreciate it if you enabled crash reporting\n"
"to help us catch any remaining problems.";
break;
}
if (!ual.isCrashMonitorStarted()) {
qWarning() << "Crash reporting not working, skipping suggestion to enable it.";
return false;
}
QLabel* explainLabel = new QLabel(explainText);
QLabel* crashReportLabel = new QLabel("Reports can only be seen by members of the Overte e.V. organization and\n"
"trusted developers, and will only be used for improving the code.");
QCheckBox* crashReportCheckbox = new QCheckBox("Enable automatic crash reporting");
crashReportCheckbox->setChecked(ual.isCrashReportingEnabled());
crashReportCheckbox->setEnabled(ual.isCrashMonitorStarted());
layout->addWidget(explainLabel);
layout->addSpacing(12);
layout->addWidget(crashReportLabel);
layout->addWidget(crashReportCheckbox);
layout->addSpacing(12);
layout->addStretch();
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok);
layout->addWidget(buttons);
crashDialog.connect(buttons, SIGNAL(accepted()), SLOT(accept()));
crashDialog.setLayout(layout);
crashDialog.exec();
ual.setCrashReportingEnabled(crashReportCheckbox->isChecked());
return true;
}
CrashRecoveryHandler::Action CrashRecoveryHandler::promptUserForAction(bool showCrashMessage) { CrashRecoveryHandler::Action CrashRecoveryHandler::promptUserForAction(bool showCrashMessage) {
QDialog crashDialog; QDialog crashDialog;
QLabel* label; QLabel* label;
auto &ual = UserActivityLogger::getInstance();
if (showCrashMessage) { if (showCrashMessage) {
crashDialog.setWindowTitle("Interface Crashed Last Run"); crashDialog.setWindowTitle("Interface Crashed Last Run");
label = new QLabel("If you are having trouble starting would you like to reset your settings?"); label = new QLabel("If you are having trouble starting would you like to reset your settings?");
@ -81,17 +177,21 @@ CrashRecoveryHandler::Action CrashRecoveryHandler::promptUserForAction(bool show
QRadioButton* option1 = new QRadioButton("Reset all my settings"); QRadioButton* option1 = new QRadioButton("Reset all my settings");
QRadioButton* option2 = new QRadioButton("Reset my settings but keep essential info"); QRadioButton* option2 = new QRadioButton("Reset my settings but keep essential info");
QRadioButton* option3 = new QRadioButton("Continue with my current settings"); QRadioButton* option3 = new QRadioButton("Continue with my current settings");
QLabel* crashReportLabel = nullptr;
QLabel* crashReportLabel = new QLabel("To help us with debugging, you can enable automatic crash reports.\n" if (ual.isCrashMonitorStarted()) {
"They'll only be seen by members of the Overte e.V. organization and\n" crashReportLabel = new QLabel("To help us with debugging, you can enable automatic crash reports.\n"
"trusted developers, and will only be used for improving the code."); "They'll only be seen by members of the Overte e.V. organization and\n"
"trusted developers, and will only be used for improving the code.");
} else {
crashReportLabel = new QLabel("Unfortunately, crash reporting isn't built into this release.");
}
QCheckBox* crashReportCheckbox = new QCheckBox("Enable automatic crash reporting"); QCheckBox* crashReportCheckbox = new QCheckBox("Enable automatic crash reporting");
auto &ual = UserActivityLogger::getInstance();
crashReportCheckbox->setChecked(ual.isCrashMonitorEnabled());
crashReportCheckbox->setChecked(ual.isCrashReportingEnabled());
crashReportCheckbox->setEnabled(ual.isCrashMonitorStarted());
option3->setChecked(true); option3->setChecked(true);
layout->addWidget(option1); layout->addWidget(option1);
@ -121,7 +221,7 @@ CrashRecoveryHandler::Action CrashRecoveryHandler::promptUserForAction(bool show
} }
} }
ual.crashMonitorDisable(!crashReportCheckbox->isChecked()); ual.setCrashReportingEnabled(crashReportCheckbox->isChecked());
// Dialog cancelled or "do nothing" option chosen // Dialog cancelled or "do nothing" option chosen
return CrashRecoveryHandler::DO_NOTHING; return CrashRecoveryHandler::DO_NOTHING;

View file

@ -14,6 +14,11 @@
#include <QString> #include <QString>
class CrashRecoveryHandler { class CrashRecoveryHandler {
public: public:
@ -26,8 +31,10 @@ private:
DO_NOTHING DO_NOTHING
}; };
static bool suggestCrashReporting();
static Action promptUserForAction(bool showCrashMessage); static Action promptUserForAction(bool showCrashMessage);
static void handleCrash(Action action); static void handleCrash(Action action);
}; };
#endif // hifi_CrashRecoveryHandler_h #endif // hifi_CrashRecoveryHandler_h

View file

@ -368,7 +368,7 @@ Menu::Menu() {
// Developer > Scripting > Verbose Logging // Developer > Scripting > Verbose Logging
addCheckableActionToQMenuAndActionHash(scriptingOptionsMenu, MenuOption::VerboseLogging, 0, false, addCheckableActionToQMenuAndActionHash(scriptingOptionsMenu, MenuOption::VerboseLogging, 0, false,
qApp, SLOT(updateVerboseLogging())); qApp, SLOT(updateVerboseLogging()));
// Developer > Scripting > Enable Cachebusting of Script.require // Developer > Scripting > Enable Cachebusting of Script.require
addCheckableActionToQMenuAndActionHash(scriptingOptionsMenu, MenuOption::CachebustRequire, 0, false, addCheckableActionToQMenuAndActionHash(scriptingOptionsMenu, MenuOption::CachebustRequire, 0, false,
qApp, SLOT(setCachebustRequire())); qApp, SLOT(setCachebustRequire()));
@ -637,11 +637,12 @@ Menu::Menu() {
&UserActivityLogger::getInstance(), &UserActivityLogger::getInstance(),
SLOT(disable(bool))); SLOT(disable(bool)));
addCheckableActionToQMenuAndActionHash(networkMenu, addCheckableActionToQMenuAndActionHash(networkMenu,
MenuOption::DisableCrashLogger, MenuOption::EnableCrashReporting,
0, 0,
true, UserActivityLogger::getInstance().isCrashReportingEnabled(),
&UserActivityLogger::getInstance(), &UserActivityLogger::getInstance(),
SLOT(crashMonitorDisable(bool))); SLOT(setCrashReportingEnabled(bool)));
addActionToQMenuAndActionHash(networkMenu, MenuOption::ShowDSConnectTable, 0, addActionToQMenuAndActionHash(networkMenu, MenuOption::ShowDSConnectTable, 0,
qApp, SLOT(loadDomainConnectionDialog())); qApp, SLOT(loadDomainConnectionDialog()));

View file

@ -90,7 +90,7 @@ namespace MenuOption {
const QString DeleteAvatarEntitiesBookmark = "Delete Avatar Entities Bookmark"; const QString DeleteAvatarEntitiesBookmark = "Delete Avatar Entities Bookmark";
const QString DeleteBookmark = "Delete Bookmark..."; const QString DeleteBookmark = "Delete Bookmark...";
const QString DisableActivityLogger = "Disable Activity Logger"; const QString DisableActivityLogger = "Disable Activity Logger";
const QString DisableCrashLogger = "Disable Crash Reporter"; const QString EnableCrashReporting = "Enable Crash Reporting";
const QString DisableEyelidAdjustment = "Disable Eyelid Adjustment"; const QString DisableEyelidAdjustment = "Disable Eyelid Adjustment";
const QString DisableLightEntities = "Disable Light Entities"; const QString DisableLightEntities = "Disable Light Entities";
const QString DisplayCrashOptions = "Display Crash Options"; const QString DisplayCrashOptions = "Display Crash Options";
@ -145,7 +145,7 @@ namespace MenuOption {
const QString OctreeStats = "Entity Statistics"; const QString OctreeStats = "Entity Statistics";
const QString OnePointCalibration = "1 Point Calibration"; const QString OnePointCalibration = "1 Point Calibration";
const QString OnlyDisplayTopTen = "Only Display Top Ten"; const QString OnlyDisplayTopTen = "Only Display Top Ten";
const QString OpenVrThreadedSubmit = "OpenVR Threaded Submit"; const QString OpenVrThreadedSubmit = "OpenVR Threaded Submit";
const QString OutputMenu = "Display"; const QString OutputMenu = "Display";
const QString Overlays = "Show Overlays"; const QString Overlays = "Show Overlays";
const QString PackageModel = "Package Avatar as .fst..."; const QString PackageModel = "Package Avatar as .fst...";

View file

@ -421,11 +421,17 @@ int main(int argc, const char* argv[]) {
} }
qDebug() << "UserActivityLogger is enabled:" << ual.isEnabled(); qDebug() << "UserActivityLogger is enabled:" << ual.isEnabled();
bool isCrashHandlerEnabled = ual.isCrashMonitorEnabled() || parser.isSet(forceCrashReportingOption); if (parser.isSet(forceCrashReportingOption)) {
qDebug() << "Crash handler logger is enabled:" << isCrashHandlerEnabled; qInfo() << "Crash reporting enabled on the command-line";
if (isCrashHandlerEnabled) { ual.setCrashReportingEnabled(true);
auto crashHandlerStarted = startCrashHandler(argv[0]); }
auto crashHandlerStarted = startCrashHandler(argv[0]);
if (crashHandlerStarted) {
ual.setCrashMonitorStarted(true);
qDebug() << "Crash handler started:" << crashHandlerStarted; qDebug() << "Crash handler started:" << crashHandlerStarted;
} else {
qWarning() << "Crash handler failed to start";
} }
const QString& applicationName = getInterfaceSharedMemoryName(); const QString& applicationName = getInterfaceSharedMemoryName();

View file

@ -238,9 +238,9 @@ void setupPreferences() {
auto preference = new BrowsePreference(SNAPSHOTS, "Put my snapshots here", getter, setter); auto preference = new BrowsePreference(SNAPSHOTS, "Put my snapshots here", getter, setter);
preferences->addPreference(preference); preferences->addPreference(preference);
} }
{ {
auto getter = []()->bool { auto getter = []()->bool {
if (!DependencyManager::get<Snapshot>()->_snapshotNotifications.isSet()){ if (!DependencyManager::get<Snapshot>()->_snapshotNotifications.isSet()){
DependencyManager::get<Snapshot>()->_snapshotNotifications.set(true); DependencyManager::get<Snapshot>()->_snapshotNotifications.set(true);
} }
@ -278,7 +278,7 @@ void setupPreferences() {
preference->setItems(items); preference->setItems(items);
preferences->addPreference(preference); preferences->addPreference(preference);
} }
{ {
auto getter = []()->float { return SnapshotAnimated::snapshotAnimatedDuration.get(); }; auto getter = []()->float { return SnapshotAnimated::snapshotAnimatedDuration.get(); };
auto setter = [](float value) { SnapshotAnimated::snapshotAnimatedDuration.set(value); }; auto setter = [](float value) { SnapshotAnimated::snapshotAnimatedDuration.set(value); };
@ -299,8 +299,8 @@ void setupPreferences() {
} }
{ {
auto getter = []()->bool { return !Menu::getInstance()->isOptionChecked(MenuOption::DisableCrashLogger); }; auto getter = []()->bool { return Menu::getInstance()->isOptionChecked(MenuOption::EnableCrashReporting); };
auto setter = [](bool value) { Menu::getInstance()->setIsOptionChecked(MenuOption::DisableCrashLogger, !value); }; auto setter = [](bool value) { Menu::getInstance()->setIsOptionChecked(MenuOption::EnableCrashReporting, value); };
preferences->addPreference(new CheckPreference("Privacy", "Send crashes - Overte uses information provided by your " preferences->addPreference(new CheckPreference("Privacy", "Send crashes - Overte uses information provided by your "
"client to improve the product through crash reports. By allowing Overte to collect " "client to improve the product through crash reports. By allowing Overte to collect "
"this information you are helping to improve the product. ", getter, setter)); "this information you are helping to improve the product. ", getter, setter));

View file

@ -34,10 +34,6 @@ void UserActivityLogger::disable(bool disable) {
_disabled.set(disable); _disabled.set(disable);
} }
void UserActivityLogger::crashMonitorDisable(bool disable) {
_crashMonitorDisabled.set(disable);
}
void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCallbackParameters params) { void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCallbackParameters params) {
// qCDebug(networking).nospace() << ">>> UserActivityLogger::logAction(" << action << "," << QJsonDocument(details).toJson(); // qCDebug(networking).nospace() << ">>> UserActivityLogger::logAction(" << action << "," << QJsonDocument(details).toJson();
// This logs what the UserActivityLogger would normally send to centralized servers. // This logs what the UserActivityLogger would normally send to centralized servers.
@ -86,6 +82,15 @@ void UserActivityLogger::requestError(QNetworkReply* errorReply) {
qCDebug(networking) << errorReply->error() << "-" << errorReply->errorString(); qCDebug(networking) << errorReply->error() << "-" << errorReply->errorString();
} }
void UserActivityLogger::setCrashReportingEnabled(bool enabled) {
bool old = _crashReportingEnabled.get();
_crashReportingEnabled.set(enabled);
if (old != enabled) {
emit crashReportingEnabledChanged();
}
}
void UserActivityLogger::launch(QString applicationVersion, bool previousSessionCrashed, int previousSessionRuntime) { void UserActivityLogger::launch(QString applicationVersion, bool previousSessionCrashed, int previousSessionRuntime) {
const QString ACTION_NAME = "launch"; const QString ACTION_NAME = "launch";
QJsonObject actionDetails; QJsonObject actionDetails;

View file

@ -27,40 +27,93 @@ const QString USER_ACTIVITY_URL = "/api/v1/user_activities";
class UserActivityLogger : public QObject { class UserActivityLogger : public QObject {
Q_OBJECT Q_OBJECT
public: public:
static UserActivityLogger& getInstance(); static UserActivityLogger& getInstance();
public slots: public slots:
bool isEnabled() { return !_disabled.get(); } bool isEnabled() { return !_disabled.get(); }
bool isDisabledSettingSet() const { return _disabled.isSet(); } bool isDisabledSettingSet() const { return _disabled.isSet(); }
bool isCrashMonitorEnabled() { return !_crashMonitorDisabled.get(); }
bool isCrashMonitorDisabledSettingSet() const { return _crashMonitorDisabled.isSet(); } /**
* @brief Whether the crash monitor has been successfully started
*
* Reasons for it failing to start include:
*
* * Not having a crash reporter for the platform
* * Crash reporter not being configured with reporting URLs (CMAKE_BACKTRACE_TOKEN and CMAKE_BACKTRACE_URL)
* * Crash reporter is present and configured, but failed to initialize for some reason
*
* @return true Crash reporter is present, configured and working.
* @return false Crash reporter has not been started for one of the above reasons.
*/
bool isCrashMonitorStarted() const { return _crashMonitorStarted; }
/**
* @brief Whether the crash monitor will report crashes if they occur
*
* This setting is independent of isCrashMonitorStarted() -- crash reporting may be enabled but fail to work
* due to the crash reporting component being missing or failing to initialize.
*
* @return true Crashes will be reported to CMAKE_BACKTRACE_URL
* @return false Crashes will not be reported
*/
bool isCrashReportingEnabled() { return _crashReportingEnabled.get(); }
/**
* @brief Marks the crash monitor as started
*
* @warning Only to be used as part of the startup process
*
* @param started
*/
void setCrashMonitorStarted(bool started) { _crashMonitorStarted = started; }
/**
* @brief Set whether we want to submit crash reports to the report server
*
* The report server is configured with CMAKE_BACKTRACE_URL.
* Emits crashReportingEnabledChanged signal.
*
* @param enabled Whether it's enabled.
*/
void setCrashReportingEnabled(bool enabled);
void disable(bool disable); void disable(bool disable);
void crashMonitorDisable(bool disable);
void logAction(QString action, QJsonObject details = QJsonObject(), JSONCallbackParameters params = JSONCallbackParameters()); void logAction(QString action, QJsonObject details = QJsonObject(), JSONCallbackParameters params = JSONCallbackParameters());
void launch(QString applicationVersion, bool previousSessionCrashed, int previousSessionRuntime); void launch(QString applicationVersion, bool previousSessionCrashed, int previousSessionRuntime);
void insufficientGLVersion(const QJsonObject& glData); void insufficientGLVersion(const QJsonObject& glData);
void changedDisplayName(QString displayName); void changedDisplayName(QString displayName);
void changedModel(QString typeOfModel, QString modelURL); void changedModel(QString typeOfModel, QString modelURL);
void changedDomain(QString domainURL); void changedDomain(QString domainURL);
void connectedDevice(QString typeOfDevice, QString deviceName); void connectedDevice(QString typeOfDevice, QString deviceName);
void loadedScript(QString scriptName); void loadedScript(QString scriptName);
void wentTo(AddressManager::LookupTrigger trigger, QString destinationType, QString destinationName); void wentTo(AddressManager::LookupTrigger trigger, QString destinationType, QString destinationName);
signals:
/**
* @brief The crash reporting setting has been changed.
*
* This signal is used by the crash reporter to enable/disable itself.
*
*/
void crashReportingEnabledChanged();
private slots: private slots:
void requestError(QNetworkReply* errorReply); void requestError(QNetworkReply* errorReply);
private: private:
UserActivityLogger(); UserActivityLogger();
Setting::Handle<bool> _disabled { "UserActivityLoggerDisabled", true }; Setting::Handle<bool> _disabled { "UserActivityLoggerDisabled", true };
Setting::Handle<bool> _crashMonitorDisabled { "CrashMonitorDisabled2", true }; Setting::Handle<bool> _crashReportingEnabled { "CrashReportingEnabled", false };
bool _crashMonitorStarted {false};
QElapsedTimer _timer; QElapsedTimer _timer;
}; };