#pragma once #include #include #include "mcc_traits.h" namespace mcc::utils { using namespace std::literals; /* SPDLOG-library based advanced single/multithreaded logger */ class MccSpdlogLogger { public: // [year-month-day time.millisecs][log-level]: log-message constexpr static std::array LOGGER_DEFAULT_FORMAT = {"[%Y-%m-%d %T.%e]"sv, "[%l]"sv, ": "sv, "%v"sv}; typedef spdlog::level::level_enum loglevel_t; template MccSpdlogLogger(std::shared_ptr logger, const R& pattern_range = LOGGER_DEFAULT_FORMAT) : _currentLogPatternRange(), _currentLogPattern(), _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 ~MccSpdlogLogger() = default; void setLogLevel(loglevel_t log_level) { _loggerSPtr->set_level(log_level); } loglevel_t getLogLevel() const { return _loggerSPtr->level(); } void logMessage(loglevel_t 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 void logMessage(spdlog::level::level_enum level, spdlog::format_string_t fmt, ArgTs&&... args) { _loggerSPtr->log(level, fmt, std::forward(args)...); } template void logCritical(spdlog::format_string_t fmt, ArgTs&&... args) { _loggerSPtr->log(spdlog::level::critical, fmt, std::forward(args)...); } template void logError(spdlog::format_string_t fmt, ArgTs&&... args) { _loggerSPtr->log(spdlog::level::err, fmt, std::forward(args)...); } template void logWarn(spdlog::format_string_t fmt, ArgTs&&... args) { _loggerSPtr->log(spdlog::level::warn, fmt, std::forward(args)...); } template void logInfo(spdlog::format_string_t fmt, ArgTs&&... args) { _loggerSPtr->log(spdlog::level::info, fmt, std::forward(args)...); } template void logDebug(spdlog::format_string_t fmt, ArgTs&&... args) { _loggerSPtr->log(spdlog::level::debug, fmt, std::forward(args)...); } template void logTrace(spdlog::format_string_t fmt, ArgTs&&... args) { _loggerSPtr->log(spdlog::level::trace, fmt, std::forward(args)...); } protected: std::list _currentLogPatternRange; std::string _currentLogPattern; std::shared_ptr _loggerSPtr; // helper methods auto getThreadId() const { std::ostringstream st; st << std::this_thread::get_id(); return st.str(); } // 'after_idx' is 0-based index! void addMarkToPatternIdx(const traits::mcc_input_char_range auto& mark, size_t after_idx = 1) requires(!std::is_pointer_v>) { 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); } void addMarkToPatternIdx(const char* mark, size_t after_idx = 1) { addMarkToPatternIdx(std::string_view{mark}, after_idx); } }; } // namespace mcc::utils