add AdcOstreamLogger class (std::basic_stream based multithread-safe

simple logger)
This commit is contained in:
Timur A. Fatkhullin 2024-11-12 18:07:00 +03:00
parent 9769c24005
commit 7251f95459
2 changed files with 97 additions and 2 deletions

View File

@ -2,7 +2,9 @@
#include <algorithm> #include <algorithm>
#include <charconv> #include <charconv>
#include <iostream>
#include <limits> #include <limits>
#include <mutex>
#include <ranges> #include <ranges>
#include <regex> #include <regex>
#include <utility> #include <utility>
@ -674,5 +676,85 @@ static constexpr size_t AdcFNV1aHash(const R& r)
return hash; return hash;
} }
/* std::basic_ostream based multithread-safe simple logger */
template <typename CharT = char, typename CharTraitsT = std::char_traits<CharT>>
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<CharT, CharTraitsT>& 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<std::mutex> lock(_logMutex);
_currentLogLevel = log_level;
}
loglevel_t getLogLevel() const
{
return _currentLogLevel;
}
template <traits::formattable... Ts>
void logMessage(loglevel_t level, std::string_view fmt, Ts&&... args)
{
std::lock_guard<std::mutex> lock(_logMutex);
if (_currentLogLevel < level)
return;
std::string s;
std::format_to(std::back_inserter(s), fmt, std::forward<Ts>(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 <traits::formattable... Ts>
void logError(std::string_view fmt, Ts&&... args)
{
logMessage(ERROR_LEVEL, fmt, std::forward<Ts>(args)...);
}
template <traits::formattable... Ts>
void logInfo(std::string_view fmt, Ts&&... args)
{
logMessage(INFO_LEVEL, fmt, std::forward<Ts>(args)...);
}
template <traits::formattable... Ts>
void logDebug(std::string_view fmt, Ts&&... args)
{
logMessage(DEBUG_LEVEL, fmt, std::forward<Ts>(args)...);
}
protected:
std::basic_ostream<CharT, CharTraitsT>& _logStream;
loglevel_t _currentLogLevel;
std::mutex _logMutex;
};
} // namespace adc::utils } // namespace adc::utils

View File

@ -227,12 +227,25 @@ concept adc_netsession_proto_c =
/* LOGGER */ /* LOGGER */
template <typename LOGGERT> template <typename LOGGERT>
concept adc_logger_c = requires(LOGGERT log) { concept adc_logger_c = requires(LOGGERT log, const LOGGERT log_const) {
// logging method must accept at least the single argument - formating string typename LOGGERT::loglevel_t;
log.setLogLevel(std::declval<typename LOGGERT::loglevel_t>());
{ log_const.getLogLevel() } -> std::same_as<typename LOGGERT::loglevel_t>;
// 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<std::string_view>()); log.logInfo(std::declval<std::string_view>());
// method must be defined at least for std::string as its argument
log.logInfo(std::declval<std::string_view>(), std::declval<std::string>()); log.logInfo(std::declval<std::string_view>(), std::declval<std::string>());
log.logWarn(std::declval<std::string_view>());
log.logWarn(std::declval<std::string_view>(), std::declval<std::string>()); log.logWarn(std::declval<std::string_view>(), std::declval<std::string>());
log.logError(std::declval<std::string_view>());
log.logError(std::declval<std::string_view>(), std::declval<std::string>()); log.logError(std::declval<std::string_view>(), std::declval<std::string>());
}; };