diff options
Diffstat (limited to 'src/buildtool/logging/logger.hpp')
-rw-r--r-- | src/buildtool/logging/logger.hpp | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/src/buildtool/logging/logger.hpp b/src/buildtool/logging/logger.hpp new file mode 100644 index 00000000..60742607 --- /dev/null +++ b/src/buildtool/logging/logger.hpp @@ -0,0 +1,123 @@ +#ifndef INCLUDED_SRC_BUILDTOOL_LOGGING_LOGGER_HPP +#define INCLUDED_SRC_BUILDTOOL_LOGGING_LOGGER_HPP + +#include <functional> +#include <memory> +#include <string> +#include <vector> + +#include "fmt/core.h" +#include "src/buildtool/logging/log_config.hpp" +#include "src/buildtool/logging/log_sink.hpp" + +class Logger { + public: + using MessageCreateFunc = std::function<std::string()>; + + /// \brief Create logger with sink instances from LogConfig::Sinks(). + explicit Logger(std::string name) noexcept + : name_{std::move(name)}, + log_limit_{LogConfig::LogLimit()}, + sinks_{LogConfig::Sinks()} {} + + /// \brief Create logger with new sink instances from specified factories. + Logger(std::string name, + std::vector<LogSinkFactory> const& factories) noexcept + : name_{std::move(name)}, log_limit_{LogConfig::LogLimit()} { + sinks_.reserve(factories.size()); + std::transform(factories.cbegin(), + factories.cend(), + std::back_inserter(sinks_), + [](auto& f) { return f(); }); + } + + ~Logger() noexcept = default; + Logger(Logger const&) noexcept = delete; + Logger(Logger&&) noexcept = delete; + auto operator=(Logger const&) noexcept -> Logger& = delete; + auto operator=(Logger&&) noexcept -> Logger& = delete; + + /// \brief Get logger name. + [[nodiscard]] auto Name() const& noexcept -> std::string const& { + return name_; + } + + /// \brief Get log limit. + [[nodiscard]] auto LogLimit() const noexcept -> LogLevel { + return log_limit_; + } + + /// \brief Set log limit. + void SetLogLimit(LogLevel level) noexcept { log_limit_ = level; } + + /// \brief Emit log message from string via this logger instance. + template <class... T_Args> + void Emit(LogLevel level, + std::string const& msg, + T_Args&&... args) const noexcept { + if (static_cast<int>(level) <= static_cast<int>(log_limit_)) { + FormatAndForward( + this, sinks_, level, msg, std::forward<T_Args>(args)...); + } + } + + /// \brief Emit log message from lambda via this logger instance. + void Emit(LogLevel level, + MessageCreateFunc const& msg_creator) const noexcept { + if (static_cast<int>(level) <= static_cast<int>(log_limit_)) { + FormatAndForward(this, sinks_, level, msg_creator()); + } + } + + /// \brief Log message from string via LogConfig's sinks and log limit. + template <class... T_Args> + static void Log(LogLevel level, + std::string const& msg, + T_Args&&... args) noexcept { + if (static_cast<int>(level) <= + static_cast<int>(LogConfig::LogLimit())) { + FormatAndForward(nullptr, + LogConfig::Sinks(), + level, + msg, + std::forward<T_Args>(args)...); + } + } + + /// \brief Log message from lambda via LogConfig's sinks and log limit. + static void Log(LogLevel level, + MessageCreateFunc const& msg_creator) noexcept { + if (static_cast<int>(level) <= + static_cast<int>(LogConfig::LogLimit())) { + FormatAndForward(nullptr, LogConfig::Sinks(), level, msg_creator()); + } + } + + private: + std::string name_{}; + LogLevel log_limit_{}; + std::vector<ILogSink::Ptr> sinks_{}; + + /// \brief Format message and forward to sinks. + template <class... T_Args> + static void FormatAndForward(Logger const* logger, + std::vector<ILogSink::Ptr> const& sinks, + LogLevel level, + std::string const& msg, + T_Args&&... args) noexcept { + if constexpr (sizeof...(T_Args) == 0) { + // forward to sinks + std::for_each(sinks.cbegin(), sinks.cend(), [&](auto& sink) { + sink->Emit(logger, level, msg); + }); + } + else { + // format the message + auto fmsg = fmt::format(msg, std::forward<T_Args>(args)...); + // recursive call without format arguments + FormatAndForward(logger, sinks, level, fmsg); + } + } +}; + +#endif // INCLUDED_SRC_BUILDTOOL_LOGGING_LOGGER_HPP |