chore: 用 operator<< 重构 Logger

This commit is contained in:
zzyyyl
2022-09-10 23:23:11 +08:00
parent 0db8d19561
commit 79ef3fa842

View File

@@ -63,6 +63,109 @@ namespace asst
std::string_view str;
};
struct _endl
{};
static constexpr _endl endl {};
class FlagLogger
{
public:
FlagLogger(std::mutex& mtx, std::ofstream& ofs) : trace_lock(mtx), m_ofs(ofs) {}
template <typename... Args>
FlagLogger(std::mutex& mtx, std::ofstream& ofs, Args&&... buff) : trace_lock(mtx), m_ofs(ofs)
{
(*this << ... << std::forward<Args>(buff));
}
template <typename T>
FlagLogger& operator<<(T&& arg)
{
if constexpr (std::same_as<separator, std::remove_cvref_t<T>>) {
m_sep = std::forward<T>(arg);
}
else if constexpr (std::same_as<_endl, std::remove_cvref_t<T>>) {
m_ofs << std::endl;
}
else {
if (!is_first) {
#ifdef ASST_DEBUG
stream_put<true>(m_ofs, m_sep.str);
#else
stream_put<false>(m_ofs, m_sep.str);
#endif
}
else {
is_first = false;
}
#ifdef ASST_DEBUG
stream_put<true>(m_ofs, std::forward<T>(arg));
#else
stream_put<false>(m_ofs, std::forward<T>(arg));
#endif
}
return *this;
}
private:
template <typename Stream, typename T, typename Enable = void>
struct has_stream_insertion_operator : std::false_type
{};
template <typename Stream, typename T>
struct has_stream_insertion_operator<Stream, T,
std::void_t<decltype(std::declval<Stream&>() << std::declval<T>())>>
: std::true_type
{};
template <bool ToAnsi, typename Stream, typename T>
static Stream& stream_put(Stream& s, T&& v)
{
if constexpr (std::same_as<std::filesystem::path, std::remove_cvref_t<T>>) {
if constexpr (ToAnsi)
s << utils::utf8_to_ansi(utils::path_to_utf8_string(std::forward<T>(v)));
else
s << utils::path_to_utf8_string(std::forward<T>(v));
return s;
}
else if constexpr (std::convertible_to<T, std::string_view>) {
if constexpr (ToAnsi)
s << utils::utf8_to_ansi(std::forward<T>(v));
else
s << std::forward<T>(v);
return s;
}
else if constexpr (has_stream_insertion_operator<Stream, T>::value) {
s << std::forward<T>(v);
return s;
}
else if constexpr (ranges::input_range<T>) {
s << "[";
std::string_view comma {};
for (const auto& elem : std::forward<T>(v)) {
s << comma;
stream_put<ToAnsi>(s, elem);
comma = ", ";
}
s << "]";
return s;
}
else {
ASST_STATIC_ASSERT_FALSE(
"unsupported type, one of the following expected\n"
"\t1. those can be converted to string;\n"
"\t2. those can be inserted to stream with operator<< directly;\n"
"\t3. container or nested container containing 1. 2. or 3. and iterable with range-based for",
Stream, T);
return s;
}
}
bool is_first = true;
separator m_sep { " " };
std::unique_lock<std::mutex> trace_lock;
std::ofstream& m_ofs;
};
public:
virtual ~Logger() override { flush(); }
@@ -146,6 +249,40 @@ namespace asst
}
}
template <typename T>
FlagLogger operator<<(T&& arg)
{
std::string_view level_str = "TRC";
if constexpr (std::same_as<Logger::level, std::remove_cvref_t<T>>) {
level_str = arg.str;
}
constexpr int buff_len = 128;
char buff[buff_len] = { 0 };
#ifdef _WIN32
#ifdef _MSC_VER
sprintf_s(buff, buff_len,
#else // ! _MSC_VER
sprintf(buff,
#endif // END _MSC_VER
"[%s][%s][Px%x][Tx%lx]", asst::utils::get_format_time().c_str(), level_str.data(), _getpid(),
::GetCurrentThreadId());
#else // ! _WIN32
sprintf(buff, "[%s][%s][Px%x][Tx%lx]", asst::utils::get_format_time().c_str(), level_str.data(), getpid(),
(unsigned long)(std::hash<std::thread::id> {}(std::this_thread::get_id())));
#endif // END _WIN32
if (!m_ofs || !m_ofs.is_open()) {
m_ofs = std::ofstream(m_log_path, std::ios::out | std::ios::app);
}
if constexpr (std::same_as<Logger::level, std::remove_cvref_t<T>>) {
return FlagLogger(m_trace_mutex, m_ofs, buff);
}
else {
return FlagLogger(m_trace_mutex, m_ofs, buff, arg);
}
}
private:
friend class SingletonHolder<Logger>;
@@ -179,95 +316,10 @@ namespace asst
trace("-----------------------------");
}
template <typename Stream, typename T, typename Enable = void>
struct has_stream_insertion_operator : std::false_type
{};
template <typename Stream, typename T>
struct has_stream_insertion_operator<Stream, T,
std::void_t<decltype(std::declval<Stream&>() << std::declval<T>())>>
: std::true_type
{};
template <bool ToAnsi, typename Stream, typename T>
static Stream& stream_put(Stream& s, T&& v)
template <typename... Args>
void log(std::string_view level, Args&&... args)
{
if constexpr (std::same_as<std::filesystem::path, std::remove_cvref_t<T>>) {
if constexpr (ToAnsi)
s << utils::utf8_to_ansi(utils::path_to_utf8_string(std::forward<T>(v)));
else
s << utils::path_to_utf8_string(std::forward<T>(v));
return s;
}
else if constexpr (std::convertible_to<T, std::string_view>) {
if constexpr (ToAnsi)
s << utils::utf8_to_ansi(std::forward<T>(v));
else
s << std::forward<T>(v);
return s;
}
else if constexpr (has_stream_insertion_operator<Stream, T>::value) {
s << std::forward<T>(v);
return s;
}
else if constexpr (ranges::input_range<T>) {
s << "[";
std::string_view comma {};
for (const auto& elem : std::forward<T>(v)) {
s << comma;
stream_put<ToAnsi>(s, elem);
comma = ", ";
}
s << "]";
return s;
}
else {
ASST_STATIC_ASSERT_FALSE(
"unsupported type, one of the following expected\n"
"\t1. those can be converted to string;\n"
"\t2. those can be inserted to stream with operator<< directly;\n"
"\t3. container or nested container containing 1. 2. or 3. and iterable with range-based for",
Stream, T);
}
}
template <bool ToAnsi, typename Stream, typename... Args>
struct stream_put_line_impl;
template <bool ToAnsi, typename Stream>
struct stream_put_line_impl<ToAnsi, Stream>
{
static constexpr Stream& apply(Stream& s, const separator&)
{
s << std::endl;
return s;
}
};
template <bool ToAnsi, typename Stream, typename First, typename... Rest>
struct stream_put_line_impl<ToAnsi, Stream, First, Rest...>
{
static constexpr Stream& apply(Stream& s, [[maybe_unused]] const separator& sep, First&& f, Rest&&... rs)
{
if constexpr (std::same_as<std::decay_t<First>, separator>) {
stream_put_line_impl<ToAnsi, Stream, Rest...>::apply(s, std::forward<First>(f),
std::forward<Rest>(rs)...);
}
else {
s << sep.str;
stream_put<ToAnsi>(s, std::forward<First>(f));
stream_put_line_impl<ToAnsi, Stream, Rest...>::apply(s, sep, std::forward<Rest>(rs)...);
}
return s;
}
};
template <bool ToAnsi = false, typename Stream, typename First, typename... Args>
Stream& stream_put_line(Stream& s, First&& a0, Args&&... args)
{
stream_put<ToAnsi>(s, std::forward<First>(a0));
stream_put_line_impl<ToAnsi, Stream, Args...>::apply(s, separator::space, std::forward<Args>(args)...);
return s;
((*this << Logger::level(level)) << ... << std::forward<Args>(args)) << endl;
}
inline static std::filesystem::path m_directory;
@@ -319,6 +371,11 @@ namespace asst
#define _CatVarNameWithLine(Var) _Cat(Var, __LINE__)
#define Log Logger::get_instance()
#define LogDebug Log << Logger::level::debug
#define LogTrace Log << Logger::level::trace
#define LogInfo Log << Logger::level::info
#define LogWarn Log << Logger::level::warn
#define LogError Log << Logger::level::error
#define LogTraceScope LoggerAux _CatVarNameWithLine(_func_aux_)
#define LogTraceFunction LogTraceScope(__FUNCTION__)
#define LogTraceFunctionWithArgs // how to do this?, like LogTraceScope(__FUNCTION__, __FUNCTION_ALL_ARGS__)