From 37110ceaa070167b4f40ed449ac9ea130503a792 Mon Sep 17 00:00:00 2001 From: Manuel Nickschas Date: Thu, 21 Jun 2018 01:36:27 +0200 Subject: [PATCH] logger: Refactor the logging framework * Rename the previous Logger class to LogMessage (since that is what it is), and consolidate logging functionality, including the various output methods, setup of log file etc., into a new Logger class. * Hold the "debug log", i.e. the collected log messages, in the Logger class instead of in the Client. Adapt the DebugLogWidget accordingly. Messages will not be kept in quasselcore, as we wouldn't have a way to display them otherwise (and we don't want to accumulate lots of data over months of the core running). * Support early log messages. Instantiate the Logger right at the start of main(), and keep all log messages until the Quassel class is initialized and we can rely on command-line options to configure backends accordingly. Accumulated messages will be output once the Logger is configured. --- src/client/client.cpp | 48 +---- src/client/client.h | 12 -- src/client/clientauthhandler.cpp | 2 +- src/common/CMakeLists.txt | 1 + src/common/basichandler.cpp | 3 +- src/common/logger.cpp | 262 +++++++++++++++++-------- src/common/logger.h | 118 +++++++---- src/common/logmessage.cpp | 52 +++++ src/common/logmessage.h | 93 +++++++++ src/common/main.cpp | 3 + src/common/quassel.cpp | 88 +-------- src/common/quassel.h | 36 ++-- src/core/abstractsqlstorage.cpp | 6 +- src/core/cipher.cpp | 2 +- src/core/core.cpp | 2 +- src/core/coreauthhandler.cpp | 2 +- src/core/corebasichandler.cpp | 2 +- src/core/coresession.cpp | 2 +- src/core/coresessioneventprocessor.cpp | 2 +- src/core/identserver.cpp | 2 +- src/core/ldapauthenticator.cpp | 2 +- src/core/postgresqlstorage.cpp | 2 +- src/core/sqlauthenticator.cpp | 2 +- src/core/sqlitestorage.cpp | 2 +- src/core/sslserver.cpp | 2 +- src/qtui/debuglogwidget.cpp | 24 ++- src/qtui/debuglogwidget.h | 16 +- src/qtui/mainwin.cpp | 2 +- src/qtui/qtui.h | 6 +- src/qtui/qtuiapplication.cpp | 5 +- 30 files changed, 491 insertions(+), 310 deletions(-) create mode 100644 src/common/logmessage.cpp create mode 100644 src/common/logmessage.h diff --git a/src/client/client.cpp b/src/client/client.cpp index 32f599d3..c3c43851 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -114,8 +114,7 @@ Client::Client(QObject *parent) _messageProcessor(0), _coreAccountModel(new CoreAccountModel(this)), _coreConnection(new CoreConnection(this)), - _connected(false), - _debugLog(&_debugLogBuffer) + _connected(false) { _signalProxy->synchronize(_ircListHelper); } @@ -753,48 +752,3 @@ void Client::corePasswordChanged(PeerPtr, bool success) coreAccountModel()->save(); emit passwordChanged(success); } - - -#if QT_VERSION < 0x050000 -void Client::logMessage(QtMsgType type, const char *msg) -{ - fprintf(stderr, "%s\n", msg); - fflush(stderr); - if (type == QtFatalMsg) { - Quassel::logFatalMessage(msg); - } - else { - QString msgString = QString("%1\n").arg(msg); - - //Check to see if there is an instance around, else we risk recursions - //when calling instance() and creating new ones. - if (!instanceExists()) - return; - - instance()->_debugLog << msgString; - emit instance()->logUpdated(msgString); - } -} -#else -void Client::logMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg) -{ - Q_UNUSED(context); - - fprintf(stderr, "%s\n", msg.toLocal8Bit().constData()); - fflush(stderr); - if (type == QtFatalMsg) { - Quassel::logFatalMessage(msg.toLocal8Bit().constData()); - } - else { - QString msgString = QString("%1\n").arg(msg); - - //Check to see if there is an instance around, else we risk recursions - //when calling instance() and creating new ones. - if (!instanceExists()) - return; - - instance()->_debugLog << msgString; - emit instance()->logUpdated(msgString); - } -} -#endif diff --git a/src/client/client.h b/src/client/client.h index f8baa983..7850b0fc 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -167,13 +167,6 @@ public: emit showIgnoreList(ignoreRule); } -#if QT_VERSION < 0x050000 - static void logMessage(QtMsgType type, const char *msg); -#else - static void logMessage(QtMsgType, const QMessageLogContext&, const QString&); -#endif - static inline const QString &debugLog() { return instance()->_debugLogBuffer; } - void displayChannelList(NetworkId networkId) { emit showChannelList(networkId); } @@ -224,8 +217,6 @@ signals: void requestCreateNetwork(const NetworkInfo &info, const QStringList &persistentChannels = QStringList()); void requestRemoveNetwork(NetworkId); - void logUpdated(const QString &msg); - //! Emitted when a buffer has been marked as read /** This is currently triggered by setting lastSeenMsg, either local or remote, * or by bringing the window to front. @@ -327,9 +318,6 @@ private: bool _connected; - QString _debugLogBuffer; - QTextStream _debugLog; - QList > _userInputBuffer; friend class CoreConnection; diff --git a/src/client/clientauthhandler.cpp b/src/client/clientauthhandler.cpp index 34404c99..322f58ad 100644 --- a/src/client/clientauthhandler.cpp +++ b/src/client/clientauthhandler.cpp @@ -32,7 +32,7 @@ #include "client.h" #include "clientsettings.h" -#include "logger.h" +#include "logmessage.h" #include "peerfactory.h" #if QT_VERSION < 0x050000 diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index d330d2c1..caca1587 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -24,6 +24,7 @@ set(SOURCES irclisthelper.cpp ircuser.cpp logger.cpp + logmessage.cpp message.cpp messageevent.cpp network.cpp diff --git a/src/common/basichandler.cpp b/src/common/basichandler.cpp index df5eb99e..fe7531d1 100644 --- a/src/common/basichandler.cpp +++ b/src/common/basichandler.cpp @@ -20,10 +20,9 @@ #include "basichandler.h" +#include #include -#include "logger.h" - BasicHandler::BasicHandler(QObject *parent) : QObject(parent), _defaultHandler(-1), diff --git a/src/common/logger.cpp b/src/common/logger.cpp index 5462355b..ed8d8023 100644 --- a/src/common/logger.cpp +++ b/src/common/logger.cpp @@ -18,128 +18,234 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#include -#include -#include +#include #ifdef HAVE_SYSLOG # include #endif +#include +#include +#include +#include + #include "logger.h" #include "quassel.h" -Logger::~Logger() +namespace { + +QByteArray msgWithTime(const Logger::LogEntry &msg) { - log(); + return (msg.timeStamp.toString("yyyy-MM-dd hh:mm:ss ") + msg.message + "\n").toUtf8(); +}; + } -void Logger::log() +Logger::Logger(QObject *parent) + : QObject(parent) { - if (_logLevel < Quassel::logLevel()) - return; + static bool registered = []() { + qRegisterMetaType(); + return true; + }(); + Q_UNUSED(registered) - switch (_logLevel) { - case Quassel::DebugLevel: - _buffer.prepend("Debug: "); - break; - case Quassel::InfoLevel: - _buffer.prepend("Info: "); - break; - case Quassel::WarningLevel: - _buffer.prepend("Warning: "); - break; - case Quassel::ErrorLevel: - _buffer.prepend("Error: "); - break; - default: - break; - } + connect(this, SIGNAL(messageLogged(Logger::LogEntry)), this, SLOT(onMessageLogged(Logger::LogEntry))); -#ifdef HAVE_SYSLOG - if (Quassel::logToSyslog()) { - int prio; - switch (_logLevel) { - case Quassel::DebugLevel: - prio = LOG_DEBUG; - break; - case Quassel::InfoLevel: - prio = LOG_INFO; - break; - case Quassel::WarningLevel: - prio = LOG_WARNING; - break; - case Quassel::ErrorLevel: - prio = LOG_ERR; - break; - default: - prio = LOG_INFO; - break; +#if QT_VERSION < 0x050000 + qInstallMsgHandler(Logger::messageHandler); +#else + qInstallMessageHandler(Logger::messageHandler); +#endif +} + + +Logger::~Logger() +{ + // If we're not initialized yet, output pending messages so they don't get lost + if (!_initialized) { + for (auto &&message : _messages) { + std::cerr << msgWithTime(message).constData(); } - syslog(prio|LOG_USER, "%s", qPrintable(_buffer)); } -#endif +} + - // if we neither use syslog nor have a logfile we log to stdout +std::vector Logger::messages() const +{ + return _messages; +} + + +bool Logger::setup(bool keepMessages) +{ + _keepMessages = keepMessages; - if (Quassel::logFile() || !Quassel::logToSyslog()) { - _buffer.prepend(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss ")); + // Set maximum level for output (we still store/announce all messages for client-side filtering) + if (Quassel::isOptionSet("loglevel")) { + QString level = Quassel::optionValue("loglevel").toLower(); + if (level == "debug") + _outputLevel = LogLevel::Debug; + else if (level == "info") + _outputLevel = LogLevel::Info; + else if (level == "warning") + _outputLevel = LogLevel::Warning; + else if (level == "error") + _outputLevel = LogLevel::Error; + else { + qCritical() << qPrintable(tr("Invalid log level %1; supported are Debug|Info|Warning|Error").arg(level)); + return false; + } + } - QTextStream out(stdout); - if (Quassel::logFile() && Quassel::logFile()->isOpen()) { - _buffer.remove(QChar('\n')); - out.setDevice(Quassel::logFile()); + QString logfilename = Quassel::optionValue("logfile"); + if (!logfilename.isEmpty()) { + _logFile.setFileName(logfilename); + if (!_logFile.open(QFile::Append|QFile::Unbuffered|QFile::Text)) { + qCritical() << qPrintable(tr("Could not open log file \"%1\": %2").arg(logfilename, _logFile.errorString())); + } + } + if (!_logFile.isOpen()) { + if (!_logFile.open(stderr, QFile::WriteOnly|QFile::Unbuffered|QFile::Text)) { + qCritical() << qPrintable(tr("Cannot write to stderr: %1").arg(_logFile.errorString())); } + } + +#ifdef HAVE_SYSLOG + _syslogEnabled = Quassel::isOptionSet("syslog"); +#endif + + _initialized = true; - out << _buffer << endl; + // Now that we've setup our logging backends, output pending messages + for (auto &&message : _messages) { + outputMessage(message); } + if (!_keepMessages) { + _messages.clear(); + } + + return true; } #if QT_VERSION < 0x050000 -void Logger::logMessage(QtMsgType type, const char *msg) +void Logger::messageHandler(QtMsgType type, const char *message) +#else +void Logger::messageHandler(QtMsgType type, const QMessageLogContext &, const QString &message) +#endif +{ + Quassel::instance()->logger()->handleMessage(type, message); +} + + +void Logger::handleMessage(QtMsgType type, const QString &msg) { switch (type) { case QtDebugMsg: - Logger(Quassel::DebugLevel) << msg; + handleMessage(LogLevel::Debug, msg); break; +#if QT_VERSION >= 0x050500 + case QtInfoMsg: + handleMessage(LogLevel::Info, msg); + break; +#endif case QtWarningMsg: - Logger(Quassel::WarningLevel) << msg; + handleMessage(LogLevel::Warning, msg); break; case QtCriticalMsg: - Logger(Quassel::ErrorLevel) << msg; + handleMessage(LogLevel::Error, msg); break; case QtFatalMsg: - Logger(Quassel::ErrorLevel) << msg; - Quassel::logFatalMessage(msg); - return; + handleMessage(LogLevel::Fatal, msg); + break; } } -#else -void Logger::logMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg) + + +void Logger::handleMessage(LogLevel level, const QString &msg) { - Q_UNUSED(context) + QString logString; - switch (type) { - case QtDebugMsg: - Logger(Quassel::DebugLevel) << msg.toLocal8Bit().constData(); + switch (level) { + case LogLevel::Debug: + logString = "[Debug] "; break; -#if QT_VERSION >= 0x050500 - case QtInfoMsg: - Logger(Quassel::InfoLevel) << msg.toLocal8Bit().constData(); + case LogLevel::Info: + logString = "[Info ] "; break; -#endif - case QtWarningMsg: - Logger(Quassel::WarningLevel) << msg.toLocal8Bit().constData(); + case LogLevel::Warning: + logString = "[Warn ] "; break; - case QtCriticalMsg: - Logger(Quassel::ErrorLevel) << msg.toLocal8Bit().constData(); + case LogLevel::Error: + logString = "[Error] "; + break; + case LogLevel::Fatal: + logString = "[FATAL] "; break; - case QtFatalMsg: - Logger(Quassel::ErrorLevel) << msg.toLocal8Bit().constData(); - Quassel::logFatalMessage(msg.toLocal8Bit().constData()); - return; } + + // Use signal connection to make this method thread-safe + emit messageLogged({QDateTime::currentDateTime(), level, logString += msg}); } + + +void Logger::onMessageLogged(const LogEntry &message) +{ + if (_keepMessages) { + _messages.push_back(message); + } + + // If setup() wasn't called yet, just store the message - will be output later + if (_initialized) { + outputMessage(message); + } +} + + +void Logger::outputMessage(const LogEntry &message) +{ + if (message.logLevel < _outputLevel) { + return; + } + +#ifdef HAVE_SYSLOG + if (_syslogEnabled) { + int prio{LOG_INFO}; + switch (message.logLevel) { + case LogLevel::Debug: + prio = LOG_DEBUG; + break; + case LogLevel::Info: + prio = LOG_INFO; + break; + case LogLevel::Warning: + prio = LOG_WARNING; + break; + case LogLevel::Error: + prio = LOG_ERR; + break; + case LogLevel::Fatal: + prio = LOG_CRIT; + } + syslog(prio|LOG_USER, "%s", qPrintable(message.message)); + } #endif + + if (!_logFile.fileName().isEmpty() || !_syslogEnabled) { + _logFile.write(msgWithTime(message)); + } + +#ifndef Q_OS_MAC + // For fatal messages, write log to dump file + if (message.logLevel == LogLevel::Fatal) { + QFile dumpFile{Quassel::instance()->coreDumpFileName()}; + if (dumpFile.open(QIODevice::Append)) { + dumpFile.write(msgWithTime(message)); + dumpFile.close(); + } + } +#endif + +} diff --git a/src/common/logger.h b/src/common/logger.h index 33375fef..8c1f2f00 100644 --- a/src/common/logger.h +++ b/src/common/logger.h @@ -18,59 +18,99 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#ifndef LOGGER_H -#define LOGGER_H +#pragma once -#include -#include +#include -#include "quassel.h" -#include "types.h" +#include +#include +#include +#include +#include -class Logger +/** + * The Logger class encapsulates the various configured logging backends. + */ +class Logger : public QObject { + Q_OBJECT + public: - inline Logger(Quassel::LogLevel level) : _stream(&_buffer, QIODevice::WriteOnly), _logLevel(level) {} - ~Logger(); + Logger(QObject *parent = nullptr); + ~Logger() override; + + enum class LogLevel { + Debug, + Info, + Warning, + Error, + Fatal + }; + + struct LogEntry { + QDateTime timeStamp; + LogLevel logLevel; + QString message; + }; + + /** + * Initial setup, to be called ones command line options are available. + * + * Sets up the log file if appropriate. Outputs the log messages already accumulated since + * construction. If @c keepMessages is false, deletes the accumulated messages afterwards, + * and won't store further ones. + * + * @param keepMessages Whether messages should be kept + * @returns true, if initialization was successful + */ + bool setup(bool keepMessages); + + /** + * Accesses the stores log messages, e.g. for consumption by DebugLogWidget. + * + * @returns The accumuates log messages + */ + std::vector messages() const; #if QT_VERSION < 0x050000 - static void logMessage(QtMsgType type, const char *msg); + static void messageHandler(QtMsgType type, const char *message); #else - static void logMessage(QtMsgType, const QMessageLogContext&, const QString&); + static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message); #endif - template - inline Logger &operator<<(const T &value) { _stream << value << " "; return *this; } - inline Logger &operator<<(const QStringList &t) { _stream << t.join(" ") << " "; return *this; } - inline Logger &operator<<(bool t) { _stream << (t ? "true" : "false") << " "; return *this; } - -private: - void log(); - QTextStream _stream; - QString _buffer; - Quassel::LogLevel _logLevel; -}; + /** + * Takes the given message with the given log level, formats it and emits the @a messageLogged() signal. + * + * @note This method is thread-safe. + * + * @param logLevel The log leve of the message + * @param message The message + */ + void handleMessage(LogLevel logLevel, const QString &message); +signals: + /** + * Emitted whenever a message was logged. + * + * @param message The message that was logged + */ + void messageLogged(const Logger::LogEntry &message); -class quInfo : public Logger -{ -public: - inline quInfo() : Logger(Quassel::InfoLevel) {} -}; +private slots: + void onMessageLogged(const Logger::LogEntry &message); +private: + void handleMessage(QtMsgType type, const QString &message); + void outputMessage(const LogEntry &message); -class quWarning : public Logger -{ -public: - inline quWarning() : Logger(Quassel::WarningLevel) {} -}; - +private: + LogLevel _outputLevel{LogLevel::Info}; + QFile _logFile; + bool _syslogEnabled{false}; -class quError : public Logger -{ -public: - inline quError() : Logger(Quassel::ErrorLevel) {} + std::vector _messages; + bool _keepMessages{true}; + bool _initialized{false}; }; - -#endif +Q_DECLARE_METATYPE(Logger::LogEntry) diff --git a/src/common/logmessage.cpp b/src/common/logmessage.cpp new file mode 100644 index 00000000..1715cfbf --- /dev/null +++ b/src/common/logmessage.cpp @@ -0,0 +1,52 @@ +/*************************************************************************** + * Copyright (C) 2005-2018 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "logmessage.h" + +#include +#include +#include + +#include "quassel.h" + +LogMessage::LogMessage(Logger::LogLevel level) + : _stream(&_buffer, QIODevice::WriteOnly) + , _logLevel(level) +{ +} + + +LogMessage::~LogMessage() +{ + Quassel::instance()->logger()->handleMessage(_logLevel, _buffer); +} + + +LogMessage &LogMessage::operator<<(const QStringList &t) +{ + _stream << t.join(" ") << " "; + return *this; +} + + +LogMessage &LogMessage::operator<<(bool t) { + _stream << (t ? "true" : "false") << " "; + return *this; +} diff --git a/src/common/logmessage.h b/src/common/logmessage.h new file mode 100644 index 00000000..e1e908f5 --- /dev/null +++ b/src/common/logmessage.h @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (C) 2005-2018 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#pragma once + +#include +#include + +#include "logger.h" +#include "types.h" + +/** + * Class encapsulating a single log message. + * + * Very similar in concept to qDebug() and friends. + */ +class LogMessage +{ +public: + LogMessage(Logger::LogLevel level); + ~LogMessage(); + + template + LogMessage &operator<<(const T &value) { + _stream << value << " "; + return *this; + } + + LogMessage &operator<<(const QStringList &t); + LogMessage &operator<<(bool t); + +private: + QTextStream _stream; + QString _buffer; + Logger::LogLevel _logLevel; +}; + + +// The only reason for LogMessage and the helpers below to exist is the fact that Qt versions +// prior to 5.5 did not support the Info level. +// Once we can rely on Qt 5.5, they will be removed and replaced by the native Qt functions. + +/** + * Creates an info-level log message. + * + * @sa qInfo + */ +class quInfo : public LogMessage +{ +public: + quInfo() : LogMessage(Logger::LogLevel::Info) {} +}; + + +/** + * Creates a warning-level log message. + * + * @sa qWarning + */ +class quWarning : public LogMessage +{ +public: + quWarning() : LogMessage(Logger::LogLevel::Warning) {} +}; + + +/** + * Creates an error-level log message. + * + * @sa qCritical + */ +class quError : public LogMessage +{ +public: + quError() : LogMessage(Logger::LogLevel::Error) {} +}; diff --git a/src/common/main.cpp b/src/common/main.cpp index 628c1a83..3076eea5 100644 --- a/src/common/main.cpp +++ b/src/common/main.cpp @@ -78,6 +78,9 @@ int main(int argc, char **argv) umask(S_IRWXG | S_IRWXO); #endif + // Instantiate early, so log messages are handled + Quassel::instance(); + #if QT_VERSION < 0x050000 // All our source files are in UTF-8, and Qt5 even requires that QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); diff --git a/src/common/quassel.cpp b/src/common/quassel.cpp index 92b03e2a..5ceddb10 100644 --- a/src/common/quassel.cpp +++ b/src/common/quassel.cpp @@ -44,6 +44,7 @@ #include "bufferinfo.h" #include "identity.h" #include "logger.h" +#include "logmessage.h" #include "message.h" #include "network.h" #include "peer.h" @@ -61,6 +62,7 @@ Quassel *Quassel::instance() Quassel::Quassel() + : _logger{new Logger{this}} { } @@ -122,52 +124,19 @@ bool Quassel::init() return false; } - // Set up logging - if (isOptionSet("loglevel")) { - QString level = optionValue("loglevel").toLower(); - - if (level == "debug") - setLogLevel(DebugLevel); - else if (level == "info") - setLogLevel(InfoLevel); - else if (level == "warning") - setLogLevel(WarningLevel); - else if (level == "error") - setLogLevel(ErrorLevel); - else { - qWarning() << qPrintable(tr("Invalid log level %1; supported are Debug|Info|Warning|Error").arg(level)); - return false; - } - } - - QString logfilename = optionValue("logfile"); - if (!logfilename.isEmpty()) { - instance()->_logFile.reset(new QFile{logfilename}); - if (!logFile()->open(QIODevice::Append | QIODevice::Text)) { - qWarning() << qPrintable(tr("Could not open log file \"%1\": %2").arg(logfilename, logFile()->errorString())); - instance()->_logFile.reset(); - } - } -#ifdef HAVE_SYSLOG - instance()->_logToSyslog = isOptionSet("syslog"); -#endif + // Don't keep a debug log on the core + return instance()->logger()->setup(runMode() != RunMode::CoreOnly); +} -#if QT_VERSION < 0x050000 - qInstallMsgHandler(Logger::logMessage); -#else - qInstallMessageHandler(Logger::logMessage); -#endif - return true; +void Quassel::destroy() +{ } -void Quassel::destroy() +Logger *Quassel::logger() const { - if (logFile()) { - logFile()->close(); - instance()->_logFile.reset(); - } + return _logger; } @@ -429,45 +398,6 @@ bool Quassel::isOptionSet(const QString &key) } -Quassel::LogLevel Quassel::logLevel() -{ - return instance()->_logLevel; -} - - -void Quassel::setLogLevel(LogLevel logLevel) -{ - instance()->_logLevel = logLevel; -} - - -QFile *Quassel::logFile() { - return instance()->_logFile.get(); -} - - -bool Quassel::logToSyslog() -{ - return instance()->_logToSyslog; -} - - -void Quassel::logFatalMessage(const char *msg) -{ -#ifdef Q_OS_MAC - Q_UNUSED(msg) -#else - QFile dumpFile(instance()->coreDumpFileName()); - dumpFile.open(QIODevice::Append); - QTextStream dumpStream(&dumpFile); - - dumpStream << "Fatal: " << msg << '\n'; - dumpStream.flush(); - dumpFile.close(); -#endif -} - - const QString &Quassel::coreDumpFileName() { if (_coreDumpFileName.isEmpty()) { diff --git a/src/common/quassel.h b/src/common/quassel.h index 952f8fa8..85660afc 100644 --- a/src/common/quassel.h +++ b/src/common/quassel.h @@ -35,6 +35,8 @@ class QFile; +class Logger; + class Quassel : public QObject { // TODO Qt5: Use Q_GADGET @@ -146,6 +148,13 @@ public: static Quassel *instance(); + /** + * Provides access to the Logger instance. + * + * @returns The Logger instance + */ + Logger *logger() const; + static void setupBuildInfo(); static const BuildInfo &buildInfo(); static RunMode runMode(); @@ -182,20 +191,6 @@ public: static QString optionValue(const QString &option); static bool isOptionSet(const QString &option); - enum LogLevel { - DebugLevel, - InfoLevel, - WarningLevel, - ErrorLevel - }; - - static LogLevel logLevel(); - static void setLogLevel(LogLevel logLevel); - static QFile *logFile(); - static bool logToSyslog(); - - static void logFatalMessage(const char *msg); - using ReloadHandler = std::function; static void registerReloadHandler(ReloadHandler handler); @@ -204,6 +199,11 @@ public: static void registerQuitHandler(QuitHandler quitHandler); + const QString &coreDumpFileName(); + +signals: + void messageLogged(const QDateTime &timeStamp, const QString &msg); + protected: static bool init(); static void destroy(); @@ -223,8 +223,6 @@ private: void setupEnvironment(); void registerMetaTypes(); - const QString &coreDumpFileName(); - /** * Requests a reload of relevant runtime configuration. * @@ -257,12 +255,10 @@ private: QStringList _dataDirPaths; QString _translationDirPath; - LogLevel _logLevel{InfoLevel}; - bool _logToSyslog{false}; - std::unique_ptr _logFile; - std::shared_ptr _cliParser; + Logger *_logger; + std::vector _reloadHandlers; std::vector _quitHandlers; }; diff --git a/src/core/abstractsqlstorage.cpp b/src/core/abstractsqlstorage.cpp index 89169ee9..149aabb1 100644 --- a/src/core/abstractsqlstorage.cpp +++ b/src/core/abstractsqlstorage.cpp @@ -19,9 +19,6 @@ ***************************************************************************/ #include "abstractsqlstorage.h" -#include "quassel.h" - -#include "logger.h" #include #include @@ -29,6 +26,9 @@ #include #include +#include "logmessage.h" +#include "quassel.h" + int AbstractSqlStorage::_nextConnectionId = 0; AbstractSqlStorage::AbstractSqlStorage(QObject *parent) : Storage(parent), diff --git a/src/core/cipher.cpp b/src/core/cipher.cpp index a8232a3c..9bfc787f 100644 --- a/src/core/cipher.cpp +++ b/src/core/cipher.cpp @@ -13,7 +13,7 @@ */ #include "cipher.h" -#include "logger.h" +#include "logmessage.h" Cipher::Cipher() { diff --git a/src/core/core.cpp b/src/core/core.cpp index d596344c..5818e2fb 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -26,8 +26,8 @@ #include "coreauthhandler.h" #include "coresession.h" #include "coresettings.h" -#include "logger.h" #include "internalpeer.h" +#include "logmessage.h" #include "network.h" #include "postgresqlstorage.h" #include "quassel.h" diff --git a/src/core/coreauthhandler.cpp b/src/core/coreauthhandler.cpp index 6cccaf87..240954eb 100644 --- a/src/core/coreauthhandler.cpp +++ b/src/core/coreauthhandler.cpp @@ -25,7 +25,7 @@ #endif #include "core.h" -#include "logger.h" +#include "logmessage.h" using namespace Protocol; diff --git a/src/core/corebasichandler.cpp b/src/core/corebasichandler.cpp index 8c7539b1..a7a67b7a 100644 --- a/src/core/corebasichandler.cpp +++ b/src/core/corebasichandler.cpp @@ -21,7 +21,7 @@ #include "corebasichandler.h" #include "util.h" -#include "logger.h" +#include "logmessage.h" CoreBasicHandler::CoreBasicHandler(CoreNetwork *parent) : BasicHandler(parent), diff --git a/src/core/coresession.cpp b/src/core/coresession.cpp index 689f043e..200fadcc 100644 --- a/src/core/coresession.cpp +++ b/src/core/coresession.cpp @@ -44,7 +44,7 @@ #include "ircchannel.h" #include "ircparser.h" #include "ircuser.h" -#include "logger.h" +#include "logmessage.h" #include "messageevent.h" #include "remotepeer.h" #include "storage.h" diff --git a/src/core/coresessioneventprocessor.cpp b/src/core/coresessioneventprocessor.cpp index 76cddb3f..8fa70157 100644 --- a/src/core/coresessioneventprocessor.cpp +++ b/src/core/coresessioneventprocessor.cpp @@ -28,7 +28,7 @@ #include "ctcpevent.h" #include "ircevent.h" #include "ircuser.h" -#include "logger.h" +#include "logmessage.h" #include "messageevent.h" #include "netsplit.h" #include "quassel.h" diff --git a/src/core/identserver.cpp b/src/core/identserver.cpp index c3be8f51..5e728746 100644 --- a/src/core/identserver.cpp +++ b/src/core/identserver.cpp @@ -22,7 +22,7 @@ #include "corenetwork.h" #include "identserver.h" -#include "logger.h" +#include "logmessage.h" IdentServer::IdentServer(QObject *parent) : QObject(parent) diff --git a/src/core/ldapauthenticator.cpp b/src/core/ldapauthenticator.cpp index 620ae511..b4204404 100644 --- a/src/core/ldapauthenticator.cpp +++ b/src/core/ldapauthenticator.cpp @@ -28,7 +28,7 @@ #include "ldapauthenticator.h" -#include "logger.h" +#include "logmessage.h" #include "network.h" #include "quassel.h" diff --git a/src/core/postgresqlstorage.cpp b/src/core/postgresqlstorage.cpp index 16ab7c39..74d0b8fe 100644 --- a/src/core/postgresqlstorage.cpp +++ b/src/core/postgresqlstorage.cpp @@ -22,7 +22,7 @@ #include -#include "logger.h" +#include "logmessage.h" #include "network.h" #include "quassel.h" diff --git a/src/core/sqlauthenticator.cpp b/src/core/sqlauthenticator.cpp index 57a6aa1c..201fd95f 100644 --- a/src/core/sqlauthenticator.cpp +++ b/src/core/sqlauthenticator.cpp @@ -20,7 +20,7 @@ #include "sqlauthenticator.h" -#include "logger.h" +#include "logmessage.h" #include "network.h" #include "quassel.h" diff --git a/src/core/sqlitestorage.cpp b/src/core/sqlitestorage.cpp index db174cb4..15030150 100644 --- a/src/core/sqlitestorage.cpp +++ b/src/core/sqlitestorage.cpp @@ -22,7 +22,7 @@ #include -#include "logger.h" +#include "logmessage.h" #include "network.h" #include "quassel.h" diff --git a/src/core/sslserver.cpp b/src/core/sslserver.cpp index dd0792e9..183bbe18 100644 --- a/src/core/sslserver.cpp +++ b/src/core/sslserver.cpp @@ -26,8 +26,8 @@ #include -#include "logger.h" #include "quassel.h" +#include "logmessage.h" #ifdef HAVE_SSL diff --git a/src/qtui/debuglogwidget.cpp b/src/qtui/debuglogwidget.cpp index 975c6fda..83a5e090 100644 --- a/src/qtui/debuglogwidget.cpp +++ b/src/qtui/debuglogwidget.cpp @@ -20,22 +20,36 @@ #include "debuglogwidget.h" -#include "client.h" +#include "quassel.h" DebugLogWidget::DebugLogWidget(QWidget *parent) : QWidget(parent) { ui.setupUi(this); setAttribute(Qt::WA_DeleteOnClose, true); - ui.textEdit->setPlainText(Client::debugLog()); - connect(Client::instance(), SIGNAL(logUpdated(const QString &)), this, SLOT(logUpdated(const QString &))); + ui.textEdit->setReadOnly(true); + + connect(Quassel::instance()->logger(), SIGNAL(messageLogged(Logger::LogEntry)), SLOT(logUpdated(Logger::LogEntry))); + + QString content; + for (auto &&message : Quassel::instance()->logger()->messages()) { + content += toString(message); + } + ui.textEdit->setPlainText(content); + +} + + +QString DebugLogWidget::toString(const Logger::LogEntry &msg) +{ + return msg.timeStamp.toString("yyyy-MM-dd hh:mm:ss ") + msg.message + "\n"; } -void DebugLogWidget::logUpdated(const QString &msg) +void DebugLogWidget::logUpdated(const Logger::LogEntry &msg) { ui.textEdit->moveCursor(QTextCursor::End); - ui.textEdit->insertPlainText(msg); + ui.textEdit->insertPlainText(toString(msg)); ui.textEdit->moveCursor(QTextCursor::End); } diff --git a/src/qtui/debuglogwidget.h b/src/qtui/debuglogwidget.h index 9a1fa8ec..5bffad9b 100644 --- a/src/qtui/debuglogwidget.h +++ b/src/qtui/debuglogwidget.h @@ -18,8 +18,12 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#ifndef DEBUGLOGWIDGET_H -#define DEBUGLOGWIDGET_H +#pragma once + +#include +#include + +#include "logger.h" #include "ui_debuglogwidget.h" @@ -31,11 +35,11 @@ public: DebugLogWidget(QWidget *parent = 0); private slots: - void logUpdated(const QString &msg); + void logUpdated(const Logger::LogEntry &msg); + +private: + QString toString(const Logger::LogEntry &msg); private: Ui::DebugLogWidget ui; }; - - -#endif //DEBUGLOGWIDGET_H diff --git a/src/qtui/mainwin.cpp b/src/qtui/mainwin.cpp index fe1a0d06..99aaff3e 100644 --- a/src/qtui/mainwin.cpp +++ b/src/qtui/mainwin.cpp @@ -1974,7 +1974,7 @@ void MainWin::on_actionDebugMessageModel_triggered() void MainWin::on_actionDebugLog_triggered() { - DebugLogWidget *logWidget = new DebugLogWidget(0); + DebugLogWidget *logWidget = new DebugLogWidget(nullptr); // will be deleted on close logWidget->show(); } diff --git a/src/qtui/qtui.h b/src/qtui/qtui.h index 0e3cad7c..907fb31b 100644 --- a/src/qtui/qtui.h +++ b/src/qtui/qtui.h @@ -24,7 +24,9 @@ #include #include -#include +#include +#include +#include #if QT_VERSION >= 0x050000 # include @@ -57,6 +59,8 @@ public: inline static QtUiStyle *style(); inline static MainWin *mainWindow(); + QString debugLog() const; + static bool haveSystemTray(); /* Notifications */ diff --git a/src/qtui/qtuiapplication.cpp b/src/qtui/qtuiapplication.cpp index a16f66e5..c9475fee 100644 --- a/src/qtui/qtuiapplication.cpp +++ b/src/qtui/qtuiapplication.cpp @@ -87,10 +87,7 @@ QtUiApplication::QtUiApplication(int &argc, char **argv) Quassel::setRunMode(Quassel::ClientOnly); -#if QT_VERSION < 0x050000 - qInstallMsgHandler(Client::logMessage); -#else - qInstallMessageHandler(Client::logMessage); +#if QT_VERSION >= 0x050000 connect(this, &QGuiApplication::commitDataRequest, this, &QtUiApplication::commitData, Qt::DirectConnection); connect(this, &QGuiApplication::saveStateRequest, this, &QtUiApplication::saveState, Qt::DirectConnection); #endif -- 2.20.1