diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp index 1ea2900c..588854d3 100644 --- a/client/amnezia_application.cpp +++ b/client/amnezia_application.cpp @@ -7,7 +7,7 @@ #include "core/servercontroller.h" -#include "debug.h" +#include "logger.h" #include "defines.h" #include @@ -99,7 +99,7 @@ void AmneziaApplication::init() QCoreApplication::exit(-1); }, Qt::QueuedConnection); - m_engine->rootContext()->setContextProperty("Debug", &Debug::Instance()); + m_engine->rootContext()->setContextProperty("Debug", &Logger::Instance()); m_uiLogic->registerPagesLogic(); #if defined(Q_OS_IOS) @@ -113,7 +113,7 @@ void AmneziaApplication::init() } if (m_settings->isSaveLogs()) { - if (!Debug::init()) { + if (!Logger::init()) { qWarning() << "Initialization of debug subsystem failed"; } } @@ -206,7 +206,7 @@ bool AmneziaApplication::parseCommands() m_parser.process(*this); if (m_parser.isSet(c_cleanup)) { - Debug::cleanUp(); + Logger::cleanUp(); QTimer::singleShot(100, this, [this]{ quit(); }); diff --git a/client/client.pro b/client/client.pro index 13383b7c..d521c9b9 100644 --- a/client/client.pro +++ b/client/client.pro @@ -43,8 +43,8 @@ HEADERS += \ core/scripts_registry.h \ core/server_defs.h \ core/servercontroller.h \ - debug.h \ defines.h \ + logger.h \ managementserver.h \ platforms/ios/MobileUtils.h \ platforms/linux/leakdetector.h \ @@ -85,9 +85,6 @@ HEADERS += \ utilities.h \ vpnconnection.h \ protocols/vpnprotocol.h \ - logger.h \ - loghandler.h \ - loglevel.h \ constants.h \ platforms/ios/QRCodeReaderBase.h @@ -106,7 +103,7 @@ SOURCES += \ core/scripts_registry.cpp \ core/server_defs.cpp \ core/servercontroller.cpp \ - debug.cpp \ + logger.cpp \ main.cpp \ managementserver.cpp \ platforms/ios/MobileUtils.cpp \ @@ -146,8 +143,6 @@ SOURCES += \ utilities.cpp \ vpnconnection.cpp \ protocols/vpnprotocol.cpp \ - logger.cpp \ - loghandler.cpp \ platforms/ios/QRCodeReaderBase.cpp RESOURCES += \ diff --git a/client/core/servercontroller.cpp b/client/core/servercontroller.cpp index c7336b62..1b2d7f94 100644 --- a/client/core/servercontroller.cpp +++ b/client/core/servercontroller.cpp @@ -79,7 +79,7 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr } qDebug().noquote() << "EXEC" << lineToExec; - Debug::appendSshLog("Run command:" + lineToExec); + Logger::appendSshLog("Run command:" + lineToExec); QSharedPointer proc = client->createRemoteProcess(lineToExec.toUtf8()); @@ -105,7 +105,7 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr QString s = proc->readAllStandardOutput(); if (s != "." && !s.isEmpty()) { - Debug::appendSshLog("Output: " + s); + Logger::appendSshLog("Output: " + s); qDebug().noquote() << "stdout" << s; } if (cbReadStdOut) cbReadStdOut(s, proc); @@ -114,7 +114,7 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardError, &wait, [proc, cbReadStdErr](){ QString s = proc->readAllStandardError(); if (s != "." && !s.isEmpty()) { - Debug::appendSshLog("Output: " + s); + Logger::appendSshLog("Output: " + s); qDebug().noquote() << "stderr" << s; } if (cbReadStdErr) cbReadStdErr(s, proc); @@ -140,7 +140,7 @@ ErrorCode ServerController::runContainerScript(const ServerCredentials &credenti const std::function)> &cbReadStdErr) { QString fileName = "/opt/amnezia/" + Utils::getRandomString(16) + ".sh"; - Debug::appendSshLog("Run container script for " + ContainerProps::containerToString(container) + ":\n" + script); + Logger::appendSshLog("Run container script for " + ContainerProps::containerToString(container) + ":\n" + script); ErrorCode e = uploadTextFileToContainer(container, credentials, script, fileName); if (e) return e; diff --git a/client/core/servercontroller.h b/client/core/servercontroller.h index 091eaa52..9e8f4e40 100644 --- a/client/core/servercontroller.h +++ b/client/core/servercontroller.h @@ -5,7 +5,7 @@ #include #include "sshconnection.h" #include "sshremoteprocess.h" -#include "debug.h" +#include "logger.h" #include "defs.h" #include "containers/containers_defs.h" diff --git a/client/debug.cpp b/client/debug.cpp deleted file mode 100644 index f4d6e5e5..00000000 --- a/client/debug.cpp +++ /dev/null @@ -1,173 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include - -#include "debug.h" -#include "defines.h" -#include "utilities.h" - -#ifdef AMNEZIA_DESKTOP -#include -#endif - -QFile Debug::m_file; -QTextStream Debug::m_textStream; -QString Debug::m_logFileName = QString("%1.log").arg(APPLICATION_NAME); - -void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) -{ - if (msg.simplified().isEmpty()) { - return; - } - - // Skip annoying messages from Qt - if (msg.startsWith("Unknown property") || msg.startsWith("Could not create pixmap") || msg.startsWith("Populating font")) { - return; - } - - Debug::m_textStream << qFormatLogMessage(type, context, msg) << Qt::endl << Qt::flush; - Debug::appendAllLog(qFormatLogMessage(type, context, msg)); - - std::cout << qFormatLogMessage(type, context, msg).toStdString() << std::endl << std::flush; -} - -Debug &Debug::Instance() -{ - static Debug s; - return s; -} - -void Debug::appendSshLog(const QString &log) -{ - QString dt = QDateTime::currentDateTime().toString(); - Instance().m_sshLog.append(dt + ": " + log + "\n"); - emit Instance().sshLogChanged(Instance().sshLog()); -} - -void Debug::appendAllLog(const QString &log) -{ - Instance().m_allLog.append(log + "\n"); - emit Instance().allLogChanged(Instance().allLog()); -} - -bool Debug::init() -{ - qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss} %{type} %{message}"); - - QString path = userLogsDir(); - QDir appDir(path); - if (!appDir.mkpath(path)) { - return false; - } - - m_file.setFileName(appDir.filePath(m_logFileName)); - if (!m_file.open(QIODevice::Append)) { - qWarning() << "Cannot open log file:" << m_logFileName; - return false; - } - m_file.setTextModeEnabled(true); - m_textStream.setDevice(&m_file); - -#ifndef QT_DEBUG - qInstallMessageHandler(debugMessageHandler); -#endif - - return true; -} - -QString Debug::userLogsDir() -{ - return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/log"; -} - -QString Debug::userLogsFilePath() -{ - return userLogsDir() + QDir::separator() + m_logFileName; -} - -QString Debug::getLogFile() -{ - m_file.flush(); - QFile file(userLogsFilePath()); - - file.open(QIODevice::ReadOnly); - return file.readAll(); -} - -bool Debug::openLogsFolder() -{ - QString path = userLogsDir(); -#ifdef Q_OS_WIN - path = "file:///" + path; -#endif - if (!QDesktopServices::openUrl(QUrl::fromLocalFile(path))) { - qWarning() << "Can't open url:" << path; - return false; - } - return true; -} - -bool Debug::openServiceLogsFolder() -{ - QString path = Utils::systemLogPath(); - path = "file:///" + path; - QDesktopServices::openUrl(QUrl::fromLocalFile(path)); - return true; -} - -QString Debug::appLogFileNamePath() -{ - return m_file.fileName(); -} - -void Debug::clearLogs() -{ - bool isLogActive = m_file.isOpen(); - m_file.close(); - - QFile file(userLogsFilePath()); - - file.open(QIODevice::WriteOnly | QIODevice::Truncate); - file.resize(0); - file.close(); - - if (isLogActive) { - init(); - } -} - -void Debug::clearServiceLogs() -{ -#ifdef AMNEZIA_DESKTOP - IpcClient *m_IpcClient = new IpcClient; - - if (!m_IpcClient->isSocketConnected()) { - if (!IpcClient::init(m_IpcClient)) { - qWarning() << "Error occured when init IPC client"; - return; - } - } - - if (m_IpcClient->Interface()) { - m_IpcClient->Interface()->setLogsEnabled(false); - m_IpcClient->Interface()->cleanUp(); - } - else { - qWarning() << "Error occured cleaning up service logs"; - } -#endif -} - -void Debug::cleanUp() -{ - clearLogs(); - QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); - dir.removeRecursively(); - - clearServiceLogs(); -} diff --git a/client/debug.h b/client/debug.h deleted file mode 100644 index e58a42ca..00000000 --- a/client/debug.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef DEBUG_H -#define DEBUG_H - -#include -#include -#include -#include -#include - -#include "ui/property_helper.h" - -class Debug : public QObject -{ - Q_OBJECT - AUTO_PROPERTY(QString, sshLog) - AUTO_PROPERTY(QString, allLog) - -public: - static Debug& Instance(); - - static void appendSshLog(const QString &log); - static void appendAllLog(const QString &log); - - - static bool init(); - static bool openLogsFolder(); - static bool openServiceLogsFolder(); - static QString appLogFileNamePath(); - static void clearLogs(); - static void clearServiceLogs(); - static void cleanUp(); - - static QString userLogsFilePath(); - static QString getLogFile(); - -private: - Debug() {} - Debug(Debug const &) = delete; - Debug& operator= (Debug const&) = delete; - - static QString userLogsDir(); - - static QFile m_file; - static QTextStream m_textStream; - static QString m_logFileName; - - friend void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg); -}; - -#endif // DEBUG_H diff --git a/client/logger.cpp b/client/logger.cpp index 06a7c6c8..d734e2d8 100644 --- a/client/logger.cpp +++ b/client/logger.cpp @@ -1,59 +1,182 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - #include "logger.h" -#include "loghandler.h" -Logger::Logger(const QString& module, const QString& className) - : Logger(QStringList({module}), className) {} +#include +#include +#include +#include +#include +#include -Logger::Logger(const QStringList& modules, const QString& className) - : m_modules(modules), m_className(className) {} +#include -Logger::Log Logger::error() { return Log(this, LogLevel::Error); } -Logger::Log Logger::warning() { return Log(this, LogLevel::Warning); } -Logger::Log Logger::info() { return Log(this, LogLevel::Info); } -Logger::Log Logger::debug() { return Log(this, LogLevel::Debug); } +#include "defines.h" +#include "utilities.h" -Logger::Log::Log(Logger* logger, LogLevel logLevel) - : m_logger(logger), m_logLevel(logLevel), m_data(new Data()) {} +#ifdef AMNEZIA_DESKTOP +#include +#endif -Logger::Log::~Log() { - LogHandler::messageHandler(m_logLevel, m_logger->modules(), - m_logger->className(), m_data->m_buffer.trimmed()); - delete m_data; +QFile Logger::m_file; +QTextStream Logger::m_textStream; +QString Logger::m_logFileName = QString("%1.log").arg(APPLICATION_NAME); + +void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) +{ + if (msg.simplified().isEmpty()) { + return; + } + + // Skip annoying messages from Qt + if (msg.startsWith("Unknown property") || msg.startsWith("Could not create pixmap") || msg.startsWith("Populating font")) { + return; + } + + Logger::m_textStream << qFormatLogMessage(type, context, msg) << Qt::endl << Qt::flush; + Logger::appendAllLog(qFormatLogMessage(type, context, msg)); + + std::cout << qFormatLogMessage(type, context, msg).toStdString() << std::endl << std::flush; } -#define CREATE_LOG_OP_REF(x) \ - Logger::Log& Logger::Log::operator<<(x t) { \ - m_data->m_ts << t << ' '; \ - return *this; \ - } - -CREATE_LOG_OP_REF(uint64_t); -CREATE_LOG_OP_REF(const char*); -CREATE_LOG_OP_REF(const QString&); -CREATE_LOG_OP_REF(const QByteArray&); -CREATE_LOG_OP_REF(void*); - -#undef CREATE_LOG_OP_REF - -Logger::Log& Logger::Log::operator<<(const QStringList& t) { - m_data->m_ts << '[' << t.join(",") << ']' << ' '; - return *this; +Logger &Logger::Instance() +{ + static Logger s; + return s; } -Logger::Log& Logger::Log::operator<<(QTextStreamFunction t) { - m_data->m_ts << t; - return *this; +void Logger::appendSshLog(const QString &log) +{ + QString dt = QDateTime::currentDateTime().toString(); + Instance().m_sshLog.append(dt + ": " + log + "\n"); + emit Instance().sshLogChanged(Instance().sshLog()); } -// static -QString Logger::sensitive(const QString& input) { -#ifdef QT_DEBUG - return input; -#else - return QString(input.length(), 'X'); +void Logger::appendAllLog(const QString &log) +{ + Instance().m_allLog.append(log + "\n"); + emit Instance().allLogChanged(Instance().allLog()); +} + +bool Logger::init() +{ + qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss} %{type} %{message}"); + + QString path = userLogsDir(); + QDir appDir(path); + if (!appDir.mkpath(path)) { + return false; + } + + m_file.setFileName(appDir.filePath(m_logFileName)); + if (!m_file.open(QIODevice::Append)) { + qWarning() << "Cannot open log file:" << m_logFileName; + return false; + } + m_file.setTextModeEnabled(true); + m_textStream.setDevice(&m_file); + +#ifndef QT_DEBUG + qInstallMessageHandler(debugMessageHandler); +#endif + + return true; +} + +void Logger::deInit() +{ + qInstallMessageHandler(nullptr); + qSetMessagePattern("%{message}"); + m_textStream.setDevice(nullptr); + m_file.close(); +} + +QString Logger::userLogsDir() +{ + return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/log"; +} + +QString Logger::userLogsFilePath() +{ + return userLogsDir() + QDir::separator() + m_logFileName; +} + +QString Logger::getLogFile() +{ + m_file.flush(); + QFile file(userLogsFilePath()); + + file.open(QIODevice::ReadOnly); + return file.readAll(); +} + +bool Logger::openLogsFolder() +{ + QString path = userLogsDir(); +#ifdef Q_OS_WIN + path = "file:///" + path; +#endif + if (!QDesktopServices::openUrl(QUrl::fromLocalFile(path))) { + qWarning() << "Can't open url:" << path; + return false; + } + return true; +} + +bool Logger::openServiceLogsFolder() +{ + QString path = Utils::systemLogPath(); + path = "file:///" + path; + QDesktopServices::openUrl(QUrl::fromLocalFile(path)); + return true; +} + +QString Logger::appLogFileNamePath() +{ + return m_file.fileName(); +} + +void Logger::clearLogs() +{ + bool isLogActive = m_file.isOpen(); + m_file.close(); + + QFile file(userLogsFilePath()); + + file.open(QIODevice::WriteOnly | QIODevice::Truncate); + file.resize(0); + file.close(); + + if (isLogActive) { + init(); + } +} + +void Logger::clearServiceLogs() +{ +#ifdef AMNEZIA_DESKTOP + IpcClient *m_IpcClient = new IpcClient; + + if (!m_IpcClient->isSocketConnected()) { + if (!IpcClient::init(m_IpcClient)) { + qWarning() << "Error occured when init IPC client"; + return; + } + } + + if (m_IpcClient->Interface()) { + m_IpcClient->Interface()->setLogsEnabled(false); + m_IpcClient->Interface()->cleanUp(); + } + else { + qWarning() << "Error occured cleaning up service logs"; + } #endif } + +void Logger::cleanUp() +{ + clearLogs(); + QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); + dir.removeRecursively(); + + clearServiceLogs(); +} diff --git a/client/logger.h b/client/logger.h index 19aeb6f3..bea5213d 100644 --- a/client/logger.h +++ b/client/logger.h @@ -1,90 +1,51 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - #ifndef LOGGER_H #define LOGGER_H -#include "loglevel.h" - +#include +#include +#include #include -#include -#include #include -constexpr const char* LOG_CAPTIVEPORTAL = "captiveportal"; -constexpr const char* LOG_CONTROLLER = "controller"; -constexpr const char* LOG_IAP = "iap"; -constexpr const char* LOG_INSPECTOR = "inspector"; -constexpr const char* LOG_MAIN = "main"; -constexpr const char* LOG_MODEL = "model"; -constexpr const char* LOG_NETWORKING = "networking"; -constexpr const char* LOG_SERVER = "server"; +#include "ui/property_helper.h" -#if defined(MVPN_LINUX) || defined(MVPN_ANDROID) -constexpr const char* LOG_LINUX = "linux"; -#endif +class Logger : public QObject +{ + Q_OBJECT + AUTO_PROPERTY(QString, sshLog) + AUTO_PROPERTY(QString, allLog) -#ifdef MVPN_WINDOWS -constexpr const char* LOG_WINDOWS = "windows"; -#endif +public: + static Logger& Instance(); -#if __APPLE__ || defined(MVPN_WASM) -constexpr const char* LOG_MACOS = "macos"; -constexpr const char* LOG_IOS = "ios"; -#endif + static void appendSshLog(const QString &log); + static void appendAllLog(const QString &log); -#if defined(MVPN_ANDROID) || defined(UNIT_TEST) -constexpr const char* LOG_ANDROID = "android"; -#endif -class Logger { - public: - Logger(const QString& module, const QString& className); - Logger(const QStringList& modules, const QString& className); + static bool init(); + static void deInit(); + static bool openLogsFolder(); + static bool openServiceLogsFolder(); + static QString appLogFileNamePath(); + static void clearLogs(); + static void clearServiceLogs(); + static void cleanUp(); - const QStringList& modules() const { return m_modules; } - const QString& className() const { return m_className; } + static QString userLogsFilePath(); + static QString getLogFile(); - class Log { - public: - Log(Logger* logger, LogLevel level); - ~Log(); +private: + Logger() {} + Logger(Logger const &) = delete; + Logger& operator= (Logger const&) = delete; - Log& operator<<(uint64_t t); - Log& operator<<(const char* t); - Log& operator<<(const QString& t); - Log& operator<<(const QStringList& t); - Log& operator<<(const QByteArray& t); - Log& operator<<(QTextStreamFunction t); - Log& operator<<(void* t); + static QString userLogsDir(); - private: - Logger* m_logger; - LogLevel m_logLevel; + static QFile m_file; + static QTextStream m_textStream; + static QString m_logFileName; - struct Data { - Data() : m_ts(&m_buffer, QIODevice::WriteOnly) {} - - QString m_buffer; - QTextStream m_ts; - }; - - Data* m_data; - }; - - Log error(); - Log warning(); - Log info(); - Log debug(); - - // Use this to log sensitive data such as IP address, session tokens, and so - // on. - QString sensitive(const QString& input); - - private: - QStringList m_modules; - QString m_className; + friend void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg); }; -#endif // LOGGER_H +#endif // LOGGER_H diff --git a/client/loghandler.cpp b/client/loghandler.cpp deleted file mode 100644 index 1302f1ca..00000000 --- a/client/loghandler.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "loghandler.h" -#include "constants.h" -#include "logger.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef MVPN_ANDROID -# include -#endif - -constexpr qint64 LOG_MAX_FILE_SIZE = 204800; -constexpr const char* LOG_FILENAME = "mozillavpn.txt"; - -namespace { -QMutex s_mutex; -QString s_location = - QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); -LogHandler* s_instance = nullptr; - -LogLevel qtTypeToLogLevel(QtMsgType type) { - switch (type) { - case QtDebugMsg: - return Debug; - case QtInfoMsg: - return Info; - case QtWarningMsg: - return Warning; - case QtCriticalMsg: - [[fallthrough]]; - case QtFatalMsg: - return Error; - default: - return Debug; - } -} - -} // namespace - -// static -LogHandler* LogHandler::instance() { - QMutexLocker lock(&s_mutex); - return maybeCreate(lock); -} - -// static -void LogHandler::messageQTHandler(QtMsgType type, - const QMessageLogContext& context, - const QString& message) { - QMutexLocker lock(&s_mutex); - maybeCreate(lock)->addLog(Log(qtTypeToLogLevel(type), context.file, - context.function, context.line, message), - lock); -} - -// static -void LogHandler::messageHandler(LogLevel logLevel, const QStringList& modules, - const QString& className, - const QString& message) { - QMutexLocker lock(&s_mutex); - maybeCreate(lock)->addLog(Log(logLevel, modules, className, message), lock); -} - -// static -LogHandler* LogHandler::maybeCreate(const QMutexLocker& proofOfLock) { - if (!s_instance) { - LogLevel minLogLevel = Debug; // TODO: in prod, we should log >= warning - QStringList modules; - QProcessEnvironment pe = QProcessEnvironment::systemEnvironment(); - if (pe.contains("MOZVPN_LEVEL")) { - QString level = pe.value("MOZVPN_LEVEL"); - if (level == "info") - minLogLevel = Info; - else if (level == "warning") - minLogLevel = Warning; - else if (level == "error") - minLogLevel = Error; - } - - if (pe.contains("MOZVPN_LOG")) { - QStringList parts = pe.value("MOZVPN_LOG").split(","); - for (const QString& part : parts) { - modules.append(part.trimmed()); - } - } - - s_instance = new LogHandler(minLogLevel, modules, proofOfLock); - } - - return s_instance; -} - -// static -void LogHandler::prettyOutput(QTextStream& out, const LogHandler::Log& log) { - out << "[" << log.m_dateTime.toString("dd.MM.yyyy hh:mm:ss.zzz") << "] "; - - switch (log.m_logLevel) { - case Debug: - out << "Debug: "; - break; - case Info: - out << "Info: "; - break; - case Warning: - out << "Warning: "; - break; - case Error: - out << "Error: "; - break; - default: - out << "?!?: "; - break; - } - - if (log.m_fromQT) { - out << log.m_message; - - if (!log.m_file.isEmpty() || !log.m_function.isEmpty()) { - out << " ("; - - if (!log.m_file.isEmpty()) { - int pos = log.m_file.lastIndexOf("/"); - out << log.m_file.right(log.m_file.length() - pos - 1); - - if (log.m_line >= 0) { - out << ":" << log.m_line; - } - - if (!log.m_function.isEmpty()) { - out << ", "; - } - } - - if (!log.m_function.isEmpty()) { - out << log.m_function; - } - - out << ")"; - } - } else { - out << "(" << log.m_modules.join("|") << " - " << log.m_className << ") " - << log.m_message; - } - - out << Qt::endl; -} - -// static -void LogHandler::enableDebug() { - QMutexLocker lock(&s_mutex); - maybeCreate(lock)->m_showDebug = true; -} - -LogHandler::LogHandler(LogLevel minLogLevel, const QStringList& modules, - const QMutexLocker& proofOfLock) - : m_minLogLevel(minLogLevel), m_modules(modules) { - Q_UNUSED(proofOfLock); - -#if defined(QT_DEBUG) || defined(MVPN_WASM) - m_showDebug = true; -#endif - - if (!s_location.isEmpty()) { - openLogFile(proofOfLock); - } -} - -void LogHandler::addLog(const Log& log, const QMutexLocker& proofOfLock) { - if (!matchLogLevel(log, proofOfLock)) { - return; - } - - if (!matchModule(log, proofOfLock)) { - return; - } - - if (m_output) { - prettyOutput(*m_output, log); - } - - if ((log.m_logLevel != LogLevel::Debug) || m_showDebug) { - QTextStream out(stderr); - prettyOutput(out, log); - } - - QByteArray buffer; - { - QTextStream out(&buffer); - prettyOutput(out, log); - } - - emit logEntryAdded(buffer); - -#if defined(MVPN_ANDROID) && defined(QT_DEBUG) - const char* str = buffer.constData(); - if (str) { - __android_log_write(ANDROID_LOG_DEBUG, "mozillavpn", str); - } -#endif -} - -bool LogHandler::matchModule(const Log& log, - const QMutexLocker& proofOfLock) const { - Q_UNUSED(proofOfLock); - - // Let's include QT logs always. - if (log.m_fromQT) { - return true; - } - - // If no modules has been specified, let's include all. - if (m_modules.isEmpty()) { - return true; - } - - for (const QString& module : log.m_modules) { - if (m_modules.contains(module)) { - return true; - } - } - - return false; -} - -bool LogHandler::matchLogLevel(const Log& log, - const QMutexLocker& proofOfLock) const { - Q_UNUSED(proofOfLock); - return log.m_logLevel >= m_minLogLevel; -} - -// static -void LogHandler::writeLogs(QTextStream& out) { - QMutexLocker lock(&s_mutex); - - if (!s_instance || !s_instance->m_logFile) { - return; - } - - QString logFileName = s_instance->m_logFile->fileName(); - s_instance->closeLogFile(lock); - - { - QFile file(logFileName); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - return; - } - - out << file.readAll(); - } - - s_instance->openLogFile(lock); -} - -// static -void LogHandler::cleanupLogs() { - QMutexLocker lock(&s_mutex); - cleanupLogFile(lock); -} - -// static -void LogHandler::cleanupLogFile(const QMutexLocker& proofOfLock) { - if (!s_instance || !s_instance->m_logFile) { - return; - } - - QString logFileName = s_instance->m_logFile->fileName(); - s_instance->closeLogFile(proofOfLock); - - { - QFile file(logFileName); - file.remove(); - } - - s_instance->openLogFile(proofOfLock); -} - -// static -void LogHandler::setLocation(const QString& path) { - QMutexLocker lock(&s_mutex); - s_location = path; - - if (s_instance && s_instance->m_logFile) { - cleanupLogFile(lock); - } -} - -void LogHandler::openLogFile(const QMutexLocker& proofOfLock) { - Q_UNUSED(proofOfLock); - Q_ASSERT(!m_logFile); - Q_ASSERT(!m_output); - - QDir appDataLocation(s_location); - if (!appDataLocation.exists()) { - QDir tmp(s_location); - tmp.cdUp(); - if (!tmp.exists()) { - return; - } - if (!tmp.mkdir(appDataLocation.dirName())) { - return; - } - } - - QString logFileName = appDataLocation.filePath(LOG_FILENAME); - m_logFile = new QFile(logFileName); - if (m_logFile->size() > LOG_MAX_FILE_SIZE) { - m_logFile->remove(); - } - - if (!m_logFile->open(QIODevice::WriteOnly | QIODevice::Append | - QIODevice::Text)) { - delete m_logFile; - m_logFile = nullptr; - return; - } - - m_output = new QTextStream(m_logFile); - - addLog(Log(Debug, QStringList{LOG_MAIN}, "LogHandler", - QString("Log file: %1").arg(logFileName)), - proofOfLock); -} - -void LogHandler::closeLogFile(const QMutexLocker& proofOfLock) { - Q_UNUSED(proofOfLock); - - if (m_logFile) { - delete m_output; - m_output = nullptr; - - delete m_logFile; - m_logFile = nullptr; - } -} diff --git a/client/loghandler.h b/client/loghandler.h deleted file mode 100644 index d853a808..00000000 --- a/client/loghandler.h +++ /dev/null @@ -1,102 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef LOGHANDLER_H -#define LOGHANDLER_H - -#include "loglevel.h" - -#include -#include -#include -#include - -class QFile; -class QTextStream; - -class LogHandler final : public QObject { - Q_OBJECT - - public: - struct Log { - Log() = default; - - Log(LogLevel logLevel, const QStringList& modules, const QString& className, - const QString& message) - : m_logLevel(logLevel), - m_dateTime(QDateTime::currentDateTime()), - m_modules(modules), - m_className(className), - m_message(message), - m_fromQT(false) {} - - Log(LogLevel logLevel, const QString& file, const QString& function, - uint32_t line, const QString& message) - : m_logLevel(logLevel), - m_dateTime(QDateTime::currentDateTime()), - m_file(file), - m_function(function), - m_message(message), - m_line(line), - m_fromQT(true) {} - - LogLevel m_logLevel = LogLevel::Debug; - QDateTime m_dateTime; - QString m_file; - QString m_function; - QStringList m_modules; - QString m_className; - QString m_message; - int32_t m_line = -1; - bool m_fromQT = false; - }; - - static LogHandler* instance(); - - static void messageQTHandler(QtMsgType type, - const QMessageLogContext& context, - const QString& message); - - static void messageHandler(LogLevel logLevel, const QStringList& modules, - const QString& className, const QString& message); - - static void prettyOutput(QTextStream& out, const LogHandler::Log& log); - - static void writeLogs(QTextStream& out); - - static void cleanupLogs(); - - static void setLocation(const QString& path); - - static void enableDebug(); - - signals: - void logEntryAdded(const QByteArray& log); - - private: - LogHandler(LogLevel m_minLogLevel, const QStringList& modules, - const QMutexLocker& proofOfLock); - - static LogHandler* maybeCreate(const QMutexLocker& proofOfLock); - - void addLog(const Log& log, const QMutexLocker& proofOfLock); - - bool matchLogLevel(const Log& log, const QMutexLocker& proofOfLock) const; - bool matchModule(const Log& log, const QMutexLocker& proofOfLock) const; - - void openLogFile(const QMutexLocker& proofOfLock); - - void closeLogFile(const QMutexLocker& proofOfLock); - - static void cleanupLogFile(const QMutexLocker& proofOfLock); - - const LogLevel m_minLogLevel; - const QStringList m_modules; - bool m_showDebug = false; - - QFile* m_logFile = nullptr; - QTextStream* m_output = nullptr; -}; - -#endif // LOGHANDLER_H diff --git a/client/loglevel.h b/client/loglevel.h deleted file mode 100644 index 0bdec85b..00000000 --- a/client/loglevel.h +++ /dev/null @@ -1,15 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef LOGLEVEL_H -#define LOGLEVEL_H - -enum LogLevel { - Debug, - Info, - Warning, - Error, -}; - -#endif // LOGLEVEL_H diff --git a/client/protocols/ikev2_vpn_protocol_windows.cpp b/client/protocols/ikev2_vpn_protocol_windows.cpp index 44950f91..66c861d3 100644 --- a/client/protocols/ikev2_vpn_protocol_windows.cpp +++ b/client/protocols/ikev2_vpn_protocol_windows.cpp @@ -6,7 +6,7 @@ #include -#include "debug.h" +#include "logger.h" #include "ikev2_vpn_protocol_windows.h" #include "utilities.h" diff --git a/client/protocols/openvpnprotocol.cpp b/client/protocols/openvpnprotocol.cpp index fcce4ee6..150e84be 100644 --- a/client/protocols/openvpnprotocol.cpp +++ b/client/protocols/openvpnprotocol.cpp @@ -5,7 +5,7 @@ #include #include -#include "debug.h" +#include "logger.h" #include "defines.h" #include "utilities.h" #include "openvpnprotocol.h" diff --git a/client/protocols/shadowsocksvpnprotocol.cpp b/client/protocols/shadowsocksvpnprotocol.cpp index 6957bc3d..7e55b6f3 100644 --- a/client/protocols/shadowsocksvpnprotocol.cpp +++ b/client/protocols/shadowsocksvpnprotocol.cpp @@ -1,6 +1,6 @@ #include "shadowsocksvpnprotocol.h" -#include "debug.h" +#include "logger.h" #include "utilities.h" #include "containers/containers_defs.h" diff --git a/client/protocols/wireguardprotocol.cpp b/client/protocols/wireguardprotocol.cpp index 7f577ac5..985d835c 100644 --- a/client/protocols/wireguardprotocol.cpp +++ b/client/protocols/wireguardprotocol.cpp @@ -4,7 +4,7 @@ #include #include -#include "debug.h" +#include "logger.h" #include "wireguardprotocol.h" #include "utilities.h" diff --git a/client/settings.cpp b/client/settings.cpp index 9fea6b68..135e87ba 100644 --- a/client/settings.cpp +++ b/client/settings.cpp @@ -3,6 +3,7 @@ #include "utilities.h" #include "containers/containers_defs.h" +#include "logger.h" const char Settings::cloudFlareNs1[] = "1.1.1.1"; const char Settings::cloudFlareNs2[] = "1.0.0.1"; @@ -206,6 +207,19 @@ QString Settings::nextAvailableServerName() const return tr("Server") + " " + QString::number(i); } +void Settings::setSaveLogs(bool enabled) +{ + m_settings.setValue("Conf/saveLogs", enabled); + if (!isSaveLogs()) { + Logger::deInit(); + } else { + if (!Logger::init()) { + qWarning() << "Initialization of debug subsystem failed"; + } + } + emit saveLogsChanged(); +} + QString Settings::routeModeString(RouteMode mode) const { switch (mode) { diff --git a/client/settings.h b/client/settings.h index c78b9a79..28a49e18 100644 --- a/client/settings.h +++ b/client/settings.h @@ -68,7 +68,7 @@ public: void setStartMinimized(bool enabled) { m_settings.setValue("Conf/startMinimized", enabled); } bool isSaveLogs() const { return m_settings.value("Conf/saveLogs", false).toBool(); } - void setSaveLogs(bool enabled) { m_settings.setValue("Conf/saveLogs", enabled); } + void setSaveLogs(bool enabled); enum RouteMode { VpnAllSites, @@ -113,6 +113,9 @@ public: QByteArray backupAppConfig() const { return m_settings.backupAppConfig(); } bool restoreAppConfig(const QByteArray &cfg) { return m_settings.restoreAppConfig(cfg); } +signals: + void saveLogsChanged(); + private: SecureQSettings m_settings; diff --git a/client/ui/pages_logic/AppSettingsLogic.cpp b/client/ui/pages_logic/AppSettingsLogic.cpp index b22918b2..3590c480 100644 --- a/client/ui/pages_logic/AppSettingsLogic.cpp +++ b/client/ui/pages_logic/AppSettingsLogic.cpp @@ -1,6 +1,6 @@ #include "AppSettingsLogic.h" -#include "debug.h" +#include "logger.h" #include "defines.h" #include "ui/qautostart.h" #include "ui/uilogic.h" @@ -62,18 +62,18 @@ void AppSettingsLogic::onCheckBoxSaveLogsCheckedToggled(bool checked) void AppSettingsLogic::onPushButtonOpenLogsClicked() { - Debug::openLogsFolder(); + Logger::openLogsFolder(); } void AppSettingsLogic::onPushButtonExportLogsClicked() { - uiLogic()->saveTextFile(tr("Save log"), "AmneziaVPN.log", ".log", Debug::getLogFile()); + uiLogic()->saveTextFile(tr("Save log"), "AmneziaVPN.log", ".log", Logger::getLogFile()); } void AppSettingsLogic::onPushButtonClearLogsClicked() { - Debug::clearLogs(); - Debug::clearServiceLogs(); + Logger::clearLogs(); + Logger::clearServiceLogs(); } void AppSettingsLogic::onPushButtonBackupAppConfigClicked() diff --git a/client/ui/pages_logic/VpnLogic.cpp b/client/ui/pages_logic/VpnLogic.cpp index 44a37a5c..5f6cf077 100644 --- a/client/ui/pages_logic/VpnLogic.cpp +++ b/client/ui/pages_logic/VpnLogic.cpp @@ -33,6 +33,8 @@ VpnLogic::VpnLogic(UiLogic *logic, QObject *parent): connect(this, &VpnLogic::connectToVpn, uiLogic()->m_vpnConnection, &VpnConnection::connectToVpn, Qt::QueuedConnection); connect(this, &VpnLogic::disconnectFromVpn, uiLogic()->m_vpnConnection, &VpnConnection::disconnectFromVpn, Qt::QueuedConnection); + connect(m_settings.get(), &Settings::saveLogsChanged, this, &VpnLogic::onUpdatePage); + if (m_settings->isAutoConnect() && m_settings->defaultServerIndex() >= 0) { QTimer::singleShot(1000, this, [this](){ set_pushButtonConnectEnabled(false); @@ -88,6 +90,8 @@ void VpnLogic::onUpdatePage() } QString ver = QString("v. %2").arg(QString(APP_MAJOR_VERSION)); set_labelVersionText(ver); + + set_labelLogEnabledVisible(m_settings->isSaveLogs()); } diff --git a/client/ui/pages_logic/VpnLogic.h b/client/ui/pages_logic/VpnLogic.h index 5d6ef2d9..f7b21be2 100644 --- a/client/ui/pages_logic/VpnLogic.h +++ b/client/ui/pages_logic/VpnLogic.h @@ -34,6 +34,8 @@ class VpnLogic : public PageLogicBase AUTO_PROPERTY(bool, radioButtonVpnModeForwardSitesChecked) AUTO_PROPERTY(bool, radioButtonVpnModeExceptSitesChecked) + AUTO_PROPERTY(bool, labelLogEnabledVisible) + public: Q_INVOKABLE void onUpdatePage() override; diff --git a/client/ui/qml/Pages/PageVPN.qml b/client/ui/qml/Pages/PageVPN.qml index 08c50f14..342fb129 100644 --- a/client/ui/qml/Pages/PageVPN.qml +++ b/client/ui/qml/Pages/PageVPN.qml @@ -31,6 +31,7 @@ PageBase { } UrlButtonType { + id: button_donate y: 10 anchors.horizontalCenter: parent.horizontalCenter height: 21 @@ -55,6 +56,21 @@ PageBase { } } + LabelType { + id: lb_log_enabled + anchors.top: button_donate.bottom + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width + height: 21 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + text: "Logging enabled!" + color: "#D4D4D4" + + visible: VpnLogic.labelLogEnabledVisible + } + AnimatedImage { id: connect_anim source: "qrc:/images/animation.gif" diff --git a/client/ui/uilogic.cpp b/client/ui/uilogic.cpp index 94da8103..4e860861 100644 --- a/client/ui/uilogic.cpp +++ b/client/ui/uilogic.cpp @@ -35,7 +35,7 @@ #include "ui/qautostart.h" -#include "debug.h" +#include "logger.h" #include "defines.h" #include "uilogic.h" #include "utilities.h" @@ -190,9 +190,9 @@ void UiLogic::keyPressEvent(Qt::Key key) case Qt::Key_AsciiTilde: case Qt::Key_QuoteLeft: emit toggleLogPanel(); break; - case Qt::Key_L: Debug::openLogsFolder(); + case Qt::Key_L: Logger::openLogsFolder(); break; - case Qt::Key_K: Debug::openServiceLogsFolder(); + case Qt::Key_K: Logger::openServiceLogsFolder(); break; #ifdef QT_DEBUG case Qt::Key_Q: diff --git a/ipc/ipcserver.cpp b/ipc/ipcserver.cpp index d71d7c7d..3d248b84 100644 --- a/ipc/ipcserver.cpp +++ b/ipc/ipcserver.cpp @@ -5,7 +5,7 @@ #include #include "router.h" -#include "log.h" +#include "logger.h" #ifdef Q_OS_WIN #include "tapcontroller_win.h" @@ -111,16 +111,16 @@ QStringList IpcServer::getTapList() void IpcServer::cleanUp() { qDebug() << "IpcServer::cleanUp"; - Log::deinit(); - Log::cleanUp(); + Logger::deinit(); + Logger::cleanUp(); } void IpcServer::setLogsEnabled(bool enabled) { if (enabled) { - Log::init(); + Logger::init(); } else { - Log::deinit(); + Logger::deinit(); } } diff --git a/service/server/CMakeLists.txt b/service/server/CMakeLists.txt index 31ee3372..23df6424 100644 --- a/service/server/CMakeLists.txt +++ b/service/server/CMakeLists.txt @@ -15,7 +15,7 @@ set(HEADERS ${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserver.h ${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserverprocess.h ${CMAKE_CURRENT_LIST_DIR}/localserver.h - ${CMAKE_CURRENT_LIST_DIR}/log.h + ${CMAKE_CURRENT_LIST_DIR}/logger.h ${CMAKE_CURRENT_LIST_DIR}/router.h ${CMAKE_CURRENT_LIST_DIR}/systemservice.h ) @@ -25,7 +25,7 @@ set(SOURCES ${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserver.cpp ${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserverprocess.cpp ${CMAKE_CURRENT_LIST_DIR}/localserver.cpp - ${CMAKE_CURRENT_LIST_DIR}/log.cpp + ${CMAKE_CURRENT_LIST_DIR}/logger.cpp ${CMAKE_CURRENT_LIST_DIR}/main.cpp ${CMAKE_CURRENT_LIST_DIR}/router.cpp ${CMAKE_CURRENT_LIST_DIR}/systemservice.cpp @@ -82,9 +82,9 @@ endif() include(${CMAKE_CURRENT_LIST_DIR}/../src/qtservice.cmake) include_directories( + ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/../../client ${CMAKE_CURRENT_LIST_DIR}/../../ipc - ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) @@ -107,4 +107,4 @@ add_custom_command( ${CMAKE_SOURCE_DIR}/deploy/data/${DEPLOY_ARTIFACT_PATH} $ COMMAND_EXPAND_LISTS -) \ No newline at end of file +) diff --git a/service/server/log.cpp b/service/server/logger.cpp similarity index 83% rename from service/server/log.cpp rename to service/server/logger.cpp index a5d56ae5..8b44e0c6 100644 --- a/service/server/log.cpp +++ b/service/server/logger.cpp @@ -1,15 +1,16 @@ +#include "logger.h" + #include #include #include -#include "log.h" #include "defines.h" #include "utilities.h" -QFile Log::m_file; -QTextStream Log::m_textStream; -QString Log::m_logFileName = QString("%1.log").arg(SERVICE_NAME); +QFile Logger::m_file; +QTextStream Logger::m_textStream; +QString Logger::m_logFileName = QString("%1.log").arg(SERVICE_NAME); void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) { @@ -17,12 +18,12 @@ void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons return; } - Log::m_textStream << qFormatLogMessage(type, context, msg) << Qt::endl << Qt::flush; + Logger::m_textStream << qFormatLogMessage(type, context, msg) << Qt::endl << Qt::flush; std::cout << qFormatLogMessage(type, context, msg).toStdString() << std::endl << std::flush; } -bool Log::init() +bool Logger::init() { if (m_file.isOpen()) return true; @@ -46,19 +47,19 @@ bool Log::init() return true; } -void Log::deinit() +void Logger::deinit() { m_file.close(); m_textStream.setDevice(nullptr); qInstallMessageHandler(nullptr); } -QString Log::serviceLogFileNamePath() +QString Logger::serviceLogFileNamePath() { return m_file.fileName(); } -void Log::clearLogs() +void Logger::clearLogs() { bool isLogActive = m_file.isOpen(); m_file.close(); @@ -78,7 +79,7 @@ void Log::clearLogs() } } -void Log::cleanUp() +void Logger::cleanUp() { clearLogs(); deinit(); diff --git a/service/server/log.h b/service/server/logger.h similarity index 87% rename from service/server/log.h rename to service/server/logger.h index e87dda1d..59044470 100644 --- a/service/server/log.h +++ b/service/server/logger.h @@ -1,12 +1,12 @@ -#ifndef LOG_H -#define LOG_H +#ifndef LOGGER_H +#define LOGGER_H #include #include #include #include -class Log +class Logger { public: static bool init(); @@ -25,4 +25,4 @@ private: static QTextStream m_textStream; }; -#endif // LOG_H +#endif // LOGGER_H diff --git a/service/server/main.cpp b/service/server/main.cpp index 6908a9d8..fe566652 100644 --- a/service/server/main.cpp +++ b/service/server/main.cpp @@ -2,7 +2,7 @@ #include "defines.h" #include "localserver.h" -#include "log.h" +#include "logger.h" #include "systemservice.h" #include "utilities.h" @@ -20,7 +20,7 @@ int main(int argc, char **argv) { Utils::initializePath(Utils::systemLogPath()); - Log::init(); + Logger::init(); if (argc == 2) { qInfo() << "Started as console application"; diff --git a/service/server/server.pro b/service/server/server.pro index 0d3ecd2a..ca7d85cb 100644 --- a/service/server/server.pro +++ b/service/server/server.pro @@ -10,7 +10,7 @@ HEADERS = \ ../../ipc/ipcserver.h \ ../../ipc/ipcserverprocess.h \ localserver.h \ - log.h \ + logger.h \ router.h \ systemservice.h @@ -19,7 +19,7 @@ SOURCES = \ ../../ipc/ipcserver.cpp \ ../../ipc/ipcserverprocess.cpp \ localserver.cpp \ - log.cpp \ + logger.cpp \ main.cpp \ router.cpp \ systemservice.cpp