302 lines
9.8 KiB
C++
302 lines
9.8 KiB
C++
#pragma once
|
|
|
|
#include <list>
|
|
#ifdef SNPLIB_SPDLOGGER
|
|
#include <spdlog/logger.h>
|
|
#include <spdlog/sinks/null_sink.h>
|
|
#include <spdlog/sinks/stdout_sinks.h>
|
|
#endif
|
|
|
|
#include "../concepts/snplib_concepts.h"
|
|
|
|
namespace snplib
|
|
{
|
|
|
|
/* snplib_logger_c-like class adaptor to use formating */
|
|
|
|
// template <snplib_logger_c LoggerT>
|
|
// struct snplib_logger_fmt_adaptor_t : public LoggerT {
|
|
// template<typename ...CtorArgTs>
|
|
// snplib_logger_fmt_adaptor_t(CtorArgTs&&... ctor_args): LoggerT(std::forward<CtorArgTs>(ctor_args)...) {}
|
|
|
|
// ~snplib_logger_fmt_adaptor_t() = default;
|
|
|
|
// template <std::formattable<char>... ArgTs>
|
|
// auto logInfo(std::format_string<ArgTs...> fmt, ArgTs&&... args)
|
|
// {
|
|
// return logInfo(std::format(fmt, std::forward<ArgTs>(args)...));
|
|
// }
|
|
|
|
// template <std::formattable<char>... ArgTs>
|
|
// auto logWarn(std::format_string<ArgTs...> fmt, ArgTs&&... args)
|
|
// {
|
|
// return logWarn(std::format(fmt, std::forward<ArgTs>(args)...));
|
|
// }
|
|
|
|
// template <std::formattable<char>... ArgTs>
|
|
// auto logDebug(std::format_string<ArgTs...> fmt, ArgTs&&... args)
|
|
// {
|
|
// return logDebug(std::format(fmt, std::forward<ArgTs>(args)...));
|
|
// }
|
|
|
|
// template <std::formattable<char>... ArgTs>
|
|
// auto logError(std::format_string<ArgTs...> fmt, ArgTs&&... args)
|
|
// {
|
|
// return logError(std::format(fmt, std::forward<ArgTs>(args)...));
|
|
// }
|
|
|
|
// template <std::formattable<char>... ArgTs>
|
|
// auto logTrace(std::format_string<ArgTs...> fmt, ArgTs&&... args)
|
|
// {
|
|
// return logTrace(std::format(fmt, std::forward<ArgTs>(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<spdlog::logger> _loggerSPtr;
|
|
std::list<std::string> _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<spdlog::logger> makeLoggerFromMark(std::string const& mark, std::string const& name)
|
|
{
|
|
if (mark == STDOUT_LOGGER_MARK) {
|
|
return std::make_shared<spdlog::stdout_logger_mt>(name);
|
|
} else if (mark == STDERR_LOGGER_MARK) {
|
|
return std::make_shared<spdlog::stderr_logger_mt>(name);
|
|
} else if (mark == NULL_LOGGER_MARK) {
|
|
return std::make_shared<spdlog::null_logger_mt>(name);
|
|
} else { // 'mark' is filename here
|
|
return std::make_shared<spdlog::basic_logger_mt>(name, mark);
|
|
}
|
|
}
|
|
|
|
/* some factory static methods */
|
|
|
|
template <std::ranges::input_range R = decltype(LOGGER_DEFAULT_FORMAT)>
|
|
requires snplib_input_char_range_c<std::ranges::range_value_t<R>>
|
|
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<spdlog::stdout_logger_mt>(logger_name), pattern_range);
|
|
}
|
|
|
|
template <std::ranges::input_range R = decltype(LOGGER_DEFAULT_FORMAT)>
|
|
requires snplib_input_char_range_c<std::ranges::range_value_t<R>>
|
|
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<spdlog::stderr_logger_mt>(logger_name), pattern_range);
|
|
}
|
|
|
|
|
|
template <std::ranges::input_range R = decltype(LOGGER_DEFAULT_FORMAT)>
|
|
requires snplib_input_char_range_c<std::ranges::range_value_t<R>>
|
|
static snplib_spdlog_logger_t makeNullLogger(std::string const& logger_name)
|
|
{
|
|
return snplib_spdlog_logger_t(std::make_shared<spdlog::null_logger_mt>(logger_name));
|
|
}
|
|
|
|
|
|
/* constructor and destructor */
|
|
|
|
template <std::ranges::input_range R = decltype(LOGGER_DEFAULT_FORMAT)>
|
|
requires snplib_input_char_range_c<std::ranges::range_value_t<R>>
|
|
snplib_spdlog_logger_t(std::shared_ptr<spdlog::logger> 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 <std::formattable<char>... ArgTs>
|
|
void logMessage(spdlog::level::level_enum level, spdlog::format_string_t<ArgTs...> fmt, ArgTs&&... args)
|
|
{
|
|
_loggerSPtr->log(level, fmt, std::forward<ArgTs>(args)...);
|
|
}
|
|
|
|
template <std::formattable<char>... ArgTs>
|
|
void logCritical(spdlog::format_string_t<ArgTs...> fmt, ArgTs&&... args)
|
|
{
|
|
_loggerSPtr->log(spdlog::level::critical, fmt, std::forward<ArgTs>(args)...);
|
|
}
|
|
|
|
template <std::formattable<char>... ArgTs>
|
|
void logError(spdlog::format_string_t<ArgTs...> fmt, ArgTs&&... args)
|
|
{
|
|
_loggerSPtr->log(spdlog::level::err, fmt, std::forward<ArgTs>(args)...);
|
|
}
|
|
|
|
template <std::formattable<char>... ArgTs>
|
|
void logWarn(spdlog::format_string_t<ArgTs...> fmt, ArgTs&&... args)
|
|
{
|
|
_loggerSPtr->log(spdlog::level::warn, fmt, std::forward<ArgTs>(args)...);
|
|
}
|
|
|
|
template <std::formattable<char>... ArgTs>
|
|
void logInfo(spdlog::format_string_t<ArgTs...> fmt, ArgTs&&... args)
|
|
{
|
|
_loggerSPtr->log(spdlog::level::info, fmt, std::forward<ArgTs>(args)...);
|
|
}
|
|
|
|
template <std::formattable<char>... ArgTs>
|
|
void logDebug(spdlog::format_string_t<ArgTs...> fmt, ArgTs&&... args)
|
|
{
|
|
_loggerSPtr->log(spdlog::level::debug, fmt, std::forward<ArgTs>(args)...);
|
|
}
|
|
|
|
template <std::formattable<char>... ArgTs>
|
|
void logTrace(spdlog::format_string_t<ArgTs...> fmt, ArgTs&&... args)
|
|
{
|
|
_loggerSPtr->log(spdlog::level::trace, fmt, std::forward<ArgTs>(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<std::decay_t<decltype(mark)>>)
|
|
{
|
|
if constexpr (std::is_pointer_v<std::decay_t<decltype(mark)>>) {
|
|
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<snplib_spdlog_logger_t>);
|
|
|
|
#endif
|
|
|
|
} // namespace snplib
|