Refactor crashpad initialization

Crashpad handler was initialized quite late since we were waiting for settings. However the settings in crashpad are persistent itself, hence we can start it at the earliest possible time and change the upload settings independently later. The only prerequisite is to have QCoreApplication constructed in order for the application name to be available.
ref T652
This commit is contained in:
Roland Rossgotterer
2019-05-03 15:08:39 +02:00
committed by Klaus Basan
parent 99bcee87aa
commit a7509669f9
18 changed files with 407 additions and 273 deletions

View File

@@ -21,6 +21,7 @@
#include "blackcore/inputmanager.h"
#include "blackmisc/atomicfile.h"
#include "blackmisc/applicationinfo.h"
#include "blackmisc/crashhandler.h"
#include "blackmisc/datacache.h"
#include "blackmisc/dbusserver.h"
#include "blackmisc/directoryutils.h"
@@ -68,16 +69,6 @@
#include <QSysInfo>
#include <cstdlib>
#ifdef BLACK_USE_CRASHPAD
#if defined(Q_OS_WIN) && !defined(NOMINMAX)
#define NOMINMAX
#endif
#include "crashpad/client/crashpad_client.h"
#include "crashpad/client/crash_report_database.h"
#include "crashpad/client/settings.h"
#include "crashpad/client/simulate_crash.h"
#endif
using namespace BlackConfig;
using namespace BlackMisc;
using namespace BlackMisc::Db;
@@ -90,7 +81,6 @@ using namespace BlackCore::Context;
using namespace BlackCore::Vatsim;
using namespace BlackCore::Data;
using namespace BlackCore::Db;
using namespace crashpad;
BlackCore::CApplication *sApp = nullptr; // set by constructor
@@ -382,9 +372,6 @@ namespace BlackCore
// Settings if not already initialized
msgs.push_back(this->initLocalSettings());
if (msgs.isFailure()) { break; }
// we have settings, so enable crash handler.
msgs.push_back(this->initCrashHandler());
}
while (false);
@@ -959,7 +946,7 @@ namespace BlackCore
CLogHandler::instance()->install(); // make sure we have a log handler!
// File logger
m_fileLogger.reset(new CFileLogger(executable(), CDirectoryUtils::logDirectory()));
m_fileLogger.reset(new CFileLogger(this));
m_fileLogger->changeLogPattern(CLogPattern().withSeverityAtOrAbove(CStatusMessage::SeverityDebug));
}
@@ -1636,164 +1623,20 @@ namespace BlackCore
return CUrlList();
}
#ifdef BLACK_USE_CRASHPAD
//! Convert to file path
base::FilePath qstringToFilePath(const QString &str)
{
# ifdef Q_OS_WIN
return base::FilePath(str.toStdWString());
# else
return base::FilePath(str.toStdString());
# endif
}
#endif
BlackMisc::CStatusMessageList CApplication::initCrashHandler()
{
#ifdef BLACK_USE_CRASHPAD
// No crash handling for unit tests
if (this->getApplicationInfo().isUnitTest()) { return CStatusMessage(this).info(u"No crash handler for unit tests"); }
static const QString crashpadHandler(CBuildConfig::isRunningOnWindowsNtPlatform() ? "swift_crashpad_handler.exe" : "swift_crashpad_handler");
static const QString handler = CFileUtils::appendFilePaths(CDirectoryUtils::binDirectory(), crashpadHandler);
// const QString crashpadPath = CDirectoryUtils::crashpadDirectory();
const QString database = CDirectoryUtils::crashpadDatabaseDirectory();
const QString metrics = CDirectoryUtils::crashpadMetricsDirectory();
if (!QFileInfo::exists(handler))
{
return CStatusMessage(this).warning(u"Crashpad handler '%1' not found. Cannot init handler!") << handler;
}
const CUrl serverUrl = this->getGlobalSetup().getCrashReportServerUrl();
std::map<std::string, std::string> annotations;
// Backtrace annotations
annotations["token"] = "b15efd93e290be3cf5d39750cadc092b651327ff0c027b80abd75e0ee50df1da";
annotations["format"] = "minidump";
annotations["version"] = CBuildConfig::getVersionString().toStdString();
annotations["platform"] = CBuildConfig::getPlatformString().toStdString();
annotations["qtversion"] = QT_VERSION_STR;
// add our logfile
const QString logFilePath = m_fileLogger->getLogFilePath(); // file and path
const QString logFileName = m_fileLogger->getLogFileName();
const QString logAttachment = QStringLiteral("--attachment=attachment_%1=%2").arg(logFileName, logFilePath);
std::vector<std::string> arguments;
arguments.push_back(logAttachment.toStdString());
// and the simplified crash info if any
const QString crashInfoFileName("swiftcrashinfo.txt");
const QString crashInfoFilePath(CFileUtils::appendFilePaths(CFileUtils::stripFileFromPath(logFilePath), crashInfoFileName));
m_crashAndLogInfo.setLogPathAndFileName(crashInfoFilePath);
const QString crashAttachment = QStringLiteral("--attachment=attachment_%1=%2").arg(crashInfoFileName, crashInfoFilePath);
arguments.push_back(crashAttachment.toStdString());
// for testing purposes
if (CBuildConfig::isLocalDeveloperDebugBuild())
{
arguments.push_back("--no-rate-limit");
}
QDir().mkpath(database);
m_crashReportDatabase = CrashReportDatabase::Initialize(qstringToFilePath(database));
this->onCrashDumpUploadEnabledChanged(); // settings for crashpad uploads
m_crashpadClient = std::make_unique<CrashpadClient>();
m_crashpadClient->StartHandler(qstringToFilePath(handler),
qstringToFilePath(database),
qstringToFilePath(metrics),
serverUrl.getFullUrl().toStdString(),
annotations,
arguments,
false, true);
this->crashAndLogAppendInfo(u"Init crash info at " % QDateTime::currentDateTimeUtc().toString());
return CStatusMessage(this).info(u"Using crash handler");
#else
return CStatusMessage(this).info(u"Not using crash handler");
#endif
}
void CApplication::onCrashDumpUploadEnabledChanged()
{
#ifdef BLACK_USE_CRASHPAD
const bool enabled = CBuildConfig::isReleaseBuild() && m_crashDumpSettings.getThreadLocal().isEnabled();
this->enableCrashDumpUpload(enabled);
#endif
}
void CApplication::triggerCrashInfoWrite()
{
m_crashAndLogInfo.triggerWritingFile();
}
void CApplication::setCrashInfo(const CCrashInfo &info)
{
m_crashAndLogInfo = info;
m_dsCrashAndLogInfo.inputSignal();
}
void CApplication::crashAndLogInfoUserName(const QString &name)
{
m_crashAndLogInfo.setUserName(name);
m_dsCrashAndLogInfo.inputSignal();
}
void CApplication::crashAndLogInfoSimulator(const QString &simulator)
{
m_crashAndLogInfo.setSimulatorString(simulator);
m_dsCrashAndLogInfo.inputSignal();
}
void CApplication::crashAndLogInfoFlightNetwork(const QString &flightNetwork)
{
m_crashAndLogInfo.setFlightNetworkString(flightNetwork);
m_dsCrashAndLogInfo.inputSignal();
}
void CApplication::crashAndLogAppendInfo(const QString &info)
{
m_crashAndLogInfo.appendInfo(info);
m_dsCrashAndLogInfo.inputSignal();
}
void CApplication::simulateCrash()
{
#ifdef BLACK_USE_CRASHPAD
CLogMessage(this).info(u"Simulated crash dump!");
m_crashAndLogInfo.appendInfo("Simulated crash dump!");
m_crashAndLogInfo.writeToFile();
CRASHPAD_SIMULATE_CRASH();
// real crash
// raise(SIGSEGV); #include <signal.h>
#else
CLogMessage(this).warning(u"This compiler or platform does not support crashpad. Cannot simulate crash dump!");
#endif
CCrashHandler::instance()->simulateCrash();
}
void CApplication::enableCrashDumpUpload(bool enable)
{
#ifdef BLACK_USE_CRASHPAD
if (!m_crashReportDatabase) { return; }
crashpad::Settings *settings = m_crashReportDatabase->GetSettings();
settings->SetUploadsEnabled(enable);
#else
Q_UNUSED(enable);
#endif
}
bool CApplication::isCrashDumpUploadEnabled() const
{
#ifdef BLACK_USE_CRASHPAD
if (!m_crashReportDatabase) { return false; }
crashpad::Settings *settings = m_crashReportDatabase->GetSettings();
bool enabled = false;
bool ok = settings->GetUploadsEnabled(&enabled);
return ok && enabled;
#else
return false;
#endif
CCrashHandler::instance()->setUploadsEnabled(enable);
}
bool CApplication::isSupportingCrashpad() const

