From ad4f0c1a8cf77bfd2dc91bb15ae2b225a5443a53 Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Wed, 22 Jun 2022 19:14:40 +0200 Subject: [PATCH 1/9] Initial implementation --- libraries/shared/CMakeLists.txt | 10 +++ libraries/shared/src/LogHandler.cpp | 97 ++++++++++++++++++++++++----- libraries/shared/src/LogHandler.h | 69 ++++++++++++++++++-- 3 files changed, 156 insertions(+), 20 deletions(-) diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index 59fb4d81ab..c03366ecda 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -21,6 +21,16 @@ if (APPLE) target_link_libraries(${TARGET_NAME} ${FRAMEWORK_IOKIT} ${CORE_FOUNDATION} ${OpenGL}) endif() +if (UNIX AND NOT APPLE) + find_package(Journald) + + if (${JOURNALD_FOUND}) + target_link_libraries(${TARGET_NAME} ${JOURNALD_LIBRARIES}) + target_include_directories(${TARGET_NAME} PRIVATE ${JOURNALD_INCLUDE_DIR}) + target_compile_definitions(${TARGET_NAME} PUBLIC HAS_JOURNALD) + endif() +endif() + target_zlib() target_nsight() target_json() diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index f214613bfa..2149350e64 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -31,6 +31,10 @@ #include #include +#ifdef HAS_JOURNALD +#include +#endif + QRecursiveMutex LogHandler::_mutex; LogHandler& LogHandler::getInstance() { @@ -51,6 +55,10 @@ LogHandler::LogHandler() { } #endif +#ifdef HAS_JOURNALD + _useJournald = true; +#endif + auto optionList = logOptions.split(","); for (auto option : optionList) { @@ -68,6 +76,8 @@ LogHandler::LogHandler() { _shouldDisplayMilliseconds = true; } else if (option == "keep_repeats") { _keepRepeats = true; + } else if (option == "nojournald") { + _useJournald = false; } else if (option != "") { fprintf(stdout, "Unrecognized option in VIRCADIA_LOG_OPTIONS: '%s'\n", option.toUtf8().constData()); } @@ -142,6 +152,13 @@ void LogHandler::setShouldDisplayMilliseconds(bool shouldDisplayMilliseconds) { _shouldDisplayMilliseconds = shouldDisplayMilliseconds; } +bool LogHandler::isJournaldAvailable() const { +#ifdef HAS_JOURNALD + return true; +#else + return false; +#endif +} void LogHandler::flushRepeatedMessages() { QMutexLocker lock(&_mutex); @@ -163,6 +180,7 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont if (message.isEmpty()) { return QString(); } + QMutexLocker lock(&_mutex); // log prefix is in the following format @@ -196,25 +214,73 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont } } + // This is returned from this function and wanted by the LogEntityServer, + // so we have to have it even when using journald. QString logMessage = QString("%1 %2\n").arg(prefixString, message.split('\n').join('\n' + prefixString + " ")); - const char* color = ""; - const char* resetColor = ""; - - if (_useColor) { - color = colorForLogType(type); - resetColor = colorReset(); - } - - if (_keepRepeats || _previousMessage != message) { - if (_repeatCount > 0) { - fprintf(stdout, "[Previous message was repeated %i times]\n", _repeatCount); + if ( _useJournald ) { +#ifdef HAS_JOURNALD + int priority = LOG_NOTICE; + switch(type) { + case LogMsgType::LogFatal: priority = LOG_EMERG; break; + case LogMsgType::LogCritical: priority = LOG_CRIT; break; + case LogMsgType::LogWarning: priority = LOG_WARNING; break; + case LogMsgType::LogInfo: priority = LOG_INFO; break; + case LogMsgType::LogDebug: priority = LOG_DEBUG; break; + case LogMsgType::LogSuppressed: priority = LOG_DEBUG; break; + default: + fprintf(stderr, "Unrecognized log type: %i", (int)type); } - fprintf(stdout, "%s%s%s", color, qPrintable(logMessage), resetColor); - _repeatCount = 0; + size_t threadID = (size_t)QThread::currentThreadId(); + QString sd_file = QString("CODE_FILE=%1").arg(context.file); + QString sd_line = QString("CODE_LINE=%1").arg(context.line); + + int retval = sd_journal_send_with_location(sd_file.toUtf8().constData(), + sd_line.toUtf8().constData(), + context.function == NULL ? "(unknown)" : context.function, + "MESSAGE=%s", message.toUtf8().constData(), + "PRIORITY=%i", priority, + "CATEGORY=%s", context.category, + "TID=%i", threadID, + NULL); + + if ( retval != 0 ) { + fprintf(stderr, "Failed to log message, error %i: ", retval); + fprintf(stderr, "file=%s, line=%i, func=%s, prio=%i, msg=%s\n", + context.file, + context.line, + context.function, + priority, + message.toUtf8().constData() + ); + } +#endif } else { - _repeatCount++; + const char* color = ""; + const char* resetColor = ""; + + if (_useColor) { + color = colorForLogType(type); + resetColor = colorReset(); + } + + if (_keepRepeats || _previousMessage != message) { + if (_repeatCount > 0) { + fprintf(stdout, "[Previous message was repeated %i times]\n", _repeatCount); + } + + fprintf(stdout, "%s%s%s", color, qPrintable(logMessage), resetColor); + _repeatCount = 0; + } else { + _repeatCount++; + } + + _previousMessage = message; + #ifdef Q_OS_WIN + // On windows, this will output log lines into the Visual Studio "output" tab + OutputDebugStringA(qPrintable(logMessage)); + #endif } if ( !_breakMessages.empty() ) { @@ -229,6 +295,7 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont // On windows, this will output log lines into the Visual Studio "output" tab OutputDebugStringA(qPrintable(logMessage)); #endif + return logMessage; } @@ -275,4 +342,4 @@ void LogHandler::printRepeatedMessage(int messageID, LogMsgType type, const QMes void LogHandler::breakOnMessage(const char *message) { QMutexLocker lock(&_mutex); LogHandler::getInstance()._breakMessages.append(QString::fromUtf8(message)); -} \ No newline at end of file +} diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h index 899e387288..54862e8e09 100644 --- a/libraries/shared/src/LogHandler.h +++ b/libraries/shared/src/LogHandler.h @@ -31,24 +31,82 @@ enum LogMsgType { LogSuppressed = 100 }; -/// Handles custom message handling and sending of stats/logs to Logstash instance +/// + +/** + * @brief Handles custom message handling and sending of stats/logs to Logstash instance + * + */ class LogHandler : public QObject { Q_OBJECT public: + /** + * @brief Returns the one instance of the LogHandler object + * + * @return LogHandler& + */ static LogHandler& getInstance(); - /// sets the target name to output via the verboseMessageHandler, called once before logging begins - /// \param targetName the desired target name to output in logs + /** + * @brief Set the Target Name to output via the verboseMessageHandler + * + * Called once before logging begins + * + * @param targetName the desired target name to output in logs + */ void setTargetName(const QString& targetName); + /** + * @brief Set whether to output the process ID + * + * @note This has no effect when logging with journald, the PID is always logged + * + * @param shouldOutputProcessID Whether to output the PID + */ void setShouldOutputProcessID(bool shouldOutputProcessID); + + /** + * @brief Set whether to output the thread ID + * + * @param shouldOutputThreadID + */ void setShouldOutputThreadID(bool shouldOutputThreadID); + + /** + * @brief Set whether to display timestamps with milliseconds + * + * @param shouldDisplayMilliseconds + */ void setShouldDisplayMilliseconds(bool shouldDisplayMilliseconds); + /** + * @brief Set whether to use Journald, if it's available + * + * @param shouldUseJournald Whether to use journald + */ + void setShouldUseJournald(bool shouldUseJournald); + + /** + * @brief Whether Journald is available on this version/system. + * + * Support is available depending on compile options and only on Linux. + * + * @return true Journald is available + * @return false Journald is not available + */ + bool isJournaldAvailable() const; + QString printMessage(LogMsgType type, const QMessageLogContext& context, const QString &message); - /// a qtMessageHandler that can be hooked up to a target that links to Qt - /// prints various process, message type, and time information + /** + * @brief A qtMessageHandler that can be hooked up to a target that links to Qt + * + * Prints various process, message type, and time information + * + * @param type Log message type + * @param context Context of the log message (source file, line, function) + * @param message Log message + */ static void verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message); int newRepeatedMessageID(); @@ -89,6 +147,7 @@ private: bool _shouldDisplayMilliseconds { false }; bool _useColor { false }; bool _keepRepeats { false }; + bool _useJournald { false }; QString _previousMessage; int _repeatCount { 0 }; From 4dec2d64309e936ac5bef7c2cb037f3c8ea9808c Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Wed, 22 Jun 2022 20:00:14 +0200 Subject: [PATCH 2/9] Add 'journald' log option --- libraries/shared/src/LogHandler.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 2149350e64..7fe90b76bc 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -76,6 +76,8 @@ LogHandler::LogHandler() { _shouldDisplayMilliseconds = true; } else if (option == "keep_repeats") { _keepRepeats = true; + } else if (option == "journald") { + _useJournald = true; } else if (option == "nojournald") { _useJournald = false; } else if (option != "") { From e01f6e30490ca5b333f112a584192594cc0af98f Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Wed, 22 Jun 2022 22:18:41 +0200 Subject: [PATCH 3/9] Finish journald logging implementation This adds command-line arguments, disables it by default on interface, adds target logging, and can deal with variable numbers of fields. It also adds some documentation. --- interface/src/main.cpp | 34 +++++++-- libraries/shared/src/LogHandler.cpp | 111 ++++++++++++++++++++-------- libraries/shared/src/LogHandler.h | 24 +++++- 3 files changed, 131 insertions(+), 38 deletions(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index e18312f8b7..a90c06df5a 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -30,8 +30,8 @@ #include "InterfaceLogging.h" #include "UserActivityLogger.h" #include "MainWindow.h" - #include "Profile.h" +#include "LogHandler.h" #ifdef Q_OS_WIN #include @@ -45,7 +45,7 @@ int main(int argc, const char* argv[]) { auto format = getDefaultOpenGLSurfaceFormat(); // Deal with some weirdness in the chromium context sharing on Mac. // The primary share context needs to be 3.2, so that the Chromium will - // succeed in it's creation of it's command stub contexts. + // succeed in it's creation of it's command stub contexts. format.setVersion(3, 2); // This appears to resolve the issues with corrupted fonts on OSX. No // idea why. @@ -54,8 +54,8 @@ int main(int argc, const char* argv[]) { QSurfaceFormat::setDefaultFormat(format); #endif -#if defined(Q_OS_WIN) - // Check the minimum version of +#if defined(Q_OS_WIN) + // Check the minimum version of if (gl::getAvailableVersion() < gl::getRequiredVersion()) { MessageBoxA(nullptr, "Interface requires OpenGL 4.1 or higher", "Unsupported", MB_OK); return -1; @@ -64,6 +64,9 @@ int main(int argc, const char* argv[]) { setupHifiApplication(BuildInfo::INTERFACE_NAME); + // Journald by default in user applications is probably a bit too modern still. + LogHandler::getInstance().setShouldUseJournald(false); + QCommandLineParser parser; parser.setApplicationDescription("Overte -- A free/libre and open-source metaverse client"); QCommandLineOption helpOption = parser.addHelpOption(); @@ -237,6 +240,11 @@ int main(int argc, const char* argv[]) { "fast-heartbeat", "Change stats polling interval from 10000ms to 1000ms." ); + QCommandLineOption logOption( + "logOptions", + "Logging options, comma separated: color,nocolor,process_id,thread_id,milliseconds,keep_repeats,journald,nojournald", + "options" + ); // "--qmljsdebugger", which appears in output from "--help-all". // Those below don't seem to be optional. // --ignore-gpu-blacklist @@ -277,6 +285,7 @@ int main(int argc, const char* argv[]) { parser.addOption(testResultsLocationOption); parser.addOption(quitWhenFinishedOption); parser.addOption(fastHeartbeatOption); + parser.addOption(logOption); QString applicationPath; // A temporary application instance is needed to get the location of the running executable @@ -299,6 +308,15 @@ int main(int argc, const char* argv[]) { #endif } + // We want to configure the logging system as early as possible + auto &logHandler = LogHandler::getInstance(); + if (parser.isSet(logOption)) { + if (!logHandler.parseOptions(parser.value(logOption).toUtf8())) { + parser.showHelp(); + Q_UNREACHABLE(); + } + } + // Act on arguments for early termination. if (parser.isSet(versionOption)) { parser.showVersion(); @@ -356,7 +374,7 @@ int main(int argc, const char* argv[]) { } } - // Early check for --traceFile argument + // Early check for --traceFile argument auto tracer = DependencyManager::set(); const char * traceFile = nullptr; float traceDuration = 0.0f; @@ -370,7 +388,7 @@ int main(int argc, const char* argv[]) { return 1; } } - + PROFILE_SYNC_BEGIN(startup, "main startup", ""); #ifdef Q_OS_LINUX @@ -378,8 +396,8 @@ int main(int argc, const char* argv[]) { #endif #if defined(USE_GLES) && defined(Q_OS_WIN) - // When using GLES on Windows, we can't create normal GL context in Qt, so - // we force Qt to use angle. This will cause the QML to be unable to be used + // When using GLES on Windows, we can't create normal GL context in Qt, so + // we force Qt to use angle. This will cause the QML to be unable to be used // in the output window, so QML should be disabled. qputenv("QT_ANGLE_PLATFORM", "d3d11"); QCoreApplication::setAttribute(Qt::AA_UseOpenGLES); diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 7fe90b76bc..b3dfecfc73 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -30,9 +30,11 @@ #include #include #include +#include #ifdef HAS_JOURNALD #include +#include #endif QRecursiveMutex LogHandler::_mutex; @@ -59,31 +61,7 @@ LogHandler::LogHandler() { _useJournald = true; #endif - auto optionList = logOptions.split(","); - - for (auto option : optionList) { - option = option.trimmed(); - - if (option == "color") { - _useColor = true; - } else if (option == "nocolor") { - _useColor = false; - } else if (option == "process_id") { - _shouldOutputProcessID = true; - } else if (option == "thread_id") { - _shouldOutputThreadID = true; - } else if (option == "milliseconds") { - _shouldDisplayMilliseconds = true; - } else if (option == "keep_repeats") { - _keepRepeats = true; - } else if (option == "journald") { - _useJournald = true; - } else if (option == "nojournald") { - _useJournald = false; - } else if (option != "") { - fprintf(stdout, "Unrecognized option in VIRCADIA_LOG_OPTIONS: '%s'\n", option.toUtf8().constData()); - } - } + parseOptions(logOptions); } const char* stringForLogType(LogMsgType msgType) { @@ -128,12 +106,53 @@ const char* colorReset() { return "\u001b[0m"; } + +#ifdef HAS_JOURNALD +void addString(std::vector&list, const QByteArray &str) { + auto data = str.constData(); + struct iovec iov{(void*)data, strlen(data)}; + list.emplace_back(iov); +} +#endif + // the following will produce 11/18 13:55:36 const QString DATE_STRING_FORMAT = "MM/dd hh:mm:ss"; // the following will produce 11/18 13:55:36.999 const QString DATE_STRING_FORMAT_WITH_MILLISECONDS = "MM/dd hh:mm:ss.zzz"; +bool LogHandler::parseOptions(QString logOptions) { + QMutexLocker lock(&_mutex); + auto optionList = logOptions.split(","); + + for (auto option : optionList) { + option = option.trimmed(); + + if (option == "color") { + _useColor = true; + } else if (option == "nocolor") { + _useColor = false; + } else if (option == "process_id") { + _shouldOutputProcessID = true; + } else if (option == "thread_id") { + _shouldOutputThreadID = true; + } else if (option == "milliseconds") { + _shouldDisplayMilliseconds = true; + } else if (option == "keep_repeats") { + _keepRepeats = true; + } else if (option == "journald") { + _useJournald = true; + } else if (option == "nojournald") { + _useJournald = false; + } else if (option != "") { + fprintf(stdout, "Unrecognized option in VIRCADIA_LOG_OPTIONS: '%s'\n", option.toUtf8().constData()); + return false; + } + } + + return true; +} + void LogHandler::setTargetName(const QString& targetName) { QMutexLocker lock(&_mutex); _targetName = targetName; @@ -154,6 +173,17 @@ void LogHandler::setShouldDisplayMilliseconds(bool shouldDisplayMilliseconds) { _shouldDisplayMilliseconds = shouldDisplayMilliseconds; } +void LogHandler::setShouldUseJournald(bool shouldUseJournald) { + QMutexLocker lock(&_mutex); +#ifdef HAS_JOURNALD + _useJournald = shouldUseJournald; +#else + if (shouldUseJournald) { + fprintf(stderr, "Journald is not supported on this system or was not compiled in.\n"); + } +#endif +} + bool LogHandler::isJournaldAvailable() const { #ifdef HAS_JOURNALD return true; @@ -231,13 +261,30 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont case LogMsgType::LogDebug: priority = LOG_DEBUG; break; case LogMsgType::LogSuppressed: priority = LOG_DEBUG; break; default: - fprintf(stderr, "Unrecognized log type: %i", (int)type); + fprintf(stderr, "Unrecognized log type: %i\n", (int)type); } - size_t threadID = (size_t)QThread::currentThreadId(); - QString sd_file = QString("CODE_FILE=%1").arg(context.file); - QString sd_line = QString("CODE_LINE=%1").arg(context.line); + QByteArray sd_file = QString("CODE_FILE=%1").arg(context.file).toUtf8(); + QByteArray sd_line = QString("CODE_LINE=%1").arg(context.line).toUtf8(); + QByteArray sd_message = QString("MESSAGE=%1").arg(message).toUtf8(); + QByteArray sd_priority = QString("PRIORITY=%1").arg(priority).toUtf8(); + QByteArray sd_category = QString("CATEGORY=%1").arg(context.category).toUtf8(); + QByteArray sd_tid = QString("TID=%1").arg((qlonglong)QThread::currentThreadId()).toUtf8(); + QByteArray sd_target = QString("TARGET=%1").arg(_targetName).toUtf8(); + + std::vector fields; + addString(fields, sd_message); + addString(fields, sd_priority); + addString(fields, sd_category); + addString(fields, sd_tid); + + if (!_targetName.isEmpty()) { + addString(fields, sd_target); + } + + +/* int retval = sd_journal_send_with_location(sd_file.toUtf8().constData(), sd_line.toUtf8().constData(), context.function == NULL ? "(unknown)" : context.function, @@ -246,6 +293,12 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont "CATEGORY=%s", context.category, "TID=%i", threadID, NULL); +*/ + int retval = sd_journal_sendv_with_location(sd_file.constData(), + sd_line.constData(), + context.function == NULL ? "(unknown)" : context.function, + fields.data(), + fields.size()); if ( retval != 0 ) { fprintf(stderr, "Failed to log message, error %i: ", retval); diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h index 54862e8e09..81ef0aff03 100644 --- a/libraries/shared/src/LogHandler.h +++ b/libraries/shared/src/LogHandler.h @@ -48,8 +48,20 @@ public: static LogHandler& getInstance(); /** - * @brief Set the Target Name to output via the verboseMessageHandler + * @brief Parse logging options * + * This parses the logging settings in the environment variable, or from the commandline + * + * @param options Option list + * @return true Option list was parsed successfully + * @return false There was an error + */ + bool parseOptions(QString options); + + /** + * @brief Set the name of the component that's producing log output + * + * For instance, "assignment-client", "audio-mixer", etc. * Called once before logging begins * * @param targetName the desired target name to output in logs @@ -96,6 +108,16 @@ public: */ bool isJournaldAvailable() const; + /** + * @brief Process a log message + * + * This writes it to a file, logs it to the console, or sends it to journald. + * + * @param type Log message type + * @param context Context of the log message (source file, line, function) + * @param message Log message + * @return QString The log message's text with added severity and timestamp + */ QString printMessage(LogMsgType type, const QMessageLogContext& context, const QString &message); /** From 133f7349c978ccef087a163112ab91e19c3b11f0 Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Wed, 22 Jun 2022 22:20:16 +0200 Subject: [PATCH 4/9] Add FindJournald cmake module From https://github.com/fluent/fluent-bit/blob/master/cmake/FindJournald.cmake --- cmake/modules/FindJournald.cmake | 45 ++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 cmake/modules/FindJournald.cmake diff --git a/cmake/modules/FindJournald.cmake b/cmake/modules/FindJournald.cmake new file mode 100644 index 0000000000..f5a3a832b2 --- /dev/null +++ b/cmake/modules/FindJournald.cmake @@ -0,0 +1,45 @@ +# - Try to find Journald library. +# Once done this will define +# +# JOURNALD_FOUND - system has Journald +# JOURNALD_INCLUDE_DIR - the Journald include directory +# JOURNALD_LIBRARIES - Link these to use Journald +# JOURNALD_DEFINITIONS - Compiler switches required for using Journald +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +# Copyright (c) 2015 David Edmundson +# + +# use pkg-config to get the directories and then use these values +# in the FIND_PATH() and FIND_LIBRARY() calls +find_package(PkgConfig) +pkg_check_modules(PC_JOURNALD QUIET systemd) + +set(JOURNALD_FOUND ${PC_JOURNALD_FOUND}) +set(JOURNALD_DEFINITIONS ${PC_JOURNALD_CFLAGS_OTHER}) + +find_path(JOURNALD_INCLUDE_DIR NAMES systemd/sd-journal.h + PATHS + ${PC_JOURNALD_INCLUDEDIR} + ${PC_JOURNALD_INCLUDE_DIRS} +) + +find_library(JOURNALD_LIBRARY NAMES systemd + PATHS + ${PC_JOURNALD_LIBDIR} + ${PC_JOURNALD_LIBRARY_DIRS} +) + +set(JOURNALD_LIBRARIES ${JOURNALD_LIBRARY}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Journald DEFAULT_MSG JOURNALD_LIBRARY JOURNALD_INCLUDE_DIR) + +include(FeatureSummary) +set_package_properties(Journald PROPERTIES URL https://github.com/systemd + DESCRIPTION "Systemd logging daemon") + +# show the JOURNALD_INCLUDE_DIR and JOURNALD_LIBRARY variables only in the advanced view +mark_as_advanced(JOURNALD_INCLUDE_DIR JOURNALD_LIBRARY) From 6110da720eb8d0b0afd0e260513e655b581d62c1 Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Thu, 23 Jun 2022 08:47:22 +0200 Subject: [PATCH 5/9] Remove old code --- libraries/shared/src/LogHandler.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index b3dfecfc73..b4b5945d74 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -283,17 +283,6 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont addString(fields, sd_target); } - -/* - int retval = sd_journal_send_with_location(sd_file.toUtf8().constData(), - sd_line.toUtf8().constData(), - context.function == NULL ? "(unknown)" : context.function, - "MESSAGE=%s", message.toUtf8().constData(), - "PRIORITY=%i", priority, - "CATEGORY=%s", context.category, - "TID=%i", threadID, - NULL); -*/ int retval = sd_journal_sendv_with_location(sd_file.constData(), sd_line.constData(), context.function == NULL ? "(unknown)" : context.function, From 2a919e35f43168239d700d9f220f293d9d1030fe Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Mon, 27 Jun 2022 20:07:00 +0200 Subject: [PATCH 6/9] Rename TARGET field to "COMPONENT" for clarity. "Target" is what's it named in the source, but it seems too confusing. --- libraries/shared/src/LogHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index b4b5945d74..2197c49dc4 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -271,7 +271,7 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont QByteArray sd_priority = QString("PRIORITY=%1").arg(priority).toUtf8(); QByteArray sd_category = QString("CATEGORY=%1").arg(context.category).toUtf8(); QByteArray sd_tid = QString("TID=%1").arg((qlonglong)QThread::currentThreadId()).toUtf8(); - QByteArray sd_target = QString("TARGET=%1").arg(_targetName).toUtf8(); + QByteArray sd_target = QString("COMPONENT=%1").arg(_targetName).toUtf8(); std::vector fields; addString(fields, sd_message); From 4204056f2ea4a851645cd5785d91cc3348ac77f2 Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Mon, 27 Jun 2022 20:07:31 +0200 Subject: [PATCH 7/9] Add --logOptions to domain server and assignment client --- assignment-client/src/AssignmentClientApp.cpp | 12 ++++++++++++ domain-server/src/DomainServer.cpp | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 6f308095c8..36e44b82a6 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -107,6 +107,9 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : const QCommandLineOption parentPIDOption(PARENT_PID_OPTION, "PID of the parent process", "parent-pid"); parser.addOption(parentPIDOption); + const QCommandLineOption logOption("logOptions", "Logging options, comma separated: color,nocolor,process_id,thread_id,milliseconds,keep_repeats,journald,nojournald", "options"); + parser.addOption(logOption); + if (!parser.parse(QCoreApplication::arguments())) { std::cout << parser.errorText().toStdString() << std::endl; // Avoid Qt log spam parser.showHelp(); @@ -123,6 +126,15 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : Q_UNREACHABLE(); } + // We want to configure the logging system as early as possible + auto &logHandler = LogHandler::getInstance(); + if (parser.isSet(logOption)) { + if (!logHandler.parseOptions(parser.value(logOption).toUtf8())) { + parser.showHelp(); + Q_UNREACHABLE(); + } + } + const QVariantMap argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments()); unsigned int numForks = 0; diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index fa7298815e..1a139530fe 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -414,6 +414,9 @@ void DomainServer::parseCommandLine(int argc, char* argv[]) { const QCommandLineOption parentPIDOption(PARENT_PID_OPTION, "PID of the parent process", "parent-pid"); parser.addOption(parentPIDOption); + const QCommandLineOption logOption("logOptions", "Logging options, comma separated: color,nocolor,process_id,thread_id,milliseconds,keep_repeats,journald,nojournald", "options"); + parser.addOption(logOption); + QStringList arguments; for (int i = 0; i < argc; ++i) { @@ -436,6 +439,15 @@ void DomainServer::parseCommandLine(int argc, char* argv[]) { Q_UNREACHABLE(); } + // We want to configure the logging system as early as possible + auto &logHandler = LogHandler::getInstance(); + if (parser.isSet(logOption)) { + if (!logHandler.parseOptions(parser.value(logOption).toUtf8())) { + parser.showHelp(); + Q_UNREACHABLE(); + } + } + if (parser.isSet(iceServerAddressOption)) { // parse the IP and port combination for this target QString hostnamePortString = parser.value(iceServerAddressOption); From 545ee0840b9d83f54a3c5645057490b99699cdfd Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Mon, 27 Jun 2022 20:30:00 +0200 Subject: [PATCH 8/9] Initialize QCoreApplication before calling showHelp --- assignment-client/src/AssignmentClientApp.cpp | 1 + domain-server/src/DomainServer.cpp | 1 + interface/src/main.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 36e44b82a6..d0e8eb2e0d 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -130,6 +130,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : auto &logHandler = LogHandler::getInstance(); if (parser.isSet(logOption)) { if (!logHandler.parseOptions(parser.value(logOption).toUtf8())) { + QCoreApplication mockApp(argc, const_cast(argv)); // required for call to showHelp() parser.showHelp(); Q_UNREACHABLE(); } diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 1a139530fe..0cf99c8d05 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -443,6 +443,7 @@ void DomainServer::parseCommandLine(int argc, char* argv[]) { auto &logHandler = LogHandler::getInstance(); if (parser.isSet(logOption)) { if (!logHandler.parseOptions(parser.value(logOption).toUtf8())) { + QCoreApplication mockApp(argc, const_cast(argv)); // required for call to showHelp() parser.showHelp(); Q_UNREACHABLE(); } diff --git a/interface/src/main.cpp b/interface/src/main.cpp index a90c06df5a..4bc0d7743a 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -312,6 +312,7 @@ int main(int argc, const char* argv[]) { auto &logHandler = LogHandler::getInstance(); if (parser.isSet(logOption)) { if (!logHandler.parseOptions(parser.value(logOption).toUtf8())) { + QCoreApplication mockApp(argc, const_cast(argv)); // required for call to showHelp() parser.showHelp(); Q_UNREACHABLE(); } From 214dce833d3612af80f89d725a89d786ef096e54 Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Mon, 27 Jun 2022 20:37:34 +0200 Subject: [PATCH 9/9] Improve error reporting for incorrect --logOptions --- assignment-client/src/AssignmentClientApp.cpp | 2 +- domain-server/src/DomainServer.cpp | 2 +- interface/src/main.cpp | 2 +- libraries/shared/src/LogHandler.cpp | 6 +++--- libraries/shared/src/LogHandler.h | 3 ++- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index d0e8eb2e0d..aafb9db5a2 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -129,7 +129,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : // We want to configure the logging system as early as possible auto &logHandler = LogHandler::getInstance(); if (parser.isSet(logOption)) { - if (!logHandler.parseOptions(parser.value(logOption).toUtf8())) { + if (!logHandler.parseOptions(parser.value(logOption).toUtf8(), logOption.names().first())) { QCoreApplication mockApp(argc, const_cast(argv)); // required for call to showHelp() parser.showHelp(); Q_UNREACHABLE(); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 0cf99c8d05..719ffa71dc 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -442,7 +442,7 @@ void DomainServer::parseCommandLine(int argc, char* argv[]) { // We want to configure the logging system as early as possible auto &logHandler = LogHandler::getInstance(); if (parser.isSet(logOption)) { - if (!logHandler.parseOptions(parser.value(logOption).toUtf8())) { + if (!logHandler.parseOptions(parser.value(logOption).toUtf8(), logOption.names().first())) { QCoreApplication mockApp(argc, const_cast(argv)); // required for call to showHelp() parser.showHelp(); Q_UNREACHABLE(); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 4bc0d7743a..640789c282 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -311,7 +311,7 @@ int main(int argc, const char* argv[]) { // We want to configure the logging system as early as possible auto &logHandler = LogHandler::getInstance(); if (parser.isSet(logOption)) { - if (!logHandler.parseOptions(parser.value(logOption).toUtf8())) { + if (!logHandler.parseOptions(parser.value(logOption).toUtf8(), logOption.names().first())) { QCoreApplication mockApp(argc, const_cast(argv)); // required for call to showHelp() parser.showHelp(); Q_UNREACHABLE(); diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 2197c49dc4..e04a036b1a 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -61,7 +61,7 @@ LogHandler::LogHandler() { _useJournald = true; #endif - parseOptions(logOptions); + parseOptions(logOptions, "VIRCADIA_LOG_OPTIONS"); } const char* stringForLogType(LogMsgType msgType) { @@ -121,7 +121,7 @@ const QString DATE_STRING_FORMAT = "MM/dd hh:mm:ss"; // the following will produce 11/18 13:55:36.999 const QString DATE_STRING_FORMAT_WITH_MILLISECONDS = "MM/dd hh:mm:ss.zzz"; -bool LogHandler::parseOptions(QString logOptions) { +bool LogHandler::parseOptions(const QString& logOptions, const QString& paramName) { QMutexLocker lock(&_mutex); auto optionList = logOptions.split(","); @@ -145,7 +145,7 @@ bool LogHandler::parseOptions(QString logOptions) { } else if (option == "nojournald") { _useJournald = false; } else if (option != "") { - fprintf(stdout, "Unrecognized option in VIRCADIA_LOG_OPTIONS: '%s'\n", option.toUtf8().constData()); + fprintf(stderr, "Unrecognized option in %s: '%s'\n", paramName.toUtf8().constData(), option.toUtf8().constData()); return false; } } diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h index 81ef0aff03..e64f8e29c3 100644 --- a/libraries/shared/src/LogHandler.h +++ b/libraries/shared/src/LogHandler.h @@ -53,10 +53,11 @@ public: * This parses the logging settings in the environment variable, or from the commandline * * @param options Option list + * @param paramName Name of the log option, for error reporting. * @return true Option list was parsed successfully * @return false There was an error */ - bool parseOptions(QString options); + bool parseOptions(const QString& options, const QString ¶mName); /** * @brief Set the name of the component that's producing log output