From 285f3d927b88aaa1f1149160dba759cdc76b7a76 Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Tue, 7 Nov 2023 09:05:01 -0500 Subject: [PATCH] Log Qt message handler messages --- CMakeLists.txt | 2 +- app/src/kernel/core.cpp | 66 ++++++++++++++++++++++++++++++++++++++++- app/src/kernel/core.h | 14 +++++++++ 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f2ed53f..258fe2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,7 +72,7 @@ endif() include(OB/FetchQx) ob_fetch_qx( - REF "757ed90239489811311c91f74ab842c2628b2e8b" + REF "708fbeb800d0591976e83c6b7a69f844a734b68c" COMPONENTS ${CLIFP_QX_COMPONENTS} ) diff --git a/app/src/kernel/core.cpp b/app/src/kernel/core.cpp index a67b37e..04d3fc1 100644 --- a/app/src/kernel/core.cpp +++ b/app/src/kernel/core.cpp @@ -62,7 +62,34 @@ Core::Core(QObject* parent) : mCriticalErrorOccurred(false), mStatusHeading(u"Initializing"_s), mStatusMessage(u"..."_s) -{} +{ + establishCanonCore(*this); // Ignore return value as there should never be more than one Core with current design +} + +//-Class Functions------------------------------------------------------------------------------------------------------ +//Private: +bool Core::establishCanonCore(Core& cc) +{ + if(!smDefaultMessageHandler) + smDefaultMessageHandler = qInstallMessageHandler(qtMessageHandler); + + if(smCanonCore) + return false; + + smCanonCore = &cc; + return true; +} + +void Core::qtMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) +{ + // Log messages + if(smCanonCore && smCanonCore->isLogOpen()) + smCanonCore->logQtMessage(type, context, msg); + + // Defer to default behavior + if(smDefaultMessageHandler) + smDefaultMessageHandler(type, context, msg); +} //-Instance Functions------------------------------------------------------------- //Private: @@ -225,6 +252,41 @@ Qx::Error Core::searchAndFilterEntity(QUuid& returnBuffer, QString name, bool ex } } +void Core::logQtMessage(QtMsgType type, const QMessageLogContext& context, const QString& msg) +{ +#if defined QT_NO_MESSAGELOGCONTEXT || !defined QT_MESSAGELOGCONTEXT + QString msgWithContext = msg; +#else + static const QString cTemplate = u"(%1:%2, %3) %4"_s; + static const QString unk = u"Unk."_s; + QString msgWithContext = cTemplate.arg( + context.file ? QString(context.file) : unk, + context.line >= 0 ? QString::number(context.line) : unk, + context.function ? QString(context.function) : unk, + msg + ); +#endif + + switch (type) + { + case QtDebugMsg: + logEvent(NAME, u"SYSTEM DEBUG) "_s + msgWithContext); + break; + case QtInfoMsg: + logEvent(NAME, u"SYSTEM INFO) "_s + msgWithContext); + break; + case QtWarningMsg: + logError(NAME, CoreError(CoreError::InternalError, msgWithContext, Qx::Warning)); + break; + case QtCriticalMsg: + logError(NAME, CoreError(CoreError::InternalError, msgWithContext, Qx::Err)); + break; + case QtFatalMsg: + logError(NAME, CoreError(CoreError::InternalError, msgWithContext, Qx::Critical)); + break; + } +} + //Public: Qx::Error Core::initialize(QStringList& commandLine) { @@ -734,6 +796,8 @@ Qx::Error Core::enqueueDataPackTasks(const Fp::GameData& gameData) void Core::enqueueSingleTask(Task* task) { mTaskQueue.push(task); logTask(NAME, task); } void Core::clearTaskQueue() { mTaskQueue = {}; } +bool Core::isLogOpen() const { return mLogger->isOpen(); } + void Core::logCommand(QString src, QString commandName) { Qx::IoOpReport logReport = mLogger->recordGeneralEvent(src, COMMAND_LABEL.arg(commandName)); diff --git a/app/src/kernel/core.h b/app/src/kernel/core.h index 227e5fe..70189b8 100644 --- a/app/src/kernel/core.h +++ b/app/src/kernel/core.h @@ -36,6 +36,7 @@ class QX_ERROR_TYPE(CoreError, "CoreError", 1200) enum Type { NoError, + InternalError, InvalidOptions, TitleNotFound, TooManyResults, @@ -48,6 +49,7 @@ class QX_ERROR_TYPE(CoreError, "CoreError", 1200) private: static inline const QHash ERR_STRINGS{ {NoError, u""_s}, + {InternalError, u"Internal system error."_s}, {InvalidOptions, u"Invalid global options provided."_s}, {TitleNotFound, u"Could not find the title in the Flashpoint database."_s}, {TooManyResults, u"More results than can be presented were returned in a search."_s}, @@ -233,6 +235,10 @@ class Core : public QObject // Meta static inline const QString NAME = u"core"_s; + // Qt Message Handling + static inline constinit QtMessageHandler smDefaultMessageHandler = nullptr; + static inline QPointer smCanonCore; + //-Instance Variables------------------------------------------------------------------------------------------------------ private: // Handles @@ -255,6 +261,12 @@ class Core : public QObject public: explicit Core(QObject* parent); +//-Class Functions------------------------------------------------------------------------------------------------------ +private: + // Qt Message Handling - NOTE: Storing a static instance of core is required due to the C-function pointer interface of qInstallMessageHandler() + static bool establishCanonCore(Core& cc); + static void qtMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg); + //-Instance Functions------------------------------------------------------------------------------------------------------ private: bool isActionableOptionSet(const QCommandLineParser& clParser) const; @@ -263,6 +275,7 @@ class Core : public QObject // Helper Qx::Error searchAndFilterEntity(QUuid& returnBuffer, QString name, bool exactName, QUuid parent = QUuid()); + void logQtMessage(QtMsgType type, const QMessageLogContext& context, const QString& msg); public: // Setup @@ -286,6 +299,7 @@ class Core : public QObject void clearTaskQueue(); // TODO: See if this can be done away with, it's awkward (i.e. not fill queue in first place). Think I tried to before though. // Notifications/Logging + bool isLogOpen() const; void logCommand(QString src, QString commandName); void logCommandOptions(QString src, QString commandOptions); void logError(QString src, Qx::Error error);