View File

@@ -43,10 +43,6 @@
#include <atomic>
#include <functional>
#if !defined(Q_CC_MINGW)
#define BLACK_USE_CRASHPAD
#endif
class QHttpMultiPart;
class QNetworkReply;
class QNetworkRequest;
@@ -57,12 +53,6 @@ namespace BlackMisc
class CLogCategoryList;
}
namespace crashpad
{
class CrashpadClient;
class CrashReportDatabase;
}
namespace BlackCore
{
class CCoreFacade;
@@ -303,26 +293,6 @@ namespace BlackCore
virtual QString cmdLineArgumentsAsString(bool withExecutable = true);
//! @}
// ----------------------- Crash info ---------------------------------
//! Extra annotation for crash to easier identify annotation
void setCrashInfo(const BlackMisc::CCrashInfo &info);
//! User name for crash info
void crashAndLogInfoUserName(const QString &name);
//! Simulator string
void crashAndLogInfoSimulator(const QString &simulator);
//! Flight network
void crashAndLogInfoFlightNetwork(const QString &flightNetwork);
//! Append crash info
void crashAndLogAppendInfo(const QString &info);
//! Get the crash info
const BlackMisc::CCrashInfo &getCrashInfo() const { return m_crashAndLogInfo; }
//! Simulate a crash
//! \private only for testing purposes
void simulateCrash();
@@ -331,9 +301,6 @@ namespace BlackCore
//! \remark only change for testing
void enableCrashDumpUpload(bool enable);
//! Is crash dump upload enabled
bool isCrashDumpUploadEnabled() const;
//! Has crashpad support?
bool isSupportingCrashpad() const;
@@ -727,22 +694,10 @@ namespace BlackCore
bool m_localSettingsLoaded = false; //!< local settings loaded?
// -------------- crashpad -----------------
//! Init the crash handler
BlackMisc::CStatusMessageList initCrashHandler();
BlackMisc::CSettingReadOnly<Application::TCrashDumpSettings> m_crashDumpSettings { this, &CApplication::onCrashDumpUploadEnabledChanged };
//! Upload settings changed
void onCrashDumpUploadEnabledChanged();
#ifdef BLACK_USE_CRASHPAD
std::unique_ptr<crashpad::CrashpadClient> m_crashpadClient;
std::unique_ptr<crashpad::CrashReportDatabase> m_crashReportDatabase;
BlackMisc::CSettingReadOnly<Application::TCrashDumpSettings> m_crashDumpSettings { this, &CApplication::onCrashDumpUploadEnabledChanged };
#endif
// crash info
void triggerCrashInfoWrite();
BlackMisc::CCrashInfo m_crashAndLogInfo; //!< info representing details
BlackMisc::CDigestSignal m_dsCrashAndLogInfo { this, &CApplication::triggerCrashInfoWrite, 10000, 5 };
};
} // namespace

