Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Control logging via command line or environment variable #1163

Merged
merged 1 commit into from
Sep 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion man/nheko.1.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,27 @@ Displays help including Qt specific options.
Displays version information.

*--debug*::
Enables debug output.
Alias for _--log-level trace_.

*-l*, *--log-level* _<level>_::
Set the global log level, or a comma-separated list of _<component>=<level>_
pairs, or both. For example, to set the default log level to _warn_ but
disable logging for the _ui_ component, pass _warn,ui=off_.
+
levels: _trace_ _debug_ _info_ _warning_ _error_ _critical_ _off_
+
components: _crypto_ _db_ _mtx_ _net_ _qml_ _ui_
+
Log levels can also be set in the NHEKO_LOG_LEVEL environment variable, using
the same syntax. It will be overridden by this command line option.

*-L*, *--log-type* _<type>_::
Set the log output type. A comma-separated list is allowed. The default is _file,stderr_.
+
types: _file_ _stderr_ _none_
+
The log type can also be set in the NHEKO_LOG_TYPE environment variable,
which will be overridden by this command line option.

*-p* _<profile>_, *--profile* _<profile>_::
Creates a unique profile, which allows you to log into several accounts at the
Expand Down
34 changes: 24 additions & 10 deletions src/Logging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <iostream>

#include <QString>
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 QString &level, const QString &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.isEmpty()) {
auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
path.toStdString(), 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,17 @@ 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);
// We assume the mtxclient library will register its own logger.

if (!level.isEmpty()) {
spdlog::cfg::helpers::load_levels(level.toStdString());
}

qInstallMessageHandler(qmlMessageHandler);
}

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

#include <memory>
#include <spdlog/logger.h>
#include <string>

#include <QString>

#include "spdlog/logger.h"

namespace nhlog {
void
init(const std::string &file);
init(const QString &level, const QString &path, bool to_stderr);

std::shared_ptr<spdlog::logger>
ui();
Expand All @@ -27,5 +31,4 @@ crypto();
std::shared_ptr<spdlog::logger>
qml();

extern bool enable_debug_log_from_commandline;
}
53 changes: 45 additions & 8 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,24 @@ main(int argc, char *argv[])
QCommandLineParser parser;
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption debugOption(QStringLiteral("debug"), QStringLiteral("Enable debug output"));
QCommandLineOption debugOption(QStringLiteral("debug"),
QObject::tr("Alias for '--log-level trace'."));
parser.addOption(debugOption);
QCommandLineOption logLevel(
QStringList() << QStringLiteral("l") << QStringLiteral("log-level"),
QObject::tr("Set the global log level, or a comma-separated list of <component>=<level> "
"pairs, or both. For example, to set the default log level to 'warn' but "
"disable logging for the 'ui' component, pass 'warn,ui=off'. "
"levels:{trace,debug,info,warning,error,critical,off} "
"components:{crypto,db,mtx,net,qml,ui}"),
QObject::tr("level"));
parser.addOption(logLevel);
QCommandLineOption logType(
QStringList() << QStringLiteral("L") << QStringLiteral("log-type"),
QObject::tr("Set the log output type. A comma-separated list is allowed. "
"The default is 'file,stderr'. types:{file,stderr,none}"),
QObject::tr("type"));
parser.addOption(logType);

// 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,15 +270,36 @@ 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());
QString level;
if (parser.isSet(logLevel)) {
level = parser.value(logLevel);
} else if (parser.isSet(debugOption)) {
level = "trace";
} else {
level = qEnvironmentVariable("NHEKO_LOG_LEVEL");
}

QStringList targets =
(parser.isSet(logType) ? parser.value(logType)
: qEnvironmentVariable("NHEKO_LOG_TYPE", "file,stderr"))
.split(',', Qt::SkipEmptyParts);
targets.removeAll("none");
bool to_stderr = bool(targets.removeAll("stderr"));
QString path = targets.removeAll("file")
? QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation))
.filePath("nheko.log")
: QLatin1String("");
if (!targets.isEmpty()) {
std::cerr << "Invalid log type '" << targets.first().toStdString().c_str() << "'"
<< std::endl;
std::exit(1);
}

nhlog::init(level, path, to_stderr);

} catch (const spdlog::spdlog_ex &ex) {
std::cout << "Log initialization failed: " << ex.what() << std::endl;
std::cerr << "Log initialization failed: " << ex.what() << std::endl;
std::exit(1);
}

Expand Down