Skip to content

Commit

Permalink
Control logging via command line or environment variable
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Forest committed Aug 24, 2022
1 parent 2e5e157 commit e8c7246
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 19 deletions.
37 changes: 27 additions & 10 deletions src/Logging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <iostream>
Expand Down Expand Up @@ -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<spdlog::sinks::rotating_file_sink_mt>(
file_path, MAX_FILE_SIZE, MAX_LOG_FILES);

auto console_sink = std::make_shared<spdlog::sinks::stderr_color_sink_mt>();

std::vector<spdlog::sink_ptr> sinks;
sinks.push_back(file_sink);
sinks.push_back(console_sink);
if (!path.empty()) {
auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
path, MAX_FILE_SIZE, MAX_LOG_FILES);
sinks.push_back(file_sink);
}
if (to_stderr) {
auto console_sink = std::make_shared<spdlog::sinks::stderr_color_sink_mt>();
sinks.push_back(console_sink);
}

mtx::utils::log::log()->sinks() = sinks;
net_logger = std::make_shared<spdlog::logger>("net", std::begin(sinks), std::end(sinks));
Expand All @@ -82,7 +85,7 @@ init(const std::string &file_path)
crypto_logger = std::make_shared<spdlog::logger>("crypto", std::begin(sinks), std::end(sinks));
qml_logger = std::make_shared<spdlog::logger>("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);
Expand All @@ -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);
}

Expand Down
4 changes: 2 additions & 2 deletions src/Logging.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
#pragma once

#include <memory>
#include <string>
#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<spdlog::logger>
ui();
Expand All @@ -27,5 +28,4 @@ crypto();
std::shared_ptr<spdlog::logger>
qml();

extern bool enable_debug_log_from_commandline;
}
25 changes: 18 additions & 7 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <component>=<level> 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
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit e8c7246

Please sign in to comment.