From 7251f954597b91cedaf465d21bcdcc63bee9ce70 Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Tue, 12 Nov 2024 18:07:00 +0300 Subject: [PATCH] add AdcOstreamLogger class (std::basic_stream based multithread-safe simple logger) --- common/adc_utils.h | 82 ++++++++++++++++++++++++++++++++++++++++++ net/adc_net_concepts.h | 17 +++++++-- 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/common/adc_utils.h b/common/adc_utils.h index 9dbaed8..b4693cf 100644 --- a/common/adc_utils.h +++ b/common/adc_utils.h @@ -2,7 +2,9 @@ #include #include +#include #include +#include #include #include #include @@ -674,5 +676,85 @@ static constexpr size_t AdcFNV1aHash(const R& r) return hash; } +/* std::basic_ostream based multithread-safe simple logger */ + +template > +class AdcOstreamLogger +{ +public: + typedef CharT char_t; + typedef CharTraitsT char_traits_t; + + enum loglevel_t { NULL_LEVEL, ERROR_LEVEL, INFO_LEVEL, DEBUG_LEVEL }; + static constexpr std::array logLevelMark{"null", "error", "info", "debug"}; + + AdcOstreamLogger(std::basic_ostream& stream = std::cout, loglevel_t log_level = INFO_LEVEL) + : _logStream(stream), _currentLogLevel(log_level) + { + } + + AdcOstreamLogger(loglevel_t log_level) : _logStream(std::cout), _currentLogLevel(log_level) {} + + virtual ~AdcOstreamLogger() = default; + + void setLogLevel(loglevel_t log_level) + { + std::lock_guard lock(_logMutex); + + _currentLogLevel = log_level; + } + + loglevel_t getLogLevel() const + { + return _currentLogLevel; + } + + template + void logMessage(loglevel_t level, std::string_view fmt, Ts&&... args) + { + std::lock_guard lock(_logMutex); + + if (_currentLogLevel < level) + return; + + std::string s; + std::format_to(std::back_inserter(s), fmt, std::forward(args)...); + + const std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + + // format log-message in form: + // [YYYY-MM-DD HH:MM:SS][level] log-message + // + _logStream << std::put_time(std::localtime(&now), "[%F %T]") << "[" << logLevelMark[_currentLogLevel] << "] " + << s; + } + + + template + void logError(std::string_view fmt, Ts&&... args) + { + logMessage(ERROR_LEVEL, fmt, std::forward(args)...); + } + + template + void logInfo(std::string_view fmt, Ts&&... args) + { + logMessage(INFO_LEVEL, fmt, std::forward(args)...); + } + + template + void logDebug(std::string_view fmt, Ts&&... args) + { + logMessage(DEBUG_LEVEL, fmt, std::forward(args)...); + } + + +protected: + std::basic_ostream& _logStream; + loglevel_t _currentLogLevel; + + std::mutex _logMutex; +}; + } // namespace adc::utils diff --git a/net/adc_net_concepts.h b/net/adc_net_concepts.h index b35e570..fcbf4d0 100644 --- a/net/adc_net_concepts.h +++ b/net/adc_net_concepts.h @@ -227,12 +227,25 @@ concept adc_netsession_proto_c = /* LOGGER */ template -concept adc_logger_c = requires(LOGGERT log) { - // logging method must accept at least the single argument - formating string +concept adc_logger_c = requires(LOGGERT log, const LOGGERT log_const) { + typename LOGGERT::loglevel_t; + + log.setLogLevel(std::declval()); + { log_const.getLogLevel() } -> std::same_as; + + // logging method signature: + // void method(std::string_view fmt, traits::formattable auto&& args...) + + + // logging method must accept at least the single argument - formatting string log.logInfo(std::declval()); + // method must be defined at least for std::string as its argument log.logInfo(std::declval(), std::declval()); + log.logWarn(std::declval()); log.logWarn(std::declval(), std::declval()); + + log.logError(std::declval()); log.logError(std::declval(), std::declval()); };