From 11816739fa20fda20204399866e5dafb0ffdcb96 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 | 7 ++++--- src/main.cpp | 26 +++++++++++++++++++------- 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/src/Logging.cpp b/src/Logging.cpp index 9ae94f088..5dbbe272b 100644 --- a/src/Logging.cpp +++ b/src/Logging.cpp @@ -6,8 +6,10 @@ #include "Logging.h" #include "config/nheko.h" +#include "spdlog/cfg/helpers.h" #include "spdlog/sinks/rotating_file_sink.h" #include "spdlog/sinks/stdout_color_sinks.h" +#include "spdlog/spdlog.h" #include #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..976a3d8a3 100644 --- a/src/Logging.h +++ b/src/Logging.h @@ -6,11 +6,13 @@ #pragma once #include -#include +#include + +#include "spdlog/logger.h" 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 +29,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..a21b0ba2d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -202,8 +202,20 @@ 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 +266,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 = QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)) + .filePath("nheko.log") + .toStdString(); + nhlog::init(level, parser.isSet(noLog) ? "" : path, !parser.isSet(noStderr)); } catch (const spdlog::spdlog_ex &ex) { std::cout << "Log initialization failed: " << ex.what() << std::endl; std::exit(1);