#pragma once #ifdef USE_SPDLOG_LIBRARY #include #include #include "adc_traits.h" namespace adc { /* SPDLOG-library based advanced single/multithreaded logger */ class AdcSPDLOGLogger { public: // [year-month-day time.millisecs] [log-level]: log-message constexpr static std::string_view LOGGER_DEFAULT_FORMAT = "[%Y-%m-%d %T.%e] [%l]: %v"; typedef spdlog::level::level_enum loglevel_t; AdcSPDLOGLogger(std::shared_ptr logger, const traits::adc_input_char_range auto& pattern = LOGGER_DEFAULT_FORMAT) : _loggerSPtr(logger), _currentLogPattern(pattern) { _loggerSPtr->set_pattern(_currentLogPattern); } virtual ~AdcSPDLOGLogger() = default; void setLogLevel(loglevel_t log_level) { _loggerSPtr->set_level(log_level); } loglevel_t getLogLevel() const { return _loggerSPtr->level(); } void logMessage(loglevel_t level, std::string_view fmt, traits::formattable auto&&... args) { _loggerSPtr->log(level, fmt, std::forward(args)...); } // specialized for given level methods void logCritical(std::string_view fmt, traits::formattable auto&&... args) { logMessage(spdlog::level::critical, fmt, std::forward(args)...); } void logError(std::string_view fmt, traits::formattable auto&&... args) { logMessage(spdlog::level::err, fmt, std::forward(args)...); } void logWarn(std::string_view fmt, traits::formattable auto&&... args) { logMessage(spdlog::level::warn, fmt, std::forward(args)...); } void logInfo(std::string_view fmt, traits::formattable auto&&... args) { logMessage(spdlog::level::info, fmt, std::forward(args)...); } void logDebug(std::string_view fmt, traits::formattable auto&&... args) { logMessage(spdlog::level::debug, fmt, std::forward(args)...); } void logTrace(std::string_view fmt, traits::formattable auto&&... args) { logMessage(spdlog::level::trace, fmt, std::forward(args)...); } protected: static constexpr size_t LOGGER_DEFAULT_FORMAT_MARK_POS = 21; std::string _currentLogPattern; std::shared_ptr _loggerSPtr; // helper method void addMarkToPattern(traits::adc_input_char_range auto& mark, size_t pos = LOGGER_DEFAULT_FORMAT_MARK_POS) { std::string ptrn = _currentLogPattern.substr(0, pos); ptrn += " ["; std::ranges::copy(mark, std::back_inserter(ptrn)); ptrn += "] "; std::ranges::copy(_currentLogPattern | std::views::drop(pos), std::back_inserter(ptrn)); _currentLogPattern = ptrn; _loggerSPtr->set_pattern(_currentLogPattern); } }; template class AdcSpdlogGenericDecorator : public BaseT { protected: std::shared_ptr _logger; void* _thisAddress; std::string _currentPattern; public: constexpr static std::string_view LOGGER_DEFAULT_FORMAT = "[%Y-%m-%d %T.%e] [%l]: %v"; template AdcSpdlogGenericDecorator(const R& pattern, std::shared_ptr logger, BaseCtorArgTs&&... ctor_args) : BaseT(std::forward(ctor_args)...), _logger(logger), _thisAddress((void*)std::addressof(*this)), _currentPattern(pattern.begin(), pattern.end()) { _logger->set_pattern(_currentPattern); if (_logger->level() == spdlog::level::trace) { logMethodCalling(__PRETTY_FUNCTION__); // in trace } else { logMethodCalling("AdcSpdlogGenericDecorator", __FUNCTION__); // in debug } _logger->debug("set logger with {}", loggerInfo()); } template AdcSpdlogGenericDecorator(std::shared_ptr logger, BaseCtorArgTs&&... ctor_args) : AdcSpdlogGenericDecorator(LOGGER_DEFAULT_FORMAT, logger, std::forward(ctor_args)...) { } virtual ~AdcSpdlogGenericDecorator() { logMethodCalling("AdcSpdlogGenericDecorator", __FUNCTION__); // in debug _logger->flush(); } template void setPattern(const R& pattern) { logMethodCalling("AdcSpdlogGenericDecorator", __FUNCTION__); // in debug _currentPattern = {pattern.begin(), pattern.end()}; _logger->debug("set current logging pattern to: {}", _currentPattern); } std::string pattern() const { logMethodCalling(); return _currentPattern; } template void logMessage(spdlog::level::level_enum level, std::string_view fmt, ArgTs&&... args) { _logger->log(level, fmt, std::forward(args)...); } template void logCritical(std::string_view fmt, ArgTs&&... args) { _logger->log(spdlog::level::critical, fmt, std::forward(args)...); } template void logError(std::string_view fmt, ArgTs&&... args) { _logger->log(spdlog::level::err, fmt, std::forward(args)...); } template void logWarn(std::string_view fmt, ArgTs&&... args) { _logger->log(spdlog::level::warn, fmt, std::forward(args)...); } template void logInfo(std::string_view fmt, ArgTs&&... args) { _logger->log(spdlog::level::info, fmt, std::forward(args)...); } template void logDebug(std::string_view fmt, ArgTs&&... args) { _logger->log(spdlog::level::debug, fmt, std::forward(args)...); } template void logTrace(std::string_view fmt, ArgTs&&... args) { _logger->log(spdlog::level::trace, fmt, std::forward(args)...); } protected: // format string must contain two formating specifications: // 1 - logger name (string) // 2 - logging level (string) template R loggerInfo(std::string_view fmt) const { R info; std::format_to(std::back_inserter(info), fmt, _logger->name(), spdlog::level::to_string_view(_logger->level())); return info; } std::string loggerInfo() const { // return loggerInfo("name [{}] and log-level [{}]"); } void logMethodCalling(std::string_view class_name, std::string_view method_name, spdlog::level::level_enum level = spdlog::level::debug) const { _logger->log(level, "call {}::{} (this: {}, thread ID: {})", class_name, method_name, _thisAddress, std::this_thread::get_id()); } void logMethodCalling(std::string_view log_msg, spdlog::level::level_enum level = spdlog::level::debug) const { _logger->log(level, "call {} (this: {}, thread ID: {})", log_msg, _thisAddress, std::this_thread::get_id()); } }; template class AdcSpdlogGenericMarkDecorator : public AdcSpdlogGenericDecorator { protected: using base_t = AdcSpdlogGenericDecorator; public: constexpr static std::array LOGGER_DEFAULT_FORMAT{"[%Y-%m-%d %T.%e] [%l] ", "%v"}; template static std::string constructPattern(const R& mark, size_t after_idx = 0, const IR& format = LOGGER_DEFAULT_FORMAT) { std::string pattern; std::ranges::copy(format | std::views::take(after_idx + 1) | std::views::join, std::back_inserter(pattern)); std::ranges::copy(std::string_view("["), std::back_inserter(pattern)); std::ranges::copy(mark, std::back_inserter(pattern)); std::ranges::copy(std::string_view("]: "), std::back_inserter(pattern)); std::ranges::copy(format | std::views::drop(after_idx + 1) | std::views::join, std::back_inserter(pattern)); return pattern; } template AdcSpdlogGenericMarkDecorator(const R& mark, std::shared_ptr logger, BaseCtorArgTs&&... ctor_args) : base_t(constructPattern(mark), logger, std::forward(ctor_args)...) { } }; } // namespace adc #endif