mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-08 02:53:25 -08:00
[CrashReporting] Mock dialog, sentry skeleton and CI prerequisites
Mock: DlgCrashReport preview dialog (no account needed, redacted log preview), CrashReportingMode Ask/Always/Never setting in DebugSettings, --simulate-crash flag and Help-menu preview entry. Send writes a local mock JSON only. Vendor sentry-native 0.17.3 via FetchContent behind WITH_CRASH_REPORTING (breakpad everywhere, backend none under sanitizers) plus a CrashReporter facade with early init and post-loop shutdown. DSN is a placeholder: empty CMake default with COCKATRICE_SENTRY_DSN env override, so SDK init is skipped and mock behavior is unchanged until a real DSN is configured. CI prerequisites riding here so every layer below builds green: libcurl dev plus CA bundles in the Linux images and CodeQL env, sentry Qt integration off (its own find_package cannot see the macOS thin Qt layout), and the StrFunc Using construction makensis requires. Tests: ctest green, format clean, code plus UI gates PASS.
This commit is contained in:
parent
ea6af0048c
commit
6411abfb57
28 changed files with 962 additions and 5 deletions
152
cockatrice/src/interface/widgets/dialogs/dlg_crash_report.cpp
Normal file
152
cockatrice/src/interface/widgets/dialogs/dlg_crash_report.cpp
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
#include "dlg_crash_report.h"
|
||||
|
||||
#include "../../../client/crash/crash_reporter.h"
|
||||
#include "../../../client/settings/cache_settings.h"
|
||||
#include "../../logger.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QEvent>
|
||||
#include <QFile>
|
||||
#include <QHBoxLayout>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QLabel>
|
||||
#include <QList>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <libcockatrice/settings/personal_settings.h>
|
||||
|
||||
DlgCrashReport::DlgCrashReport(QWidget *parent) : QDialog(parent)
|
||||
{
|
||||
infoLabel = new QLabel(this);
|
||||
infoLabel->setWordWrap(true);
|
||||
|
||||
accountLabel = new QLabel(this);
|
||||
accountLabel->setWordWrap(true);
|
||||
|
||||
previewArea = new QPlainTextEdit(this);
|
||||
previewArea->setReadOnly(true);
|
||||
previewArea->setPlainText(buildRedactedPreview());
|
||||
|
||||
rememberBox = new QCheckBox(this);
|
||||
|
||||
sendButton = new QPushButton(this);
|
||||
sendButton->setDefault(true);
|
||||
connect(sendButton, &QPushButton::clicked, this, &DlgCrashReport::actSend);
|
||||
|
||||
dontSendButton = new QPushButton(this);
|
||||
dontSendButton->setAutoDefault(false);
|
||||
connect(dontSendButton, &QPushButton::clicked, this, &DlgCrashReport::actDontSend);
|
||||
|
||||
auto *buttonLayout = new QHBoxLayout;
|
||||
buttonLayout->addWidget(rememberBox);
|
||||
buttonLayout->addStretch();
|
||||
buttonLayout->addWidget(dontSendButton);
|
||||
buttonLayout->addWidget(sendButton);
|
||||
|
||||
auto *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addWidget(infoLabel);
|
||||
mainLayout->addWidget(accountLabel);
|
||||
mainLayout->addWidget(previewArea);
|
||||
mainLayout->addLayout(buttonLayout);
|
||||
setLayout(mainLayout);
|
||||
|
||||
resize(700, 500);
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void DlgCrashReport::changeEvent(QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::LanguageChange) {
|
||||
retranslateUi();
|
||||
}
|
||||
QDialog::changeEvent(event);
|
||||
}
|
||||
|
||||
void DlgCrashReport::retranslateUi()
|
||||
{
|
||||
setWindowTitle(tr("Send crash report"));
|
||||
infoLabel->setText(
|
||||
tr("Cockatrice closed unexpectedly. The preview below shows what a crash report would contain (mock)."));
|
||||
accountLabel->setText(tr("No account needed to send a crash report."));
|
||||
rememberBox->setText(tr("Remember my choice"));
|
||||
sendButton->setText(tr("Send"));
|
||||
dontSendButton->setText(tr("Don't send"));
|
||||
}
|
||||
|
||||
QString DlgCrashReport::buildRedactedPreview()
|
||||
{
|
||||
Logger &logger = Logger::getInstance();
|
||||
|
||||
QStringList header;
|
||||
header.append(logger.getClientVersion());
|
||||
header.append(logger.getSystemArchitecture());
|
||||
header.append(logger.getSystemLocale());
|
||||
header.append(logger.getClientInstallInfo());
|
||||
header.append(QStringLiteral("---"));
|
||||
|
||||
QList<QString> logLines = logger.getPreviousSessionTail();
|
||||
if (logLines.isEmpty()) {
|
||||
logLines = logger.getLogBuffer();
|
||||
}
|
||||
const int previewLines = 60;
|
||||
int start = logLines.size() > previewLines ? logLines.size() - previewLines : 0;
|
||||
|
||||
QStringList lines = header;
|
||||
for (int i = start; i < logLines.size(); ++i) {
|
||||
lines.append(CrashReporter::redactCockatriceUrls(CrashReporter::sanitizeLogLine(logLines.at(i))));
|
||||
}
|
||||
return lines.join(QStringLiteral("\n"));
|
||||
}
|
||||
|
||||
QString DlgCrashReport::writeMockReport(const QString &previewText)
|
||||
{
|
||||
Logger &logger = Logger::getInstance();
|
||||
|
||||
QJsonObject report;
|
||||
report[QStringLiteral("mock")] = true;
|
||||
report[QStringLiteral("timestamp")] = QDateTime::currentDateTimeUtc().toString(Qt::ISODate);
|
||||
report[QStringLiteral("clientVersion")] = logger.getClientVersion();
|
||||
report[QStringLiteral("systemArchitecture")] = logger.getSystemArchitecture();
|
||||
report[QStringLiteral("systemLocale")] = logger.getSystemLocale();
|
||||
report[QStringLiteral("installInfo")] = logger.getClientInstallInfo();
|
||||
report[QStringLiteral("logPreview")] = previewText;
|
||||
|
||||
QString fileName = QStringLiteral("crash-report-mock-%1.json")
|
||||
.arg(QDateTime::currentDateTimeUtc().toString(QStringLiteral("yyyyMMdd-HHmmss")));
|
||||
QString filePath = QDir::tempPath() + QStringLiteral("/") + fileName;
|
||||
|
||||
QFile file(filePath);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
return QString();
|
||||
}
|
||||
file.write(QJsonDocument(report).toJson());
|
||||
file.close();
|
||||
return filePath;
|
||||
}
|
||||
|
||||
void DlgCrashReport::actSend()
|
||||
{
|
||||
if (rememberBox->isChecked()) {
|
||||
SettingsCache::instance().personal().setCrashReportingMode(PersonalSettings::CrashReportingMode::AlwaysSend);
|
||||
}
|
||||
const QString savedPath = writeMockReport(previewArea->toPlainText());
|
||||
if (savedPath.isEmpty()) {
|
||||
qWarning() << "Could not save the mock crash report locally";
|
||||
} else {
|
||||
qInfo() << "Mock crash report saved locally to" << savedPath;
|
||||
}
|
||||
accept();
|
||||
}
|
||||
|
||||
void DlgCrashReport::actDontSend()
|
||||
{
|
||||
if (rememberBox->isChecked()) {
|
||||
SettingsCache::instance().personal().setCrashReportingMode(PersonalSettings::CrashReportingMode::NeverSend);
|
||||
}
|
||||
reject();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue