// SPDX-FileCopyrightText: 2021 Nheko Contributors // SPDX-FileCopyrightText: 2022 Nheko Contributors // SPDX-FileCopyrightText: 2023 Nheko Contributors // // SPDX-License-Identifier: GPL-3.0-or-later #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 #include #include namespace { std::shared_ptr db_logger = nullptr; std::shared_ptr net_logger = nullptr; std::shared_ptr crypto_logger = nullptr; std::shared_ptr ui_logger = nullptr; std::shared_ptr qml_logger = nullptr; constexpr auto MAX_FILE_SIZE = 1024 * 1024 * 6; constexpr auto MAX_LOG_FILES = 3; void qmlMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { std::string localMsg = msg.toStdString(); const char *file = context.file ? context.file : ""; const char *function = context.function ? context.function : ""; if ( // The default style has the point size set. If you use pixel size anywhere, you get // that warning, which is useless, since sometimes you need the pixel size to match the // text to the size of the outer element for example. This is done in the avatar and // without that you get one warning for every Avatar displayed, which is stupid! msg.endsWith(QStringLiteral("Both point size and pixel size set. Using pixel size."))) return; switch (type) { case QtDebugMsg: nhlog::qml()->debug("{} ({}:{}, {})", localMsg, file, context.line, function); break; case QtInfoMsg: nhlog::qml()->info("{} ({}:{}, {})", localMsg, file, context.line, function); break; case QtWarningMsg: nhlog::qml()->warn("{} ({}:{}, {})", localMsg, file, context.line, function); break; case QtCriticalMsg: nhlog::qml()->critical("{} ({}:{}, {})", localMsg, file, context.line, function); break; case QtFatalMsg: nhlog::qml()->critical("{} ({}:{}, {})", localMsg, file, context.line, function); break; } } } namespace nhlog { void init(const QString &level, const QString &path, bool to_stderr) { std::vector sinks; if (!path.isEmpty()) { auto file_sink = std::make_shared( path.toStdString(), 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)); ui_logger = std::make_shared("ui", std::begin(sinks), std::end(sinks)); db_logger = std::make_shared("db", std::begin(sinks), std::end(sinks)); 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) { db_logger->set_level(spdlog::level::trace); ui_logger->set_level(spdlog::level::trace); crypto_logger->set_level(spdlog::level::trace); net_logger->set_level(spdlog::level::trace); qml_logger->set_level(spdlog::level::trace); 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); } std::shared_ptr ui() { return ui_logger; } std::shared_ptr net() { return net_logger; } std::shared_ptr db() { return db_logger; } std::shared_ptr crypto() { return crypto_logger; } std::shared_ptr qml() { return qml_logger; } }