View File

@@ -20,9 +20,6 @@ INCLUDEPATH += pch
DEFINES += LOG_IN_FILE BUILD_BLACKCORE_LIB
INCLUDEPATH *= $$EXTERNALSROOT/common/include/crashpad
INCLUDEPATH *= $$EXTERNALSROOT/common/include/crashpad/mini_chromium
HEADERS += *.h
HEADERS += $$PWD/application/*.h
HEADERS += $$PWD/audio/*.h
@@ -41,13 +38,6 @@ LIBS *= -lvatlib
DESTDIR = $$DestRoot/lib
DLLDESTDIR = $$DestRoot/bin
msvc {
CONFIG(debug, debug|release): LIBS *= -lclientd -lutild -lbased -lRpcrt4 -lAdvapi32
CONFIG(release, debug|release): LIBS *= -lclient -lutil -lbase -lRpcrt4 -lAdvapi32
}
macx: LIBS *= -lclient -lutil -lbase -lbsm -framework Security
unix:!macx: LIBS *= -lclient -lutil -lbase
OTHER_FILES += readme.txt *.xml
win32 {

View File

@@ -14,6 +14,7 @@
#include "blackmisc/network/server.h"
#include "blackmisc/network/user.h"
#include "blackmisc/stringutils.h"
#include "blackmisc/crashhandler.h"
#include <QVersionNumber>
#include <QJsonObject>
@@ -165,7 +166,7 @@ namespace BlackCore
if (CBuildConfig::isLocalDeveloperDebugBuild()) { pingUrl.appendQuery("dev", "true"); }
if (sApp)
{
const CCrashInfo ci = sApp->getCrashInfo();
const CCrashInfo ci = CCrashHandler::instance()->getCrashInfo();
pingUrl.appendQuery("application", sApp->getApplicationNameAndVersion());
if (!ci.getSimulatorString().isEmpty()) { pingUrl.appendQuery("fs", ci.getSimulatorString()); }
if (!ci.getFlightNetworkString().isEmpty()) { pingUrl.appendQuery("network", ci.getFlightNetworkString()); }

View File

@@ -12,6 +12,7 @@
#include "blackcore/application.h"
#include "blackmisc/simulation/data/modelcaches.h"
#include "blackmisc/math/mathutils.h"
#include "blackmisc/crashhandler.h"
#include "blackmisc/directoryutils.h"
#include "blackmisc/threadutils.h"
#include "blackmisc/logmessage.h"
@@ -153,7 +154,7 @@ namespace BlackCore
void ISimulator::reloadWeatherSettings()
{
// log crash info about weather
if (sApp && !sApp->isShuttingDown()) { sApp->crashAndLogAppendInfo(u"Simulator weather: " % boolToYesNo(m_isWeatherActivated)); }
if (sApp && !sApp->isShuttingDown()) { CCrashHandler::instance()->crashAndLogAppendInfo(u"Simulator weather: " % boolToYesNo(m_isWeatherActivated)); }
if (!m_isWeatherActivated) { return; }
const CWeatherScenario selectedWeatherScenario = m_weatherScenarioSettings.get();
if (!CWeatherScenario::isRealWeatherScenario(selectedWeatherScenario))
@@ -163,7 +164,7 @@ namespace BlackCore
}
// log crash info about weather
if (sApp && !sApp->isShuttingDown()) { sApp->crashAndLogAppendInfo(selectedWeatherScenario.toQString(true)); }
if (sApp && !sApp->isShuttingDown()) { CCrashHandler::instance()->crashAndLogAppendInfo(selectedWeatherScenario.toQString(true)); }
}
void ISimulator::clearAllRemoteAircraftData()
@@ -872,7 +873,7 @@ namespace BlackCore
const bool r = setup.isRenderingRestricted();
const bool e = setup.isRenderingEnabled();
if (sApp && !sApp->isShuttingDown()) { sApp->crashAndLogAppendInfo(u"Rendering setup: " % setup.toQString(true)); }
if (sApp && !sApp->isShuttingDown()) { CCrashHandler::instance()->crashAndLogAppendInfo(u"Rendering setup: " % setup.toQString(true)); }
emit this->renderRestrictionsChanged(r, e, setup.getMaxRenderedAircraft(), setup.getMaxRenderedDistance());
return true;
}

View File

@@ -18,6 +18,7 @@
#include "blackmisc/logmessage.h"
#include "blackmisc/statusmessage.h"
#include "blackmisc/verify.h"
#include "blackmisc/crashhandler.h"
#include "blackconfig/buildconfig.h"
#include <QLabel>
@@ -164,8 +165,8 @@ namespace BlackGui
}
// crashpad info
sGui->crashAndLogInfoUserName(user.getRealNameAndId());
sGui->crashAndLogAppendInfo(QStringLiteral("Login as user %1 %2").arg(user.getRealNameAndId(), user.getRolesAsString()));
CCrashHandler::instance()->crashAndLogInfoUserName(user.getRealNameAndId());
CCrashHandler::instance()->crashAndLogAppendInfo(QStringLiteral("Login as user %1 %2").arg(user.getRealNameAndId(), user.getRolesAsString()));
}
else
{

View File

@@ -25,6 +25,7 @@
#include "blackmisc/math/mathutils.h"
#include "blackmisc/logmessage.h"
#include "blackmisc/statusmessage.h"
#include "blackmisc/crashhandler.h"
#include "blackconfig/buildconfig.h"
#include "ui_internalscomponent.h"
@@ -93,7 +94,7 @@ namespace BlackGui
if (sGui && sGui->isSupportingCrashpad())
{
ui->cb_CrashDumpUpload->setChecked(sGui->isCrashDumpUploadEnabled());
ui->cb_CrashDumpUpload->setChecked(CCrashHandler::instance()->isCrashDumpUploadEnabled());
connect(ui->pb_SimulateCrash, &QPushButton::released, this, &CInternalsComponent::simulateCrash);
connect(ui->cb_CrashDumpUpload, &QCheckBox::toggled, this, &CInternalsComponent::onCrashDumpUploadToggled);
}
@@ -348,7 +349,7 @@ namespace BlackGui
{
if (sGui && sGui->isSupportingCrashpad())
{
const bool current = sGui->isCrashDumpUploadEnabled();
const bool current = CCrashHandler::instance()->isCrashDumpUploadEnabled();
if (current == checked) { return; }
sGui->enableCrashDumpUpload(checked);
}

View File

@@ -35,6 +35,7 @@
#include "blackmisc/simulation/aircraftmodel.h"
#include "blackmisc/simulation/simulatedaircraft.h"
#include "blackmisc/statusmessage.h"
#include "blackmisc/crashhandler.h"
#include "blackconfig/buildconfig.h"
#include <QDialogButtonBox>
@@ -324,9 +325,9 @@ namespace BlackGui
{
Q_ASSERT_X(currentServer.isValidForLogin(), Q_FUNC_INFO, "invalid server");
sGui->setExtraWindowTitle(QStringLiteral("[%1]").arg(ownAircraft.getCallsignAsString()));
sGui->crashAndLogInfoUserName(currentServer.getUser().getRealNameAndId());
sGui->crashAndLogInfoFlightNetwork(currentServer.getEcosystem().toQString(true));
sGui->crashAndLogAppendInfo(currentServer.getServerSessionId(false));
CCrashHandler::instance()->crashAndLogInfoUserName(currentServer.getUser().getRealNameAndId());
CCrashHandler::instance()->crashAndLogInfoFlightNetwork(currentServer.getEcosystem().toQString(true));
CCrashHandler::instance()->crashAndLogAppendInfo(currentServer.getServerSessionId(false));
m_networkSetup.setLastServer(currentServer);
m_lastAircraftModel.set(ownAircraft.getModel());
ui->le_LoginCallsign->setText(ownAircraft.getCallsignAsString());
@@ -550,7 +551,7 @@ namespace BlackGui
const CSimulatorInfo sim = sGui->getIContextSimulator()->getSimulatorPluginInfo().getSimulator();
const CSimulatorInternals simulatorInternals = sGui->getIContextSimulator()->getSimulatorInternals();
const QString simStr = sim.toQString() + QStringLiteral(" ") + simulatorInternals.getSimulatorVersion();
sGui->crashAndLogInfoSimulator(simStr);
CCrashHandler::instance()->crashAndLogInfoSimulator(simStr);
}
else
{

View File

@@ -0,0 +1,18 @@
/* Copyright (C) 2019
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated,
* or distributed except according to the terms contained in the LICENSE file.
*/
#include "appstarttime.h"
namespace BlackMisc
{
const QDateTime &getApplicationStartTimeUtc()
{
static const QDateTime gApplicationStartTimeUtc = QDateTime::currentDateTimeUtc();
return gApplicationStartTimeUtc;
}
}

View File

@@ -0,0 +1,24 @@
/* Copyright (C) 2019
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated,
* or distributed except according to the terms contained in the LICENSE file.
*/
//! \file
#ifndef BLACKMISC_APPSTARTTIME_H
#define BLACKMISC_APPSTARTTIME_H
#include "blackmisc/blackmiscexport.h"
#include <QDateTime>
namespace BlackMisc
{
//! Get the application start time in UTC.
BLACKMISC_EXPORT const QDateTime &getApplicationStartTimeUtc();
}
#endif

View File

@@ -70,6 +70,10 @@ SOURCES += *.cpp \
$$PWD/test/*.cpp \
$$PWD/weather/*.cpp
INCLUDEPATH *= $$EXTERNALSROOT/common/include/crashpad
INCLUDEPATH *= $$EXTERNALSROOT/common/include/crashpad/mini_chromium
win32 {
LIBS *= -lShell32 -lDbghelp -lversion
# Remove the one below once the Reg functions are removed again from CIdentifier
@@ -79,6 +83,13 @@ win32-g++ {
LIBS *= -lpsapi
}
msvc {
CONFIG(debug, debug|release): LIBS *= -lclientd -lutild -lbased -lRpcrt4 -lAdvapi32
CONFIG(release, debug|release): LIBS *= -lclient -lutil -lbase -lRpcrt4 -lAdvapi32
}
macx: LIBS += -lclient -lutil -lbase -lbsm -framework Security -framework CoreFoundation -framework ApplicationServices -framework Foundation
unix:!macx: LIBS *= -lclient -lutil -lbase
DESTDIR = $$DestRoot/lib
DLLDESTDIR = $$DestRoot/bin

View File

@@ -0,0 +1,189 @@
/* Copyright (C) 2019
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated,
* or distributed except according to the terms contained in the LICENSE file.
*/
#include "crashhandler.h"
#include "blackconfig/buildconfig.h"
#include "blackmisc/appstarttime.h"
#include "blackmisc/directoryutils.h"
#include "blackmisc/logmessage.h"
#include "blackmisc/filelogger.h"
#include <QCoreApplication>
#include <QFileInfo>
#include <QStringBuilder>
#ifdef BLACK_USE_CRASHPAD
#if defined(Q_OS_WIN) && !defined(NOMINMAX)
#define NOMINMAX
#endif
#include "crashpad/client/crashpad_client.h"
#include "crashpad/client/crash_report_database.h"
#include "crashpad/client/settings.h"
#include "crashpad/client/simulate_crash.h"
#endif
using namespace BlackConfig;
using namespace BlackMisc;
using namespace crashpad;
namespace BlackMisc
{
CCrashHandler *CCrashHandler::instance()
{
static CCrashHandler crashHandler;
return &crashHandler;
}
CCrashHandler::~CCrashHandler()
{ }
#ifdef BLACK_USE_CRASHPAD
//! Convert to file path
base::FilePath qstringToFilePath(const QString &str)
{
# ifdef Q_OS_WIN
return base::FilePath(str.toStdWString());
# else
return base::FilePath(str.toStdString());
# endif
}
#endif
void CCrashHandler::init()
{
#ifdef BLACK_USE_CRASHPAD
static const QString crashpadHandler(CBuildConfig::isRunningOnWindowsNtPlatform() ? "swift_crashpad_handler.exe" : "swift_crashpad_handler");
static const QString handler = CFileUtils::appendFilePaths(CDirectoryUtils::binDirectory(), crashpadHandler);
const QString database = CDirectoryUtils::crashpadDatabaseDirectory();
const QString metrics = CDirectoryUtils::crashpadMetricsDirectory();
if (!QFileInfo::exists(handler)) { return; }
const std::string serverUrl("http://swift-project.sp.backtrace.io:6097/");
std::map<std::string, std::string> annotations;
// Backtrace annotations
annotations["token"] = "b15efd93e290be3cf5d39750cadc092b651327ff0c027b80abd75e0ee50df1da";
annotations["format"] = "minidump";
annotations["version"] = CBuildConfig::getVersionString().toStdString();
annotations["platform"] = CBuildConfig::getPlatformString().toStdString();
annotations["qtversion"] = QT_VERSION_STR;
// add our logfile
const QString logAttachment = QStringLiteral("--attachment=attachment_%1=%2").arg(CFileLogger::getLogFileName(), CFileLogger::getLogFilePath());
std::vector<std::string> arguments;
arguments.push_back(logAttachment.toStdString());
// and the simplified crash info if any
const QString crashInfoFileName("swiftcrashinfo.txt");
const QString crashInfoFilePath(CFileUtils::appendFilePaths(CFileUtils::stripFileFromPath(CFileLogger::getLogFilePath()), crashInfoFileName));
m_crashAndLogInfo.setLogPathAndFileName(crashInfoFilePath);
const QString crashAttachment = QStringLiteral("--attachment=attachment_%1=%2").arg(crashInfoFileName, crashInfoFilePath);
arguments.push_back(crashAttachment.toStdString());
// for testing purposes
if (CBuildConfig::isLocalDeveloperDebugBuild())
{
arguments.push_back("--no-rate-limit");
}
QDir().mkpath(database);
m_crashReportDatabase = CrashReportDatabase::Initialize(qstringToFilePath(database));
m_crashpadClient = std::make_unique<CrashpadClient>();
m_crashpadClient->StartHandler(qstringToFilePath(handler),
qstringToFilePath(database),
qstringToFilePath(metrics),
serverUrl,
annotations,
arguments,
false, true);
this->crashAndLogAppendInfo(u"Init crash info at " % QDateTime::currentDateTimeUtc().toString());
#endif
}
void CCrashHandler::setUploadsEnabled(bool enable)
{
#ifdef BLACK_USE_CRASHPAD
if (!m_crashReportDatabase) { return; }
crashpad::Settings *settings = m_crashReportDatabase->GetSettings();
settings->SetUploadsEnabled(enable);
#else
Q_UNUSED(enable);
#endif
}
bool CCrashHandler::isCrashDumpUploadEnabled() const
{
#ifdef BLACK_USE_CRASHPAD
if (!m_crashReportDatabase) { return false; }
crashpad::Settings *settings = m_crashReportDatabase->GetSettings();
bool enabled = false;
bool ok = settings->GetUploadsEnabled(&enabled);
return ok && enabled;
#else
return false;
#endif
}
void CCrashHandler::triggerCrashInfoWrite()
{
m_crashAndLogInfo.triggerWritingFile();
}
void CCrashHandler::setCrashInfo(const CCrashInfo &info)
{
m_crashAndLogInfo = info;
m_dsCrashAndLogInfo.inputSignal();
}
void CCrashHandler::crashAndLogInfoUserName(const QString &name)
{
m_crashAndLogInfo.setUserName(name);
m_dsCrashAndLogInfo.inputSignal();
}
void CCrashHandler::crashAndLogInfoSimulator(const QString &simulator)
{
m_crashAndLogInfo.setSimulatorString(simulator);
m_dsCrashAndLogInfo.inputSignal();
}
void CCrashHandler::crashAndLogInfoFlightNetwork(const QString &flightNetwork)
{
m_crashAndLogInfo.setFlightNetworkString(flightNetwork);
m_dsCrashAndLogInfo.inputSignal();
}
void CCrashHandler::crashAndLogAppendInfo(const QString &info)
{
m_crashAndLogInfo.appendInfo(info);
m_dsCrashAndLogInfo.inputSignal();
}
void CCrashHandler::simulateCrash()
{
#ifdef BLACK_USE_CRASHPAD
CLogMessage(this).info(u"Simulated crash dump!");
m_crashAndLogInfo.appendInfo("Simulated crash dump!");
m_crashAndLogInfo.writeToFile();
CRASHPAD_SIMULATE_CRASH();
// real crash
// raise(SIGSEGV); #include <signal.h>
#else
CLogMessage(this).warning(u"This compiler or platform does not support crashpad. Cannot simulate crash dump!");
#endif
}
CCrashHandler::CCrashHandler(QObject *parent) :
QObject(parent)
{ }
}

