diff --git a/src/Lib/Log.cc b/src/Lib/Log.cc index 35d84b25e3453026386a144b5237b52bf7f8129b..5c97d0c8432145aaacc46531a399acf944f35095 100644 --- a/src/Lib/Log.cc +++ b/src/Lib/Log.cc @@ -5,8 +5,8 @@ namespace Vivy { LogSinkDispatcher::~LogSinkDispatcher() noexcept {} -StderrLogSinkDispatcher::StderrLogSinkDispatcher(LogSink *const sink) noexcept - : LogSinkDispatcher(sink, std::string_view{ "stderr" }) +StderrLogSinkDispatcher::StderrLogSinkDispatcher() noexcept + : LogSinkDispatcher(std::string_view{ "stderr" }) { } @@ -14,14 +14,15 @@ void StderrLogSinkDispatcher::handleLogMessage(const std::string_view category, const LogMessage &msg) noexcept { - std::cerr << '[' << category << ']' << msg.getTextBuffer() << '\n'; + std::cerr << '[' << category << "] " << msg.getTextBuffer() << '\n'; } } // Vivy::LogSink implementation namespace Vivy { -LogSink::~LogSink() noexcept {} +// Flush all messages before exiting +LogSink::~LogSink() noexcept { flush(); } // Get the log message from the logger and add it to the sink's queue. void @@ -53,11 +54,11 @@ LogSink::newSink() noexcept return std::make_shared<makeSharedEnabler>(); } -// void -// LogSink::registerLogDispatcher(std::shared_ptr<LogSinkDispatcher> dispatcher) noexcept -// { -// logDispatchers.push_back(dispatcher); -// } +void +LogSink::registerLogDispatcher(std::shared_ptr<LogSinkDispatcher> dispatcher) noexcept +{ + logDispatchers.push_back(dispatcher); +} } // Vivy::Logger implementation @@ -78,8 +79,6 @@ Logger::logEvent(const char *fileName, const char *functionName, const int lineN .severity = logSeverity, .lineNumberInFile = lineNumber }); } - -Logger::~Logger() noexcept {} } // Vivy::LogMessage implementation diff --git a/src/Lib/Log.hh b/src/Lib/Log.hh index 5d507dafa7a3677caa18a74dacb3b6376c0fce62..dcb33f6bc2b9922c96cbb6afa5d84e623bb11b2f 100644 --- a/src/Lib/Log.hh +++ b/src/Lib/Log.hh @@ -2,7 +2,6 @@ #include "Utils.hh" -#define VIVY_NEW_LOG_SINK() LogSink::newSink() #define VIVY_GET_LOGGER(sink, cat) std::make_shared<Logger>(sink.get(), cat) #define VIVY_LOG_WITH_LEVEL(log, level) log->logEvent(__FILE__, __func__, __LINE__, level) #define VIVY_LOG_WARN(log) VIVY_LOG_WITH_LEVEL(log, LogLevel::Warning) @@ -11,7 +10,9 @@ #define VIVY_LOG_ERR(log) VIVY_LOG_WITH_LEVEL(log, LogLevel::Error) #define VIVY_LOG_FATAL(log) VIVY_LOG_WITH_LEVEL(log, LogLevel::Critical) -#define VIVY_DCL_LOG_SINK(sink) std::shared_ptr<LogSink> sink{ VIVY_NEW_LOG_SINK() }; +#define VIVY_DCL_LOG_SINK(sink) std::shared_ptr<LogSink> sink{ LogSink::newSink() }; +#define VIVY_DCL_LOG_DISPATCH(sink, name, dispatch) \ + std::shared_ptr<dispatch> name{ sink->newDispatcher<dispatch>() }; #define VIVY_LOGGABLE_OBJECT(sink, name, logger) \ std::shared_ptr<Logger> logger{ VIVY_GET_LOGGER(sink, name) }; \ @@ -41,6 +42,35 @@ enum class LogLevel : int { None = std::numeric_limits<int>::min() // In option setup to disable logs }; +// A LogSinkDispatcher will excavate LogMessages from the Sink and do something +// with them (save to a file, display in stderr/Vivy console, etc). +class LogSinkDispatcher { + VIVY_UNMOVABLE_OBJECT(LogSinkDispatcher) + + const std::string dispatcherName; + +protected: + explicit LogSinkDispatcher(const std::string_view name) noexcept + : dispatcherName(name) + { + } + +public: + const std::string_view getDispatcherName() const noexcept { return dispatcherName; } + virtual ~LogSinkDispatcher() noexcept; + + virtual void handleLogMessage(const std::string_view, const LogMessage &) noexcept = 0; +}; + +// The stderr dispatcher for logs +class StderrLogSinkDispatcher : public LogSinkDispatcher { + VIVY_UNMOVABLE_OBJECT(StderrLogSinkDispatcher) + +public: + explicit StderrLogSinkDispatcher() noexcept; + void handleLogMessage(const std::string_view, const LogMessage &) noexcept override; +}; + // LogSink is the parent logger. It will recieve messages and display them to a // console or to std::cerr or to a file, etc. The save to over file, etc will // be donne by the LogSinkDispatcher. @@ -53,9 +83,18 @@ public: static std::shared_ptr<LogSink> newSink() noexcept; ~LogSink() noexcept; + void registerLogDispatcher(std::shared_ptr<LogSinkDispatcher>) noexcept; void recieveLogMessage(const Logger *const, LogMessage &&) noexcept; void flush() noexcept; + template <Derived<LogSinkDispatcher> DispatcherType> + std::shared_ptr<DispatcherType> newDispatcher() noexcept + { + std::shared_ptr<DispatcherType> dispatch = std::make_shared<DispatcherType>(); + registerLogDispatcher(dispatch); + return dispatch; + } + private: std::mutex messageQueueLock{}; std::vector<std::tuple<const std::string_view, LogMessage>> messageQueue; @@ -106,28 +145,6 @@ public: LogMessage &operator<<(const long) noexcept; }; -// A LogSinkDispatcher will excavate LogMessages from the Sink and do something -// with them (save to a file, display in stderr/Vivy console, etc). -class LogSinkDispatcher : public std::enable_shared_from_this<LogSinkDispatcher> { - VIVY_UNMOVABLE_OBJECT(LogSinkDispatcher) - - const std::string dispatcherName; - -protected: - explicit LogSinkDispatcher(LogSink *const, const std::string_view name) noexcept - : dispatcherName(name) - { - std::shared_ptr<LogSinkDispatcher> self = shared_from_this(); - // sink->registerLogDispatcher(self); - } - -public: - const std::string_view getDispatcherName() const noexcept { return dispatcherName; } - virtual ~LogSinkDispatcher() noexcept; - - virtual void handleLogMessage(const std::string_view, const LogMessage &) noexcept = 0; -}; - // A logger class, a client to LogSink. Will generate and send instances of // LogMessage. class Logger final : public std::enable_shared_from_this<Logger> { @@ -136,44 +153,19 @@ class Logger final : public std::enable_shared_from_this<Logger> { LogSink *const parentLogSink; const std::string logCategory; - static std::string anyStringToStdString(StringType auto const &str) noexcept - { - std::string ret; - std::size_t i; - const std::size_t size = str.size(); - ret.resize(size); - for (i = 0; i < size && str[i]; ++i) - ret[i] = str[i]; - ret.resize(i); - return ret; - } - public: // Templated constructor, construct from anything that can be considered as // a string. explicit Logger(LogSink *const sink, const StringType auto category) noexcept : parentLogSink(sink) - , logCategory(anyStringToStdString(category)) + , logCategory(Utils::anyStringToStdString(category)) { } - ~Logger() noexcept; - - const std::string_view getCategoryView() const noexcept - { - return std::string_view{ logCategory }; - } + const std::string_view getCategoryView() const noexcept { return logCategory; } void sendLogMessage(LogMessage &&) const noexcept; LogMessage logEvent(const char *fileName, const char *functionName, const int lineNumber, const LogLevel) noexcept; }; - -class StderrLogSinkDispatcher : public LogSinkDispatcher { - VIVY_UNMOVABLE_OBJECT(StderrLogSinkDispatcher) - -public: - explicit StderrLogSinkDispatcher(LogSink *const sink) noexcept; - void handleLogMessage(const std::string_view, const LogMessage &) noexcept override; -}; } diff --git a/src/Lib/Utils.hh b/src/Lib/Utils.hh index ff65ad6d5c475aa4ad1572db9cfea1aea21a2dd6..6346183b710e520aac0cf0eb43aae8bdfcd07450 100644 --- a/src/Lib/Utils.hh +++ b/src/Lib/Utils.hh @@ -123,7 +123,7 @@ uniqAndSort(std::vector<T> &vec) noexcept } // WARN: The V1 and V2 vectors need to be sorted before calling this function. -template <typename T> inline std::vector<T> +template <typename T> static inline std::vector<T> sortedSetDifference(const std::vector<T> &v1, const std::vector<T> &v2) { std::vector<T> res{}; @@ -136,6 +136,19 @@ sortedSetDifference(const std::vector<T> &v1, const std::vector<T> &v2) return res; } +static inline std::string +anyStringToStdString(StringType auto const &str) noexcept +{ + std::string ret; + std::size_t i; + const std::size_t size = str.size(); + ret.resize(size); + for (i = 0; i < size && str[i]; ++i) + ret[i] = str[i]; + ret.resize(i); + return ret; +} + enum class DocumentType : quint64 { /* Basic types */ Vivy = (1 << 1), diff --git a/src/VivyApplication.hh b/src/VivyApplication.hh index 493ab004d60b2f3d9bdc5c6935516e5975f5ad06..ca1254ed08e9fccfc2d3357fa94c22e448b22677 100644 --- a/src/VivyApplication.hh +++ b/src/VivyApplication.hh @@ -42,6 +42,7 @@ class MainWindow; class VivyApplication : public QApplication { Q_OBJECT VIVY_DCL_LOG_SINK(logSink) + VIVY_DCL_LOG_DISPATCH(logSink, stderrLogDispathcer, StderrLogSinkDispatcher) VIVY_LOGGABLE_OBJECT(logSink, std::string_view("APPLICATION"), logger) public: