Save logs for Tape and Puzzle apps in log file on disk for sending with crash reports.

This commit is contained in:
Roman Telezhynskyi 2024-03-13 15:45:28 +02:00
parent eb4f8719f2
commit 24d39bffb7
5 changed files with 214 additions and 56 deletions

View File

@ -33,12 +33,11 @@
#include "../ifc/exception/vexceptionemptyparameter.h" #include "../ifc/exception/vexceptionemptyparameter.h"
#include "../ifc/exception/vexceptionobjecterror.h" #include "../ifc/exception/vexceptionobjecterror.h"
#include "../ifc/exception/vexceptionwrongid.h" #include "../ifc/exception/vexceptionwrongid.h"
#include "../vganalytics/def.h"
#include "../vganalytics/vganalytics.h" #include "../vganalytics/vganalytics.h"
#include "../vmisc/projectversion.h"
#include "../vmisc/qt_dispatch/qt_dispatch.h" #include "../vmisc/qt_dispatch/qt_dispatch.h"
#include "../vmisc/theme/vtheme.h" #include "../vmisc/theme/vtheme.h"
#include "../vmisc/vsysexits.h" #include "../vmisc/vsysexits.h"
#include "version.h"
#include "vpmainwindow.h" #include "vpmainwindow.h"
#include "vpuzzleshortcutmanager.h" #include "vpuzzleshortcutmanager.h"
@ -159,29 +158,55 @@ inline void noisyFailureMsgHandler(QtMsgType type, const QMessageLogContext &con
type = QtDebugMsg; type = QtDebugMsg;
} }
switch (type)
{ {
case QtDebugMsg: QString debugdate = "["_L1 + QDateTime::currentDateTime().toString(QStringLiteral("yyyy.MM.dd hh:mm:ss"));
vStdOut() << QApplication::translate("mNoisyHandler", "DEBUG:") << msg << "\n";
return;
case QtWarningMsg:
vStdErr() << QApplication::translate("mNoisyHandler", "WARNING:") << msg << "\n";
break;
case QtCriticalMsg:
vStdErr() << QApplication::translate("mNoisyHandler", "CRITICAL:") << msg << "\n";
break;
case QtFatalMsg:
vStdErr() << QApplication::translate("mNoisyHandler", "FATAL:") << msg << "\n";
break;
case QtInfoMsg:
vStdOut() << QApplication::translate("mNoisyHandler", "INFO:") << msg << "\n";
break;
default:
break;
}
vStdOut().flush(); switch (type)
vStdErr().flush(); {
case QtDebugMsg:
debugdate += QStringLiteral(":DEBUG:%1(%2)] %3: %4: %5")
.arg(context.file)
.arg(context.line)
.arg(context.function, context.category, msg);
vStdOut() << QApplication::translate("mNoisyHandler", "DEBUG:") << msg << "\n";
break;
case QtWarningMsg:
debugdate += QStringLiteral(":WARNING:%1(%2)] %3: %4: %5")
.arg(context.file)
.arg(context.line)
.arg(context.function, context.category, msg);
vStdErr() << QApplication::translate("mNoisyHandler", "WARNING:") << msg << "\n";
break;
case QtCriticalMsg:
debugdate += QStringLiteral(":CRITICAL:%1(%2)] %3: %4: %5")
.arg(context.file)
.arg(context.line)
.arg(context.function, context.category, msg);
vStdErr() << QApplication::translate("mNoisyHandler", "CRITICAL:") << msg << "\n";
break;
case QtFatalMsg:
debugdate += QStringLiteral(":FATAL:%1(%2)] %3: %4: %5")
.arg(context.file)
.arg(context.line)
.arg(context.function, context.category, msg);
vStdErr() << QApplication::translate("mNoisyHandler", "FATAL:") << msg << "\n";
break;
case QtInfoMsg:
debugdate += QStringLiteral(":INFO:%1(%2)] %3: %4: %5")
.arg(context.file)
.arg(context.line)
.arg(context.function, context.category, msg);
vStdOut() << QApplication::translate("mNoisyHandler", "INFO:") << msg << "\n";
break;
default:
break;
}
vStdOut().flush();
vStdErr().flush();
(*VPApplication::VApp()->LogFile()) << debugdate << Qt::endl;
}
if (isGuiThread) if (isGuiThread)
{ {
@ -209,8 +234,6 @@ inline void noisyFailureMsgHandler(QtMsgType type, const QMessageLogContext &con
messageBox.setIcon(QMessageBox::Information); messageBox.setIcon(QMessageBox::Information);
break; break;
case QtDebugMsg: case QtDebugMsg:
Q_UNREACHABLE(); //-V501
break;
default: default:
break; break;
} }
@ -405,10 +428,10 @@ auto VPApplication::NewMainWindow(const VPCommandLinePtr &cmd) -> VPMainWindow *
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void VPApplication::InitOptions() void VPApplication::InitOptions()
{ {
qInstallMessageHandler(noisyFailureMsgHandler);
OpenSettings(); OpenSettings();
StartLogging();
qCDebug(pApp, "Version: %s", qUtf8Printable(AppVersionStr())); qCDebug(pApp, "Version: %s", qUtf8Printable(AppVersionStr()));
qCDebug(pApp, "Build revision: %s", BUILD_REVISION); qCDebug(pApp, "Build revision: %s", BUILD_REVISION);
qCDebug(pApp, "%s", qUtf8Printable(buildCompatibilityString())); qCDebug(pApp, "%s", qUtf8Printable(buildCompatibilityString()));
@ -443,6 +466,22 @@ void VPApplication::InitOptions()
m_shortcutManager = new VPuzzleShortcutManager(this); m_shortcutManager = new VPuzzleShortcutManager(this);
} }
//---------------------------------------------------------------------------------------------------------------------
void VPApplication::StartLogging()
{
if (CreateLogDir())
{
BeginLogging();
ClearOldLogs();
}
}
//---------------------------------------------------------------------------------------------------------------------
auto VPApplication::LogFile() -> QTextStream *
{
return m_out.get();
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
auto VPApplication::TrVars() -> const VTranslateVars * auto VPApplication::TrVars() -> const VTranslateVars *
{ {
@ -723,6 +762,38 @@ auto VPApplication::SingleStart(const VPCommandLinePtr &cmd, const QStringList &
return true; return true;
} }
//---------------------------------------------------------------------------------------------------------------------
auto VPApplication::LogPath() -> QString
{
// Keep in sync with VCrashPaths::GetAttachmentPath
return QStringLiteral("%1/puzzle-pid%2.log").arg(LogDirPath()).arg(applicationPid());
}
//---------------------------------------------------------------------------------------------------------------------
void VPApplication::BeginLogging()
{
VlpCreateLock(m_lockLog, LogPath(), []() { return new QFile(LogPath()); });
if (m_lockLog->IsLocked())
{
if (m_lockLog->GetProtected()->open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
{
m_out.reset(new QTextStream(m_lockLog->GetProtected().data()));
qInstallMessageHandler(noisyFailureMsgHandler);
qCDebug(pApp, "Log file %s was locked.", qUtf8Printable(LogPath()));
}
else
{
qCDebug(pApp, "Error opening log file \'%s\'. All debug output redirected to console.",
qUtf8Printable(LogPath()));
}
}
else
{
qCDebug(pApp, "Failed to lock %s", qUtf8Printable(LogPath()));
}
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
auto VPApplication::CommandLine() -> VPCommandLinePtr auto VPApplication::CommandLine() -> VPCommandLinePtr
{ {

View File

@ -30,6 +30,7 @@
#include "../vmisc/def.h" #include "../vmisc/def.h"
#include "../vmisc/vabstractapplication.h" #include "../vmisc/vabstractapplication.h"
#include "../vmisc/vlockguard.h"
#include "vpcommandline.h" #include "vpcommandline.h"
#include "vpsettings.h" #include "vpsettings.h"
@ -62,6 +63,9 @@ public:
void InitOptions(); void InitOptions();
void StartLogging();
auto LogFile() -> QTextStream *;
auto TrVars() -> const VTranslateVars * override; auto TrVars() -> const VTranslateVars * override;
void OpenSettings() override; void OpenSettings() override;
@ -95,6 +99,8 @@ private:
QList<QPointer<VPMainWindow>> m_mainWindows{}; QList<QPointer<VPMainWindow>> m_mainWindows{};
QLocalServer *m_localServer{nullptr}; QLocalServer *m_localServer{nullptr};
QWeakPointer<DialogPuzzlePreferences> m_preferencesDialog{}; QWeakPointer<DialogPuzzlePreferences> m_preferencesDialog{};
QSharedPointer<VLockGuard<QFile>> m_lockLog{};
std::shared_ptr<QTextStream> m_out{nullptr};
void Clean(); void Clean();
@ -102,6 +108,9 @@ private:
auto StartWithFiles(const VPCommandLinePtr &cmd, const QStringList &rawLayouts) -> bool; auto StartWithFiles(const VPCommandLinePtr &cmd, const QStringList &rawLayouts) -> bool;
auto SingleStart(const VPCommandLinePtr &cmd, const QStringList &rawLayouts) -> bool; auto SingleStart(const VPCommandLinePtr &cmd, const QStringList &rawLayouts) -> bool;
static auto LogPath() -> QString;
void BeginLogging();
}; };
#endif // VPAPPLICATION_H #endif // VPAPPLICATION_H

View File

@ -35,7 +35,6 @@
#include "../ifc/exception/vexceptionwrongid.h" #include "../ifc/exception/vexceptionwrongid.h"
#include "../qmuparser/qmuparsererror.h" #include "../qmuparser/qmuparsererror.h"
#include "../vformat/knownmeasurements/vknownmeasurementsdatabase.h" #include "../vformat/knownmeasurements/vknownmeasurementsdatabase.h"
#include "../vganalytics/def.h"
#include "../vganalytics/vganalytics.h" #include "../vganalytics/vganalytics.h"
#include "../vmisc/projectversion.h" #include "../vmisc/projectversion.h"
#include "../vmisc/qt_dispatch/qt_dispatch.h" #include "../vmisc/qt_dispatch/qt_dispatch.h"
@ -66,7 +65,6 @@
#include <QThread> #include <QThread>
#include <QTranslator> #include <QTranslator>
#include <QUuid> #include <QUuid>
#include <iostream>
#if !defined(BUILD_REVISION) && defined(QBS_BUILD) #if !defined(BUILD_REVISION) && defined(QBS_BUILD)
#include <QEvent> #include <QEvent>
@ -197,29 +195,55 @@ inline void noisyFailureMsgHandler(QtMsgType type, const QMessageLogContext &con
logMsg = logMsg.remove(VAbstractApplication::warningMessageSignature); logMsg = logMsg.remove(VAbstractApplication::warningMessageSignature);
} }
switch (type)
{ {
case QtDebugMsg: QString debugdate = "["_L1 + QDateTime::currentDateTime().toString(QStringLiteral("yyyy.MM.dd hh:mm:ss"));
vStdOut() << QApplication::translate("mNoisyHandler", "DEBUG:") << logMsg << "\n";
return;
case QtWarningMsg:
vStdErr() << QApplication::translate("mNoisyHandler", "WARNING:") << logMsg << "\n";
break;
case QtCriticalMsg:
vStdErr() << QApplication::translate("mNoisyHandler", "CRITICAL:") << logMsg << "\n";
break;
case QtFatalMsg:
vStdErr() << QApplication::translate("mNoisyHandler", "FATAL:") << logMsg << "\n";
break;
case QtInfoMsg:
vStdOut() << QApplication::translate("mNoisyHandler", "INFO:") << logMsg << "\n";
break;
default:
break;
}
vStdOut().flush(); switch (type)
vStdErr().flush(); {
case QtDebugMsg:
debugdate += QStringLiteral(":DEBUG:%1(%2)] %3: %4: %5")
.arg(context.file)
.arg(context.line)
.arg(context.function, context.category, logMsg);
vStdOut() << QApplication::translate("mNoisyHandler", "DEBUG:") << logMsg << "\n";
break;
case QtWarningMsg:
debugdate += QStringLiteral(":WARNING:%1(%2)] %3: %4: %5")
.arg(context.file)
.arg(context.line)
.arg(context.function, context.category, logMsg);
vStdErr() << QApplication::translate("mNoisyHandler", "WARNING:") << logMsg << "\n";
break;
case QtCriticalMsg:
debugdate += QStringLiteral(":CRITICAL:%1(%2)] %3: %4: %5")
.arg(context.file)
.arg(context.line)
.arg(context.function, context.category, logMsg);
vStdErr() << QApplication::translate("mNoisyHandler", "CRITICAL:") << logMsg << "\n";
break;
case QtFatalMsg:
debugdate += QStringLiteral(":FATAL:%1(%2)] %3: %4: %5")
.arg(context.file)
.arg(context.line)
.arg(context.function, context.category, logMsg);
vStdErr() << QApplication::translate("mNoisyHandler", "FATAL:") << logMsg << "\n";
break;
case QtInfoMsg:
debugdate += QStringLiteral(":INFO:%1(%2)] %3: %4: %5")
.arg(context.file)
.arg(context.line)
.arg(context.function, context.category, logMsg);
vStdOut() << QApplication::translate("mNoisyHandler", "INFO:") << logMsg << "\n";
break;
default:
break;
}
vStdOut().flush();
vStdErr().flush();
(*MApplication::VApp()->LogFile()) << debugdate << Qt::endl;
}
if (isGuiThread) if (isGuiThread)
{ {
@ -247,8 +271,6 @@ inline void noisyFailureMsgHandler(QtMsgType type, const QMessageLogContext &con
messageBox.setIcon(QMessageBox::Information); messageBox.setIcon(QMessageBox::Information);
break; break;
case QtDebugMsg: case QtDebugMsg:
Q_UNREACHABLE(); //-V501
break;
default: default:
break; break;
} }
@ -450,10 +472,10 @@ auto MApplication::MainTapeWindows() -> QList<TMainWindow *>
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void MApplication::InitOptions() void MApplication::InitOptions()
{ {
qInstallMessageHandler(noisyFailureMsgHandler);
OpenSettings(); OpenSettings();
StartLogging();
qCDebug(mApp, "Version: %s", qUtf8Printable(AppVersionStr())); qCDebug(mApp, "Version: %s", qUtf8Printable(AppVersionStr()));
qCDebug(mApp, "Build revision: %s", BUILD_REVISION); qCDebug(mApp, "Build revision: %s", BUILD_REVISION);
qCDebug(mApp, "%s", qUtf8Printable(buildCompatibilityString())); qCDebug(mApp, "%s", qUtf8Printable(buildCompatibilityString()));
@ -484,6 +506,22 @@ void MApplication::InitOptions()
m_shortcutManager = new VTapeShortcutManager(this); m_shortcutManager = new VTapeShortcutManager(this);
} }
//---------------------------------------------------------------------------------------------------------------------
void MApplication::StartLogging()
{
if (CreateLogDir())
{
BeginLogging();
ClearOldLogs();
}
}
//---------------------------------------------------------------------------------------------------------------------
auto MApplication::LogFile() -> QTextStream *
{
return m_out.get();
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void MApplication::InitTrVars() void MApplication::InitTrVars()
{ {
@ -722,6 +760,38 @@ void MApplication::RestartKnownMeasurementsDatabaseWatcher()
} }
} }
//---------------------------------------------------------------------------------------------------------------------
auto MApplication::LogPath() -> QString
{
// Keep in sync with VCrashPaths::GetAttachmentPath
return QStringLiteral("%1/tape-pid%2.log").arg(LogDirPath()).arg(applicationPid());
}
//---------------------------------------------------------------------------------------------------------------------
void MApplication::BeginLogging()
{
VlpCreateLock(m_lockLog, LogPath(), []() { return new QFile(LogPath()); });
if (m_lockLog->IsLocked())
{
if (m_lockLog->GetProtected()->open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
{
m_out.reset(new QTextStream(m_lockLog->GetProtected().data()));
qInstallMessageHandler(noisyFailureMsgHandler);
qCDebug(mApp, "Log file %s was locked.", qUtf8Printable(LogPath()));
}
else
{
qCDebug(mApp, "Error opening log file \'%s\'. All debug output redirected to console.",
qUtf8Printable(LogPath()));
}
}
else
{
qCDebug(mApp, "Failed to lock %s", qUtf8Printable(LogPath()));
}
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
auto MApplication::NewMainTapeWindow() -> TMainWindow * auto MApplication::NewMainTapeWindow() -> TMainWindow *
{ {

View File

@ -30,6 +30,7 @@
#define MAPPLICATION_H #define MAPPLICATION_H
#include "../vmisc/vabstractapplication.h" #include "../vmisc/vabstractapplication.h"
#include "../vmisc/vlockguard.h"
#include "../vpatterndb/vtranslatevars.h" #include "../vpatterndb/vtranslatevars.h"
#include "dialogs/dialogmdatabase.h" #include "dialogs/dialogmdatabase.h"
#include "vtapesettings.h" #include "vtapesettings.h"
@ -71,6 +72,9 @@ public:
void InitOptions(); void InitOptions();
void StartLogging();
auto LogFile() -> QTextStream *;
auto TrVars() -> const VTranslateVars * override; auto TrVars() -> const VTranslateVars * override;
void OpenSettings() override; void OpenSettings() override;
@ -113,6 +117,8 @@ private:
VKnownMeasurementsDatabase *m_knownMeasurementsDatabase{nullptr}; VKnownMeasurementsDatabase *m_knownMeasurementsDatabase{nullptr};
QFileSystemWatcher *m_knownMeasurementsDatabaseWatcher{nullptr}; QFileSystemWatcher *m_knownMeasurementsDatabaseWatcher{nullptr};
QFutureWatcher<void> *m_knownMeasurementsRepopulateWatcher; QFutureWatcher<void> *m_knownMeasurementsRepopulateWatcher;
QSharedPointer<VLockGuard<QFile>> m_lockLog{};
std::shared_ptr<QTextStream> m_out{nullptr};
void CleanTapeWindows(); void CleanTapeWindows();
void CleanKMWindows(); void CleanKMWindows();
@ -131,6 +137,9 @@ private:
static void ParseUnitsOption(QCommandLineParser &parser, Unit &unit, bool &flagUnits); static void ParseUnitsOption(QCommandLineParser &parser, Unit &unit, bool &flagUnits);
void RestartKnownMeasurementsDatabaseWatcher(); void RestartKnownMeasurementsDatabaseWatcher();
static auto LogPath() -> QString;
void BeginLogging();
}; };
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------

View File

@ -224,7 +224,7 @@ inline void noisyFailureMsgHandler(QtMsgType type, const QMessageLogContext &con
} }
{ {
QString debugdate = "[" + QDateTime::currentDateTime().toString(QStringLiteral("yyyy.MM.dd hh:mm:ss")); QString debugdate = "["_L1 + QDateTime::currentDateTime().toString(QStringLiteral("yyyy.MM.dd hh:mm:ss"));
switch (type) switch (type)
{ {
@ -572,7 +572,6 @@ void VApplication::InitOptions()
{ {
OpenSettings(); OpenSettings();
// Run creation log after sending crash report
StartLogging(); StartLogging();
qDebug() << "Version:" << AppVersionStr(); qDebug() << "Version:" << AppVersionStr();