View File

@@ -0,0 +1,92 @@
/* Copyright (C) 2019
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated,
* or distributed except according to the terms contained in the LICENSE file.
*/
//! \file
#ifndef BLACKMISC_CRASHHANDLER_H
#define BLACKMISC_CRASHHANDLER_H
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/crashinfo.h"
#include "blackmisc/digestsignal.h"
#include <memory>
#if !defined(Q_CC_MINGW)
#define BLACK_USE_CRASHPAD
#endif
namespace crashpad
{
class CrashpadClient;
class CrashReportDatabase;
}
namespace BlackMisc
{
//! Crash handler
class BLACKMISC_EXPORT CCrashHandler : public QObject
{
Q_OBJECT
public:
//! Get singleton instance
static CCrashHandler *instance();
//! Destructor
virtual ~CCrashHandler();
//! Initialize and start crashpad handler process
void init();
//! Enable/disable automatic uploading
void setUploadsEnabled(bool enable);
//! Is automatic dump uploading enabled?
bool isCrashDumpUploadEnabled() const;
// ----------------------- Crash info ---------------------------------
//! Extra annotation for crash to easier identify annotation
void setCrashInfo(const BlackMisc::CCrashInfo &info);
//! Set user name for crash info
void crashAndLogInfoUserName(const QString &name);
//! Set simulator string in crash info
void crashAndLogInfoSimulator(const QString &simulator);
//! Set flight network in crash info
void crashAndLogInfoFlightNetwork(const QString &flightNetwork);
//! Append crash info
void crashAndLogAppendInfo(const QString &info);
//! Get crash info
const BlackMisc::CCrashInfo &getCrashInfo() const { return m_crashAndLogInfo; }
//! Simulate a crash
void simulateCrash();
private:
CCrashHandler(QObject *parent = nullptr);
// crash info
void triggerCrashInfoWrite();
BlackMisc::CCrashInfo m_crashAndLogInfo; //!< info representing details
BlackMisc::CDigestSignal m_dsCrashAndLogInfo { this, &CCrashHandler::triggerCrashInfoWrite, 10000, 5 };
#ifdef BLACK_USE_CRASHPAD
std::unique_ptr<crashpad::CrashpadClient> m_crashpadClient;
std::unique_ptr<crashpad::CrashReportDatabase> m_crashReportDatabase;
#endif
};
}
#endif

