forked from qt-creator/qt-creator
Support building with Sentry Native SDK
As a replacement for Crashpad directly. Enables us to report the version number in a way that is useful in Sentry. This might also open the option for informing the user with the option to not send the report (with sentry_on_crash_handler, which on macOS is only supported with Breakpad). To use Sentry Native SDK set SENTRY_DSN to the API entry point, SENTRY_PROJECT to the project in Sentry, and point the CMAKE_PREFIX_PATH to the Sentry Native SDK installation path. Both the Crashpad and the Breakpad backends are supported. Dependencies (sentry dynamic library and crashpad_handler if used) are installed with the `Dependencies` install component. Change-Id: I3eb96cbee3ed3910b3f0dfe4c127bd1346b96fc6 Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io> Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -136,6 +136,32 @@ if(CRASHPAD_BACKEND_URL AND (WIN32 OR APPLE)) # Linux is not supported for now
|
||||
endif()
|
||||
add_feature_info("Build with Crashpad" ${BUILD_WITH_CRASHPAD} "")
|
||||
|
||||
set(SENTRY_DSN "$ENV{QTC_SENTRY_DSN}" CACHE STRING "Data Source Name to use for sending Sentry events.")
|
||||
set(SENTRY_PROJECT "" CACHE STRING "Project ID to use for sending Sentry events.")
|
||||
set(BUILD_WITH_SENTRY OFF)
|
||||
if(SENTRY_DSN AND SENTRY_PROJECT)
|
||||
find_package(sentry QUIET)
|
||||
if(TARGET sentry::sentry)
|
||||
set(BUILD_WITH_SENTRY ON)
|
||||
get_target_property(__sentry_configs sentry::sentry IMPORTED_CONFIGURATIONS)
|
||||
get_target_property(__sentry_lib sentry::sentry IMPORTED_LOCATION_${__sentry_configs})
|
||||
install(FILES ${__sentry_lib}
|
||||
DESTINATION "${IDE_LIBRARY_ARCHIVE_PATH}"
|
||||
COMPONENT Dependencies
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
if (TARGET sentry_crashpad::crashpad_handler)
|
||||
get_target_property(SENTRY_CRASHPAD_PATH sentry_crashpad::crashpad_handler IMPORTED_LOCATION_${__sentry_configs})
|
||||
install(PROGRAMS ${SENTRY_CRASHPAD_PATH}
|
||||
DESTINATION "${IDE_LIBEXEC_PATH}"
|
||||
COMPONENT Dependencies
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
add_feature_info("Build with Sentry" ${BUILD_WITH_SENTRY} "")
|
||||
|
||||
function (set_if_target var target)
|
||||
if (TARGET "${target}")
|
||||
set(_result ON)
|
||||
|
@@ -157,6 +157,20 @@ if(BUILD_WITH_CRASHPAD)
|
||||
)
|
||||
endif()
|
||||
|
||||
extend_qtc_executable(qtcreator
|
||||
CONDITION BUILD_WITH_SENTRY
|
||||
DEFINES
|
||||
SENTRY_DSN="${SENTRY_DSN}"
|
||||
SENTRY_PROJECT="${SENTRY_PROJECT}"
|
||||
ENABLE_SENTRY
|
||||
DEPENDS sentry::sentry
|
||||
)
|
||||
extend_qtc_executable(qtcreator
|
||||
CONDITION DEFINED SENTRY_CRASHPAD_PATH
|
||||
DEFINES
|
||||
SENTRY_CRASHPAD_PATH="${SENTRY_CRASHPAD_PATH}"
|
||||
)
|
||||
|
||||
if ((NOT WIN32) AND (NOT APPLE))
|
||||
# install logo
|
||||
foreach(size 16 24 32 48 64 128 256 512)
|
||||
|
@@ -54,6 +54,12 @@
|
||||
#include "client/settings.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SENTRY
|
||||
#include <sentry.h>
|
||||
|
||||
Q_LOGGING_CATEGORY(sentryLog, "qtc.sentry", QtWarningMsg)
|
||||
#endif
|
||||
|
||||
using namespace ExtensionSystem;
|
||||
using namespace Utils;
|
||||
|
||||
@@ -496,6 +502,35 @@ void startCrashpad(const AppInfo &appInfo, bool crashReportingEnabled)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SENTRY
|
||||
void configureSentry(const AppInfo &appInfo, bool crashReportingEnabled)
|
||||
{
|
||||
if (!crashReportingEnabled)
|
||||
return;
|
||||
|
||||
sentry_options_t *options = sentry_options_new();
|
||||
sentry_options_set_dsn(options, SENTRY_DSN);
|
||||
#ifdef Q_OS_WIN
|
||||
sentry_options_set_database_pathw(options, appInfo.crashReports.nativePath().toStdWString().c_str());
|
||||
#else
|
||||
sentry_options_set_database_path(options, appInfo.crashReports.nativePath().toUtf8().constData());
|
||||
#endif
|
||||
#ifdef SENTRY_CRASHPAD_PATH
|
||||
if (const FilePath handlerpath = appInfo.libexec / "crashpad_handler"; handlerpath.exists()) {
|
||||
sentry_options_set_handler_path(options, handlerpath.nativePath().toUtf8().constData());
|
||||
} else if (const auto fallback = FilePath::fromString(SENTRY_CRASHPAD_PATH); fallback.exists()) {
|
||||
sentry_options_set_handler_path(options, fallback.nativePath().toUtf8().constData());
|
||||
} else {
|
||||
qCWarning(sentryLog) << "Failed to find crashpad_handler for Sentry crash reports.";
|
||||
}
|
||||
#endif
|
||||
const QString release = QString(SENTRY_PROJECT) + "@" + QCoreApplication::applicationVersion();
|
||||
sentry_options_set_release(options, release.toUtf8().constData());
|
||||
sentry_options_set_debug(options, sentryLog().isDebugEnabled() ? 1 : 0);
|
||||
sentry_init(options);
|
||||
}
|
||||
#endif
|
||||
|
||||
class ShowInGuiHandler
|
||||
{
|
||||
public:
|
||||
@@ -792,10 +827,15 @@ int main(int argc, char **argv)
|
||||
CrashHandlerSetup setupCrashHandler(
|
||||
Core::Constants::IDE_DISPLAY_NAME, CrashHandlerSetup::EnableRestart, info.libexec.path());
|
||||
|
||||
#ifdef ENABLE_CRASHPAD
|
||||
// depends on AppInfo and QApplication being created
|
||||
bool crashReportingEnabled = settings->value("CrashReportingEnabled", false).toBool();
|
||||
const bool crashReportingEnabled = settings->value("CrashReportingEnabled", false).toBool();
|
||||
|
||||
#if defined(ENABLE_CRASHPAD)
|
||||
startCrashpad(info, crashReportingEnabled);
|
||||
#elif defined(ENABLE_SENTRY)
|
||||
configureSentry(info, crashReportingEnabled);
|
||||
#else
|
||||
Q_UNUSED(crashReportingEnabled)
|
||||
#endif
|
||||
|
||||
PluginManager pluginManager;
|
||||
@@ -983,5 +1023,9 @@ int main(int argc, char **argv)
|
||||
QApplication::setEffectEnabled(Qt::UI_AnimateMenu, false);
|
||||
}
|
||||
|
||||
return restarter.restartOrExit(app.exec());
|
||||
const int exitCode = restarter.restartOrExit(app.exec());
|
||||
#ifdef ENABLE_SENTRY
|
||||
sentry_close();
|
||||
#endif
|
||||
return exitCode;
|
||||
}
|
||||
|
@@ -322,8 +322,13 @@ extend_qtc_plugin(Core
|
||||
)
|
||||
|
||||
extend_qtc_plugin(Core
|
||||
CONDITION BUILD_WITH_CRASHPAD
|
||||
DEFINES ENABLE_CRASHPAD
|
||||
CONDITION BUILD_WITH_CRASHPAD OR BUILD_WITH_SENTRY
|
||||
DEFINES ENABLE_CRASHREPORTING
|
||||
)
|
||||
|
||||
extend_qtc_plugin(Core
|
||||
CONDITION BUILD_WITH_CRASHPAD OR (BUILD_WITH_SENTRY AND SENTRY_CRASHPAD_PATH)
|
||||
DEFINES CRASHREPORTING_USES_CRASHPAD
|
||||
)
|
||||
|
||||
set(FONTS_BASE "${QtCreator_SOURCE_DIR}/src/share/3rdparty/studiofonts/")
|
||||
|
@@ -359,8 +359,12 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage)
|
||||
|
||||
Utils::PathChooser::setAboutToShowContextMenuHandler(&addToPathChooserContextMenu);
|
||||
|
||||
#ifdef ENABLE_CRASHPAD
|
||||
connect(ICore::instance(), &ICore::coreOpened, this, &CorePlugin::warnAboutCrashReporing,
|
||||
#ifdef ENABLE_CRASHREPORTING
|
||||
connect(
|
||||
ICore::instance(),
|
||||
&ICore::coreOpened,
|
||||
this,
|
||||
&CorePlugin::warnAboutCrashReporing,
|
||||
Qt::QueuedConnection);
|
||||
#endif
|
||||
|
||||
@@ -542,19 +546,33 @@ void CorePlugin::warnAboutCrashReporing()
|
||||
// static
|
||||
QString CorePlugin::msgCrashpadInformation()
|
||||
{
|
||||
return Tr::tr("%1 uses Google Crashpad for collecting crashes and sending them to Sentry "
|
||||
"for processing. Crashpad may capture arbitrary contents from crashed process’ "
|
||||
#if ENABLE_CRASHREPORTING
|
||||
#if CRASHREPORTING_USES_CRASHPAD
|
||||
const QString backend = "Google Crashpad";
|
||||
const QString url
|
||||
= "https://chromium.googlesource.com/crashpad/crashpad/+/master/doc/overview_design.md";
|
||||
#else
|
||||
const QString backend = "Google Breakpad";
|
||||
const QString url
|
||||
= "https://chromium.googlesource.com/breakpad/breakpad/+/HEAD/docs/client_design.md";
|
||||
#endif
|
||||
//: %1 = application name, %2 crash backend name (Google Crashpad or Google Breakpad)
|
||||
return Tr::tr("%1 uses %2 for collecting crashes and sending them to Sentry "
|
||||
"for processing. %2 may capture arbitrary contents from crashed process’ "
|
||||
"memory, including user sensitive information, URLs, and whatever other content "
|
||||
"users have trusted %1 with. The collected crash reports are however only used "
|
||||
"for the sole purpose of fixing bugs.")
|
||||
.arg(QGuiApplication::applicationDisplayName())
|
||||
+ "<br><br>" + Tr::tr("More information:")
|
||||
+ "<br><a href='https://chromium.googlesource.com/crashpad/crashpad/+/master/doc/"
|
||||
"overview_design.md'>"
|
||||
+ Tr::tr("Crashpad Overview")
|
||||
.arg(QGuiApplication::applicationDisplayName(), backend)
|
||||
+ "<br><br>" + Tr::tr("More information:") + "<br><a href='" + url
|
||||
+ "'>"
|
||||
//: %1 = crash backend name (Google Crashpad or Google Breakpad)
|
||||
+ Tr::tr("%1 Overview").arg(backend)
|
||||
+ "</a>"
|
||||
"<br><a href='https://sentry.io/security/'>"
|
||||
+ Tr::tr("%1 security policy").arg("Sentry.io") + "</a>";
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
ExtensionSystem::IPlugin::ShutdownFlag CorePlugin::aboutToShutdown()
|
||||
|
@@ -12,7 +12,7 @@
|
||||
#include "iversioncontrol.h" // sic!
|
||||
#include "vcsmanager.h"
|
||||
|
||||
#ifdef ENABLE_CRASHPAD
|
||||
#ifdef ENABLE_CRASHREPORTING
|
||||
#include "coreplugin.h"
|
||||
#endif
|
||||
|
||||
@@ -40,7 +40,7 @@ using namespace Layouting;
|
||||
|
||||
namespace Core::Internal {
|
||||
|
||||
#ifdef ENABLE_CRASHPAD
|
||||
#ifdef CRASHREPORTING_USES_CRASHPAD
|
||||
// TODO: move to somewhere in Utils
|
||||
static QString formatSize(qint64 size)
|
||||
{
|
||||
@@ -55,7 +55,7 @@ static QString formatSize(qint64 size)
|
||||
return i == 0 ? QString("%0 %1").arg(outputSize).arg(units[i]) // Bytes
|
||||
: QString("%0 %1").arg(outputSize, 0, 'f', 2).arg(units[i]); // KB, MB, GB, TB
|
||||
}
|
||||
#endif // ENABLE_CRASHPAD
|
||||
#endif // CRASHREPORTING_USES_CRASHPAD
|
||||
|
||||
SystemSettings &systemSettings()
|
||||
{
|
||||
@@ -145,15 +145,17 @@ SystemSettings::SystemSettings()
|
||||
askBeforeExit.setLabelText(Tr::tr("Ask for confirmation before exiting"));
|
||||
askBeforeExit.setLabelPlacement(BoolAspect::LabelPlacement::Compact);
|
||||
|
||||
#ifdef ENABLE_CRASHPAD
|
||||
#ifdef ENABLE_CRASHREPORTING
|
||||
enableCrashReporting.setSettingsKey("CrashReportingEnabled");
|
||||
enableCrashReporting.setLabelPlacement(BoolAspect::LabelPlacement::Compact);
|
||||
enableCrashReporting.setLabelText(Tr::tr("Enable crash reporting"));
|
||||
enableCrashReporting.setToolTip(
|
||||
Tr::tr("Allow crashes to be automatically reported. Collected reports are "
|
||||
"used for the sole purpose of fixing bugs."));
|
||||
|
||||
#endif
|
||||
"<p>"
|
||||
+ Tr::tr("Allow crashes to be automatically reported. Collected reports are "
|
||||
"used for the sole purpose of fixing bugs.")
|
||||
+ "</p><p>"
|
||||
+ Tr::tr("Crash reports are saved in \"%1\".").arg(appInfo().crashReports.toUserOutput()));
|
||||
#endif // ENABLE_CRASHREPORTING
|
||||
readSettings();
|
||||
|
||||
autoSaveInterval.setEnabler(&autoSaveModifiedFiles);
|
||||
@@ -174,7 +176,7 @@ public:
|
||||
, m_terminalOpenArgs(new QLineEdit)
|
||||
, m_terminalExecuteArgs(new QLineEdit)
|
||||
, m_environmentChangesLabel(new Utils::ElidingLabel)
|
||||
#ifdef ENABLE_CRASHPAD
|
||||
#ifdef CRASHREPORTING_USES_CRASHPAD
|
||||
, m_clearCrashReportsButton(new QPushButton(Tr::tr("Clear Local Crash Reports"), this))
|
||||
, m_crashReportsSizeText(new QLabel(this))
|
||||
#endif
|
||||
@@ -199,9 +201,12 @@ public:
|
||||
resetFileBrowserButton->setToolTip(Tr::tr("Reset to default."));
|
||||
auto helpExternalFileBrowserButton = new QToolButton;
|
||||
helpExternalFileBrowserButton->setText(Tr::tr("?"));
|
||||
#ifdef ENABLE_CRASHPAD
|
||||
#ifdef ENABLE_CRASHREPORTING
|
||||
auto helpCrashReportingButton = new QToolButton(this);
|
||||
helpCrashReportingButton->setText(Tr::tr("?"));
|
||||
connect(helpCrashReportingButton, &QAbstractButton::clicked, this, [this] {
|
||||
showHelpDialog(Tr::tr("Crash Reporting"), CorePlugin::msgCrashpadInformation());
|
||||
});
|
||||
#endif
|
||||
auto resetTerminalButton = new QPushButton(Tr::tr("Reset"));
|
||||
resetTerminalButton->setToolTip(Tr::tr("Reset to default.", "Terminal"));
|
||||
@@ -241,13 +246,14 @@ public:
|
||||
grid.addRow({Tr::tr("Maximum number of entries in \"Recent Files\":"),
|
||||
Row{s.maxRecentFiles, st}});
|
||||
grid.addRow({s.askBeforeExit});
|
||||
#ifdef ENABLE_CRASHPAD
|
||||
const QString toolTip = Tr::tr("Crash reports are saved in \"%1\".")
|
||||
.arg(appInfo().crashReports.toUserOutput());
|
||||
m_clearCrashReportsButton->setToolTip(toolTip);
|
||||
m_crashReportsSizeText->setToolTip(toolTip);
|
||||
Row crashDetails
|
||||
= Row{m_clearCrashReportsButton, m_crashReportsSizeText, helpCrashReportingButton, st};
|
||||
#ifdef ENABLE_CRASHREPORTING
|
||||
Row crashDetails;
|
||||
#ifdef CRASHREPORTING_USES_CRASHPAD
|
||||
m_clearCrashReportsButton->setToolTip(s.enableCrashReporting.toolTip());
|
||||
m_crashReportsSizeText->setToolTip(s.enableCrashReporting.toolTip());
|
||||
crashDetails.addItems({m_clearCrashReportsButton, m_crashReportsSizeText});
|
||||
#endif // CRASHREPORTING_USES_CRASHPAD
|
||||
crashDetails.addItem(helpCrashReportingButton);
|
||||
if (qtcEnvironmentVariableIsSet("QTC_SHOW_CRASHBUTTON")) {
|
||||
auto crashButton = new QPushButton("CRASH!!!");
|
||||
connect(crashButton, &QPushButton::clicked, [] {
|
||||
@@ -257,6 +263,7 @@ public:
|
||||
});
|
||||
crashDetails.addItem(crashButton);
|
||||
}
|
||||
crashDetails.addItem(st);
|
||||
grid.addRow({s.enableCrashReporting, crashDetails});
|
||||
|
||||
#endif
|
||||
@@ -283,20 +290,24 @@ public:
|
||||
m_externalFileBrowserEdit->setText(UnixUtils::fileBrowser(ICore::settings()));
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CRASHPAD
|
||||
connect(helpCrashReportingButton, &QAbstractButton::clicked, this, [this] {
|
||||
showHelpDialog(Tr::tr("Crash Reporting"), CorePlugin::msgCrashpadInformation());
|
||||
});
|
||||
#if defined(ENABLE_CRASHREPORTING) && defined(CRASHREPORTING_USES_CRASHPAD)
|
||||
const FilePaths reportsPaths
|
||||
= {ICore::crashReportsPath() / "completed",
|
||||
ICore::crashReportsPath() / "reports",
|
||||
ICore::crashReportsPath() / "attachments",
|
||||
ICore::crashReportsPath() / "pending",
|
||||
ICore::crashReportsPath() / "new"};
|
||||
|
||||
const FilePath reportsPath = ICore::crashReportsPath()
|
||||
/ QLatin1String(
|
||||
HostOsInfo::isMacHost() ? "completed" : "reports");
|
||||
const auto updateClearCrashWidgets = [this, reportsPath] {
|
||||
const auto updateClearCrashWidgets = [this, reportsPaths] {
|
||||
qint64 size = 0;
|
||||
const FilePaths crashFiles = reportsPath.dirEntries(QDir::Files);
|
||||
for (const FilePath &file : crashFiles)
|
||||
size += file.fileSize();
|
||||
m_clearCrashReportsButton->setEnabled(!crashFiles.isEmpty());
|
||||
FilePath::iterateDirectories(
|
||||
reportsPaths,
|
||||
[&size](const FilePath &item) {
|
||||
size += item.fileSize();
|
||||
return IterationPolicy::Continue;
|
||||
},
|
||||
FileFilter({}, QDir::Files, QDirIterator::Subdirectories));
|
||||
m_clearCrashReportsButton->setEnabled(size > 0);
|
||||
m_crashReportsSizeText->setText(formatSize(size));
|
||||
};
|
||||
updateClearCrashWidgets();
|
||||
@@ -304,13 +315,17 @@ public:
|
||||
m_clearCrashReportsButton,
|
||||
&QPushButton::clicked,
|
||||
this,
|
||||
[updateClearCrashWidgets, reportsPath] {
|
||||
const FilePaths &crashFiles = reportsPath.dirEntries(QDir::Files);
|
||||
for (const FilePath &file : crashFiles)
|
||||
file.removeFile();
|
||||
[updateClearCrashWidgets, reportsPaths] {
|
||||
FilePath::iterateDirectories(
|
||||
reportsPaths,
|
||||
[](const FilePath &item) {
|
||||
item.removeRecursively();
|
||||
return IterationPolicy::Continue;
|
||||
},
|
||||
FileFilter({}, QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot));
|
||||
updateClearCrashWidgets();
|
||||
});
|
||||
#endif
|
||||
#endif // ENABLE_CRASHREPORTING && CRASHREPORTING_USES_CRASHPAD
|
||||
|
||||
if (HostOsInfo::isAnyUnixHost()) {
|
||||
connect(resetTerminalButton,
|
||||
@@ -389,7 +404,7 @@ private:
|
||||
QLineEdit *m_terminalOpenArgs;
|
||||
QLineEdit *m_terminalExecuteArgs;
|
||||
Utils::ElidingLabel *m_environmentChangesLabel;
|
||||
#ifdef ENABLE_CRASHPAD
|
||||
#ifdef CRASHREPORTING_USES_CRASHPAD
|
||||
QPushButton *m_clearCrashReportsButton;
|
||||
QLabel *m_crashReportsSizeText;
|
||||
#endif
|
||||
|
@@ -34,7 +34,7 @@ public:
|
||||
|
||||
Utils::SelectionAspect reloadSetting{this};
|
||||
|
||||
#ifdef ENABLE_CRASHPAD
|
||||
#ifdef ENABLE_CRASHREPORTING
|
||||
Utils::BoolAspect enableCrashReporting{this};
|
||||
#endif
|
||||
|
||||
|
Reference in New Issue
Block a user