From e8c724684f47813aa1aa8b46b3183613a6698cf5 Mon Sep 17 00:00:00 2001 From: Forest Date: Tue, 23 Aug 2022 12:47:52 -0700 Subject: [PATCH] Control logging via command line or environment variable Nheko is very chatty in its log output, generating log noise (which complicates diagnostics) and needless disk writes (which affect power consumption and SSD life). This patch provides control over logging, with command line options for: - Setting the global log level - Setting log levels for individual components (loggers) - Disabling log file writes - Disabling stderr writes (which are often written to ~/.xsession-errors) Log levels can also be set by the NHEKO_LOG_LEVEL environment variable. The old --debug command line option still works, at least for now, and is overridden by the new fine-grained options. Partially addresses #665. --- src/Logging.cpp | 37 +++++++++++++++++++++++++++---------- src/Logging.h | 4 ++-- src/main.cpp | 25 ++++++++++++++++++------- 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/src/Logging.cpp b/src/Logging.cpp index 9ae94f088..801225507 100644 --- a/src/Logging.cpp +++ b/src/Logging.cpp @@ -6,6 +6,8 @@ #include "Logging.h" #include "config/nheko.h" +#include "spdlog/spdlog.h" +#include "spdlog/cfg/helpers.h" #include "spdlog/sinks/rotating_file_sink.h" #include "spdlog/sinks/stdout_color_sinks.h" #include @@ -61,19 +63,20 @@ qmlMessageHandler(QtMsgType type, const QMessageLogContext &context, const QStri } namespace nhlog { -bool enable_debug_log_from_commandline = false; void -init(const std::string &file_path) +init(const std::string &level, const std::string &path, bool to_stderr) { - auto file_sink = std::make_shared( - file_path, MAX_FILE_SIZE, MAX_LOG_FILES); - - auto console_sink = std::make_shared(); - std::vector sinks; - sinks.push_back(file_sink); - sinks.push_back(console_sink); + if (!path.empty()) { + auto file_sink = std::make_shared( + path, MAX_FILE_SIZE, MAX_LOG_FILES); + sinks.push_back(file_sink); + } + if (to_stderr) { + auto console_sink = std::make_shared(); + sinks.push_back(console_sink); + } mtx::utils::log::log()->sinks() = sinks; net_logger = std::make_shared("net", std::begin(sinks), std::end(sinks)); @@ -82,7 +85,7 @@ init(const std::string &file_path) crypto_logger = std::make_shared("crypto", std::begin(sinks), std::end(sinks)); qml_logger = std::make_shared("qml", std::begin(sinks), std::end(sinks)); - if (nheko::enable_debug_log || enable_debug_log_from_commandline) { + if (nheko::enable_debug_log) { db_logger->set_level(spdlog::level::trace); ui_logger->set_level(spdlog::level::trace); crypto_logger->set_level(spdlog::level::trace); @@ -91,6 +94,20 @@ init(const std::string &file_path) mtx::utils::log::log()->set_level(spdlog::level::trace); } + spdlog::register_logger(net_logger); + spdlog::register_logger(ui_logger); + spdlog::register_logger(db_logger); + spdlog::register_logger(crypto_logger); + spdlog::register_logger(qml_logger); + + auto envlevel = qEnvironmentVariable("NHEKO_LOG_LEVEL").toStdString(); + if (!envlevel.empty()) { + spdlog::cfg::helpers::load_levels(envlevel); + } + if (!level.empty()) { + spdlog::cfg::helpers::load_levels(level); + } + qInstallMessageHandler(qmlMessageHandler); } diff --git a/src/Logging.h b/src/Logging.h index 4a5109a62..21b4585be 100644 --- a/src/Logging.h +++ b/src/Logging.h @@ -6,11 +6,12 @@ #pragma once #include +#include #include namespace nhlog { void -init(const std::string &file); +init(const std::string &level, const std::string &path, bool to_stderr); std::shared_ptr ui(); @@ -27,5 +28,4 @@ crypto(); std::shared_ptr qml(); -extern bool enable_debug_log_from_commandline; } diff --git a/src/main.cpp b/src/main.cpp index 47ebba27d..3367e9b46 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -202,8 +202,19 @@ main(int argc, char *argv[]) QCommandLineParser parser; parser.addHelpOption(); parser.addVersionOption(); - QCommandLineOption debugOption(QStringLiteral("debug"), QStringLiteral("Enable debug output")); + QCommandLineOption logLevel(QStringLiteral("loglevel"), + QStringLiteral("Set the log level, or a = list like \"warn,ui=off\". " + "levels:{trace,debug,info,warning,error,critical,off} " + "components:{crypto,db,net,qml,ui}"), + QStringLiteral("loglevel")); + parser.addOption(logLevel); + QCommandLineOption debugOption(QStringLiteral("debug"), + QStringLiteral("Alias for \"--loglevel trace\".")); parser.addOption(debugOption); + QCommandLineOption noLog(QStringLiteral("nolog"), QStringLiteral("No log file output.")); + parser.addOption(noLog); + QCommandLineOption noStderr(QStringLiteral("nostderr"), QStringLiteral("No stderr output.")); + parser.addOption(noStderr); // This option is not actually parsed via Qt due to the need to parse it before the app // name is set. It only exists to keep Qt from complaining about the --profile/-p @@ -254,13 +265,13 @@ main(int argc, char *argv[]) } #endif - if (parser.isSet(debugOption)) - nhlog::enable_debug_log_from_commandline = true; - try { - nhlog::init(QStringLiteral("%1/nheko.log") - .arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)) - .toStdString()); + std::string level = (parser.isSet(debugOption) ? "trace," : "") + + parser.value(logLevel).toStdString(); + std::string path = parser.isSet(noLog) ? "" : + QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)) + .filePath("nheko.log").toStdString(); + nhlog::init(level, path, !parser.isSet(noStderr)); } catch (const spdlog::spdlog_ex &ex) { std::cout << "Log initialization failed: " << ex.what() << std::endl; std::exit(1);