View File

@@ -7,8 +7,10 @@
*/
#include "blackconfig/buildconfig.h"
#include "blackmisc/appstarttime.h"
#include "blackmisc/filelogger.h"
#include "blackmisc/loghandler.h"
#include "blackmisc/directoryutils.h"
#include <QCoreApplication>
#include <QDateTime>
@@ -26,22 +28,33 @@ using namespace BlackConfig;
namespace BlackMisc
{
CFileLogger::CFileLogger(QObject *parent) :
CFileLogger(QCoreApplication::applicationName(), QString(), parent)
//! Get application name
QString applicationName()
{
// void
static const QString applicationName = QFileInfo(QCoreApplication::applicationFilePath()).completeBaseName();
return applicationName;
}
CFileLogger::CFileLogger(const QString &applicationName, const QString &logPath, QObject *parent) :
QObject(parent),
m_logFile(this),
m_applicationName(applicationName),
m_logPath(logPath)
//! Get log file name
QString logFileName()
{
if (!m_logPath.isEmpty()) { QDir::root().mkpath(m_logPath); }
static const QString fileName = applicationName() %
QLatin1String("_") %
getApplicationStartTimeUtc().toString(QStringLiteral("yyMMddhhmmss")) %
QLatin1String("_") %
QString::number(QCoreApplication::applicationPid()) %
QLatin1String(".log");
return fileName;
}
CFileLogger::CFileLogger(QObject *parent) :
QObject(parent),
m_logFile(this)
{
Q_ASSERT(! applicationName().isEmpty());
QDir::root().mkpath(CDirectoryUtils::logDirectory());
removeOldLogFiles();
if (!m_logPath.isEmpty() && !m_logPath.endsWith('/')) { m_logPath += '/'; }
m_logFile.setFileName(getFullFileName());
m_logFile.setFileName(getLogFilePath());
m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
m_stream.setDevice(&m_logFile);
m_stream.setCodec("UTF-8");
@@ -66,6 +79,11 @@ namespace BlackMisc
}
}
QString CFileLogger::getLogFileName()
{
return logFileName();
}
void CFileLogger::ps_writeStatusMessageToFile(const BlackMisc::CStatusMessage &statusMessage)
{
if (statusMessage.isEmpty()) { return; }
@@ -85,26 +103,17 @@ namespace BlackMisc
writeContentToFile(finalContent);
}
QString CFileLogger::getFullFileName()
QString CFileLogger::getLogFilePath()
{
QString filePath;
Q_ASSERT(!m_applicationName.isEmpty());
if (!m_logPath.isEmpty()) filePath += m_logPath;
m_fileName += m_applicationName;
m_fileName += QLatin1String("_");
m_fileName += QDateTime::currentDateTime().toString(QStringLiteral("yyMMddhhmmss"));
m_fileName += QLatin1String("_");
m_fileName += QString::number(QCoreApplication::applicationPid());
m_fileName += QLatin1String(".log");
return filePath + m_fileName;
QString filePath = CDirectoryUtils::logDirectory() % '/' % logFileName();
return filePath;
}
void CFileLogger::removeOldLogFiles()
{
QString nameFilter(m_applicationName);
QString nameFilter(applicationName());
nameFilter += QLatin1String("*.log");
QDir dir(m_logPath, nameFilter, QDir::Name, QDir::Files);
QDir dir(CDirectoryUtils::logDirectory(), nameFilter, QDir::Name, QDir::Files);
QDateTime now = QDateTime::currentDateTime();
for (const auto &logFileInfo : dir.entryInfoList())
@@ -118,7 +127,7 @@ namespace BlackMisc
void CFileLogger::writeHeaderToFile()
{
m_stream << "This is " << m_applicationName;
m_stream << "This is " << applicationName();
m_stream << " version " << CBuildConfig::getVersionString();
m_stream << " running on " << QSysInfo::prettyProductName();
m_stream << " " << QSysInfo::currentCpuArchitecture() << endl;

View File

@@ -32,16 +32,6 @@ namespace BlackMisc
//! Filename defaults to QCoreApplication::applicationName() and path to "."
CFileLogger(QObject *parent = nullptr);
/*!
* Constructor
* \param applicationName Use the applications name without any extension.
* A timestamp and extension will be added automatically.
* \param logPath Path the log files is written to. If you leave this empty, the
* file will be written in the working directory of the binary.
* \param parent QObject parent
*/
CFileLogger(const QString &applicationName, const QString &logPath, QObject *parent = nullptr);
//! Destructor.
virtual ~CFileLogger();
@@ -51,20 +41,18 @@ namespace BlackMisc
//! Close file
void close();
//! Get the current log file path
QString getLogFilePath() const { return m_logFile.fileName(); }
//! Get the log file name
static QString getLogFileName();
//! Get the current log file name
QString getLogFileName() const { return m_fileName; }
//! Get the log file path (including its name)
static QString getLogFilePath();
private slots:
//! Write single status message to file
void ps_writeStatusMessageToFile(const BlackMisc::CStatusMessage &statusMessage);
private:
QString getFullFileName();
void removeOldLogFiles();
void writeHeaderToFile();
void writeContentToFile(const QString &content);
@@ -72,8 +60,6 @@ namespace BlackMisc
QFile m_logFile;
QString m_fileName;
QTextStream m_stream;
QString m_applicationName;
QString m_logPath; //!< Empty by default. Hence the working directory "." is used
QString m_previousCategories;
};
}

