summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--man/nheko.1.adoc22
-rw-r--r--src/Logging.cpp34
-rw-r--r--src/Logging.h9
-rw-r--r--src/main.cpp53
4 files changed, 96 insertions, 22 deletions
diff --git a/man/nheko.1.adoc b/man/nheko.1.adoc
index 82053af0..d2eacbd4 100644
--- a/man/nheko.1.adoc
+++ b/man/nheko.1.adoc
@@ -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
diff --git a/src/Logging.cpp b/src/Logging.cpp
index 9ae94f08..cd72e395 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 <iostream>
 
 #include <QString>
@@ -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));
@@ -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);
@@ -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);
 }
 
diff --git a/src/Logging.h b/src/Logging.h
index 4a5109a6..23ff8236 100644
--- a/src/Logging.h
+++ b/src/Logging.h
@@ -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();
@@ -27,5 +31,4 @@ crypto();
 std::shared_ptr<spdlog::logger>
 qml();
 
-extern bool enable_debug_log_from_commandline;
 }
diff --git a/src/main.cpp b/src/main.cpp
index 47ebba27..f76d8ca6 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -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
@@ -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);
     }