From 8b4c1c64b0d088d282a049b581d0c8fb85f54655 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Mon, 15 Jun 2026 17:37:37 -0400 Subject: [PATCH] Include Qt messages in log file --- include/log.h | 5 +- src/log.cpp | 142 +++++++++++++++++++++++++++++++++++--------------- 2 files changed, 104 insertions(+), 43 deletions(-) diff --git a/include/log.h b/include/log.h index abe85d35..198c1f65 100644 --- a/include/log.h +++ b/include/log.h @@ -20,7 +20,10 @@ void logInit(); void logInfo(const QString &message); void logWarn(const QString &message); void logError(const QString &message); -void log(const QString &message, LogType type); + +template +void log(const QString &message, T type); + QString getLogPath(); QString getMostRecentError(); void addLogStatusBar(QStatusBar *statusBar, const QSet &types = {}); diff --git a/src/log.cpp b/src/log.cpp index d2cde0a4..89b3a0d8 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -7,12 +7,15 @@ #include #include +#include + namespace Log { static QString mostRecentError; static QString path; static QFile file; static QTextStream textStream; static bool initialized = false; + static QtMessageHandler originalHandler = nullptr; struct Display { QPointer statusBar; @@ -38,34 +41,69 @@ namespace Log { #define CLEAR_COLOR "\033[0m" #endif -void logInfo(const QString &message) { - log(message, LogType::LOG_INFO); -} - -void logWarn(const QString &message) { - log(message, LogType::LOG_WARN); -} - -void logError(const QString &message) { - Log::mostRecentError = message; - log(message, LogType::LOG_ERROR); +QString colorizeTypeName(const QString &message, const QString &typeName, const QString &colorFormat) { + QString colorized = message; + return colorized.replace(typeName, colorFormat + typeName + CLEAR_COLOR); } QString colorizeMessage(const QString &message, LogType type) { - QString colorized = message; switch (type) { - case LogType::LOG_INFO: - colorized = colorized.replace("INFO", INFO_COLOR "INFO" CLEAR_COLOR); - break; - case LogType::LOG_WARN: - colorized = colorized.replace("WARN", WARNING_COLOR "WARN" CLEAR_COLOR); - break; - case LogType::LOG_ERROR: - colorized = colorized.replace("ERROR", ERROR_COLOR "ERROR" CLEAR_COLOR); - break; + case LogType::LOG_INFO: return colorizeTypeName(message, "INFO", INFO_COLOR); + case LogType::LOG_WARN: return colorizeTypeName(message, "WARN", WARNING_COLOR); + case LogType::LOG_ERROR: return colorizeTypeName(message, "ERROR", ERROR_COLOR); + } +} + +QString colorizeMessage(const QString &message, QtMsgType type) { + switch (type) + { + case QtDebugMsg: return colorizeTypeName(message, "QT DEBUG", INFO_COLOR); + case QtInfoMsg: return colorizeTypeName(message, "QT INFO", INFO_COLOR); + case QtWarningMsg: return colorizeTypeName(message, "QT WARN", WARNING_COLOR); + case QtCriticalMsg: return colorizeTypeName(message, "QT ERROR", ERROR_COLOR); + case QtFatalMsg: return colorizeTypeName(message, "QT FATAL", ERROR_COLOR); + } +} + +std::ostream& stream(LogType type) { + switch (type) { + case LogType::LOG_INFO: + return std::cout; + case LogType::LOG_WARN: + case LogType::LOG_ERROR: + return std::cerr; + } +} + +std::ostream& stream(QtMsgType type) { + switch (type) { + case QtDebugMsg: + case QtInfoMsg: + return std::cout; + case QtWarningMsg: + case QtCriticalMsg: + case QtFatalMsg: + return std::cerr; + } +} + +QString prefix(LogType type) { + switch (type) { + case LogType::LOG_INFO: return QStringLiteral(" [INFO]"); + case LogType::LOG_WARN: return QStringLiteral(" [WARN]"); + case LogType::LOG_ERROR: return QStringLiteral(" [ERROR]"); + } +} + +QString prefix(QtMsgType type) { + switch (type) { + case QtDebugMsg: return QStringLiteral("[QT DEBUG]"); + case QtInfoMsg: return QStringLiteral(" [QT INFO]"); + case QtWarningMsg: return QStringLiteral(" [QT WARN]"); + case QtCriticalMsg: return QStringLiteral("[QT ERROR]"); + case QtFatalMsg: return QStringLiteral("[QT FATAL]"); } - return colorized; } void addLogStatusBar(QStatusBar *statusBar, const QSet &acceptedTypes) { @@ -115,6 +153,10 @@ void pruneLogDisplays() { } } +void updateLogDisplays(const QString &/*message*/, QtMsgType /*type*/) { + // Don't send Qt messages to status bar +} + void updateLogDisplays(const QString &message, LogType type) { static const QMap icons = { {LogType::LOG_INFO, QPixmap(QStringLiteral(":/icons/information.ico"))}, @@ -146,29 +188,23 @@ void clearLogDisplays() { } } -void log(const QString &message, LogType type) { - QString now = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"); - QString typeString = ""; - switch (type) - { - case LogType::LOG_INFO: - typeString = QStringLiteral(" [INFO]"); - break; - case LogType::LOG_WARN: - typeString = QStringLiteral(" [WARN]"); - break; - case LogType::LOG_ERROR: - typeString = QStringLiteral("[ERROR]"); - break; - } +template +void logToConsole(const QString &message, T type) { + stream(type) << colorizeMessage(message, type).toStdString() << std::endl; +} - QString fullMessage = QString("%1 %2 %3").arg(now).arg(typeString).arg(message); +template +QString toPrefixedMessage(const QString &message, T type) { + const QString now = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"); + return QString("%1 %2 %3").arg(now).arg(prefix(type)).arg(message); +} - qDebug().noquote() << colorizeMessage(fullMessage, type); +template +void log(const QString &message, T type) { + const QString fullMessage = toPrefixedMessage(message, type); + logToConsole(fullMessage, type); - if (!Log::initialized) { - return; - } + if (!Log::initialized) return; updateLogDisplays(message, type); @@ -176,6 +212,24 @@ void log(const QString &message, LogType type) { Log::file.flush(); } +void logQt(QtMsgType type, const QMessageLogContext &context, const QString &msg) { + log(qFormatLogMessage(type, context, msg), type); + if (Log::originalHandler) Log::originalHandler(type, context, msg); +} + +void logInfo(const QString &message) { + log(message, LogType::LOG_INFO); +} + +void logWarn(const QString &message) { + log(message, LogType::LOG_WARN); +} + +void logError(const QString &message) { + Log::mostRecentError = message; + log(message, LogType::LOG_ERROR); +} + QString getLogPath() { return Log::path; } @@ -189,6 +243,8 @@ bool cleanupLargeLog() { } void logInit() { + if (Log::initialized) return; + QString settingsPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); QDir dir(settingsPath); if (!dir.exists()) @@ -202,6 +258,8 @@ void logInit() { clearLogDisplays(); }); + qInstallMessageHandler(logQt); + Log::initialized = true; if (cleanupLargeLog()) {