#pragma once #include #ifdef SNPLIB_SPDLOGGER #include #include #include #endif #include "../concepts/snplib_concepts.h" namespace snplib { /* snplib_logger_c-like class adaptor to use formating */ // template // struct snplib_logger_fmt_adaptor_t : public LoggerT { // template // snplib_logger_fmt_adaptor_t(CtorArgTs&&... ctor_args): LoggerT(std::forward(ctor_args)...) {} // ~snplib_logger_fmt_adaptor_t() = default; // template ... ArgTs> // auto logInfo(std::format_string fmt, ArgTs&&... args) // { // return logInfo(std::format(fmt, std::forward(args)...)); // } // template ... ArgTs> // auto logWarn(std::format_string fmt, ArgTs&&... args) // { // return logWarn(std::format(fmt, std::forward(args)...)); // } // template ... ArgTs> // auto logDebug(std::format_string fmt, ArgTs&&... args) // { // return logDebug(std::format(fmt, std::forward(args)...)); // } // template ... ArgTs> // auto logError(std::format_string fmt, ArgTs&&... args) // { // return logError(std::format(fmt, std::forward(args)...)); // } // template ... ArgTs> // auto logTrace(std::format_string fmt, ArgTs&&... args) // { // return logTrace(std::format(fmt, std::forward(args)...)); // } // }; /* a NULL-logger */ struct snplib_null_logger_t { void logInfo(std::string const&) {} void logWarn(std::string const&) {} void logDebug(std::string const&) {} void logError(std::string const&) {} void logTrace(std::string const&) {} }; #ifdef SNPLIB_SPDLOGGER /* SPDLOG-library based advanced single/multithreaded logger */ class snplib_spdlog_logger_t { protected: std::shared_ptr _loggerSPtr; std::list _currentLogPatternRange{}; std::string _currentLogPattern{}; public: // [year-month-day time.millisecs][log-level]: log-message constexpr static std::array LOGGER_DEFAULT_FORMAT = {std::string_view{"[%Y-%m-%d %T.%e]"}, std::string_view{"[%l]"}, std::string_view{": "}, std::string_view{"%v"}}; // special logger names constexpr static std::string_view STDOUT_LOGGER_MARK{"stdout"}; constexpr static std::string_view STDERR_LOGGER_MARK{"stderr"}; constexpr static std::string_view NULL_LOGGER_MARK{"null"}; /* helper method */ static std::shared_ptr makeLoggerFromMark(std::string const& mark, std::string const& name) { if (mark == STDOUT_LOGGER_MARK) { return std::make_shared(name); } else if (mark == STDERR_LOGGER_MARK) { return std::make_shared(name); } else if (mark == NULL_LOGGER_MARK) { return std::make_shared(name); } else { // 'mark' is filename here return std::make_shared(name, mark); } } /* some factory static methods */ template requires snplib_input_char_range_c> static snplib_spdlog_logger_t makeConsoleLogger(std::string const& logger_name, R const& pattern_range = LOGGER_DEFAULT_FORMAT) { return snplib_spdlog_logger_t(std::make_shared(logger_name), pattern_range); } template requires snplib_input_char_range_c> static snplib_spdlog_logger_t makeConsoleErrLogger(std::string const& logger_name, R const& pattern_range = LOGGER_DEFAULT_FORMAT) { return snplib_spdlog_logger_t(std::make_shared(logger_name), pattern_range); } template requires snplib_input_char_range_c> static snplib_spdlog_logger_t makeNullLogger(std::string const& logger_name) { return snplib_spdlog_logger_t(std::make_shared(logger_name)); } /* constructor and destructor */ template requires snplib_input_char_range_c> snplib_spdlog_logger_t(std::shared_ptr logger, R const& pattern_range = LOGGER_DEFAULT_FORMAT) : _loggerSPtr(logger) { if (std::distance(pattern_range.begin(), pattern_range.end())) { std::ranges::copy( pattern_range | std::views::transform([](const auto& el) { return std::string(el.begin(), el.end()); }), std::back_inserter(_currentLogPatternRange)); } else { std::ranges::copy(LOGGER_DEFAULT_FORMAT | std::views::transform([](const auto& el) { return std::string(el.begin(), el.end()); }), std::back_inserter(_currentLogPatternRange)); } std::ranges::copy(std::views::join(_currentLogPatternRange), std::back_inserter(_currentLogPattern)); _loggerSPtr->set_pattern(_currentLogPattern); } virtual ~snplib_spdlog_logger_t() = default; void setLoglevel(spdlog::level::level_enum level) { _loggerSPtr->set_level(level); } spdlog::level::level_enum logLevel() const { return _loggerSPtr->level(); } void setFlushOn(spdlog::level::level_enum level) { _loggerSPtr->flush_on(level); } spdlog::level::level_enum flushOn() const { return _loggerSPtr->flush_level(); } void flush() { _loggerSPtr->flush(); } void logMessage(spdlog::level::level_enum level, const std::string& msg) { _loggerSPtr->log(level, msg); } // specialized for given level methods void logCritical(const std::string& msg) { logMessage(spdlog::level::critical, msg); } void logError(const std::string& msg) { logMessage(spdlog::level::err, msg); } void logWarn(const std::string& msg) { logMessage(spdlog::level::warn, msg); } void logInfo(const std::string& msg) { logMessage(spdlog::level::info, msg); } void logDebug(const std::string& msg) { logMessage(spdlog::level::debug, msg); } void logTrace(const std::string& msg) { logMessage(spdlog::level::trace, msg); } template ... ArgTs> void logMessage(spdlog::level::level_enum level, spdlog::format_string_t fmt, ArgTs&&... args) { _loggerSPtr->log(level, fmt, std::forward(args)...); } template ... ArgTs> void logCritical(spdlog::format_string_t fmt, ArgTs&&... args) { _loggerSPtr->log(spdlog::level::critical, fmt, std::forward(args)...); } template ... ArgTs> void logError(spdlog::format_string_t fmt, ArgTs&&... args) { _loggerSPtr->log(spdlog::level::err, fmt, std::forward(args)...); } template ... ArgTs> void logWarn(spdlog::format_string_t fmt, ArgTs&&... args) { _loggerSPtr->log(spdlog::level::warn, fmt, std::forward(args)...); } template ... ArgTs> void logInfo(spdlog::format_string_t fmt, ArgTs&&... args) { _loggerSPtr->log(spdlog::level::info, fmt, std::forward(args)...); } template ... ArgTs> void logDebug(spdlog::format_string_t fmt, ArgTs&&... args) { _loggerSPtr->log(spdlog::level::debug, fmt, std::forward(args)...); } template ... ArgTs> void logTrace(spdlog::format_string_t fmt, ArgTs&&... args) { _loggerSPtr->log(spdlog::level::trace, fmt, std::forward(args)...); } // 'after_idx' is 0-based index! void addMarkToPatternIdx(snplib_input_char_range_c auto&& mark, size_t after_idx = 1) requires(!std::is_pointer_v>) { if constexpr (std::is_pointer_v>) { addMarkToPatternIdx(std::string_view(mark), after_idx); } else { if (!std::distance(mark.begin(), mark.end())) { return; } auto it = _currentLogPatternRange.begin(); size_t idx = 0; while (it != _currentLogPatternRange.end()) { ++it; if (idx == after_idx) break; ++idx; } _currentLogPatternRange.emplace(it, mark.begin(), mark.end()); _currentLogPattern.clear(); std::ranges::copy(std::views::join(_currentLogPatternRange), std::back_inserter(_currentLogPattern)); _loggerSPtr->set_pattern(_currentLogPattern); } } }; static_assert(snplib_logger_c); #endif } // namespace snplib