View File

@@ -10,6 +10,8 @@
#include "blackgui/guiapplication.h"
#include "blackmisc/icons.h"
#include "blackmisc/directoryutils.h"
#include "blackmisc/crashhandler.h"
#include "blackmisc/appstarttime.h"
#include "swiftcore.h"
#include <stdlib.h>
@@ -28,6 +30,8 @@ int main(int argc, char *argv[])
CGuiApplication::highDpiScreenSupport(CGuiApplication::parseScaleFactor(argc, argv));
QApplication qa(argc, argv);
Q_UNUSED(qa); // init of qa is required, but qa not used
CCrashHandler::instance()->init();
CGuiApplication a(CApplicationInfo::swiftCore(), CApplicationInfo::PilotClientCore, CIcons::swiftCore24());
a.addWindowStateOption();
a.addDBusAddressOption();

View File

@@ -10,6 +10,8 @@
#include "blackgui/guiapplication.h"
#include "blackmisc/directoryutils.h"
#include "blackmisc/icons.h"
#include "blackmisc/crashhandler.h"
#include "blackmisc/appstarttime.h"
#include "swiftdata.h"
#include <stdlib.h>
@@ -26,6 +28,8 @@ int main(int argc, char *argv[])
CGuiApplication::highDpiScreenSupport(CGuiApplication::parseScaleFactor(argc, argv));
QApplication qa(argc, argv);
Q_UNUSED(qa);
CCrashHandler::instance()->init();
CGuiApplication a(CApplicationInfo::swiftMappingTool(), CApplicationInfo::MappingTool, CIcons::swiftDatabase48());
a.setSignalStartupAutomatically(false); // application will signal startup on its own
a.splashScreen(CIcons::swiftDatabase256());

View File

@@ -9,6 +9,8 @@
#include "blackgui/enableforframelesswindow.h"
#include "blackgui/guiapplication.h"
#include "blackmisc/directoryutils.h"
#include "blackmisc/crashhandler.h"
#include "blackmisc/appstarttime.h"
#include "swiftguistd.h"
#include "swiftguistdapplication.h"
@@ -25,6 +27,8 @@ int main(int argc, char *argv[])
CGuiApplication::highDpiScreenSupport(CGuiApplication::parseScaleFactor(argc, argv));
QApplication qa(argc, argv);
Q_UNUSED(qa); // application init needed
CCrashHandler::instance()->init();
CSwiftGuiStdApplication a; // application with contexts
a.setSignalStartupAutomatically(false); // application will signal startup on its own
a.splashScreen(CIcons::swift256());