diff --git a/src/MeoAssistant/Logger.hpp b/src/MeoAssistant/Logger.hpp index 3035bbd171..8f88a0ce12 100644 --- a/src/MeoAssistant/Logger.hpp +++ b/src/MeoAssistant/Logger.hpp @@ -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 + FlagLogger(std::mutex& mtx, std::ofstream& ofs, Args&&... buff) : trace_lock(mtx), m_ofs(ofs) + { + (*this << ... << std::forward(buff)); + } + + template + FlagLogger& operator<<(T&& arg) + { + if constexpr (std::same_as>) { + m_sep = std::forward(arg); + } + else if constexpr (std::same_as<_endl, std::remove_cvref_t>) { + m_ofs << std::endl; + } + else { + if (!is_first) { +#ifdef ASST_DEBUG + stream_put(m_ofs, m_sep.str); +#else + stream_put(m_ofs, m_sep.str); +#endif + } + else { + is_first = false; + } +#ifdef ASST_DEBUG + stream_put(m_ofs, std::forward(arg)); +#else + stream_put(m_ofs, std::forward(arg)); +#endif + } + return *this; + } + + private: + template + struct has_stream_insertion_operator : std::false_type + {}; + + template + struct has_stream_insertion_operator() << std::declval())>> + : std::true_type + {}; + + template + static Stream& stream_put(Stream& s, T&& v) + { + if constexpr (std::same_as>) { + if constexpr (ToAnsi) + s << utils::utf8_to_ansi(utils::path_to_utf8_string(std::forward(v))); + else + s << utils::path_to_utf8_string(std::forward(v)); + return s; + } + else if constexpr (std::convertible_to) { + if constexpr (ToAnsi) + s << utils::utf8_to_ansi(std::forward(v)); + else + s << std::forward(v); + return s; + } + else if constexpr (has_stream_insertion_operator::value) { + s << std::forward(v); + return s; + } + else if constexpr (ranges::input_range) { + s << "["; + std::string_view comma {}; + for (const auto& elem : std::forward(v)) { + s << comma; + stream_put(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 trace_lock; + std::ofstream& m_ofs; + }; + public: virtual ~Logger() override { flush(); } @@ -146,6 +249,40 @@ namespace asst } } + template + FlagLogger operator<<(T&& arg) + { + std::string_view level_str = "TRC"; + if constexpr (std::same_as>) { + 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::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>) { + return FlagLogger(m_trace_mutex, m_ofs, buff); + } + else { + return FlagLogger(m_trace_mutex, m_ofs, buff, arg); + } + } + private: friend class SingletonHolder; @@ -179,95 +316,10 @@ namespace asst trace("-----------------------------"); } - template - struct has_stream_insertion_operator : std::false_type - {}; - - template - struct has_stream_insertion_operator() << std::declval())>> - : std::true_type - {}; - - template - static Stream& stream_put(Stream& s, T&& v) + template + void log(std::string_view level, Args&&... args) { - if constexpr (std::same_as>) { - if constexpr (ToAnsi) - s << utils::utf8_to_ansi(utils::path_to_utf8_string(std::forward(v))); - else - s << utils::path_to_utf8_string(std::forward(v)); - return s; - } - else if constexpr (std::convertible_to) { - if constexpr (ToAnsi) - s << utils::utf8_to_ansi(std::forward(v)); - else - s << std::forward(v); - return s; - } - else if constexpr (has_stream_insertion_operator::value) { - s << std::forward(v); - return s; - } - else if constexpr (ranges::input_range) { - s << "["; - std::string_view comma {}; - for (const auto& elem : std::forward(v)) { - s << comma; - stream_put(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 - struct stream_put_line_impl; - - template - struct stream_put_line_impl - { - static constexpr Stream& apply(Stream& s, const separator&) - { - s << std::endl; - return s; - } - }; - - template - struct stream_put_line_impl - { - static constexpr Stream& apply(Stream& s, [[maybe_unused]] const separator& sep, First&& f, Rest&&... rs) - { - if constexpr (std::same_as, separator>) { - stream_put_line_impl::apply(s, std::forward(f), - std::forward(rs)...); - } - else { - s << sep.str; - stream_put(s, std::forward(f)); - stream_put_line_impl::apply(s, sep, std::forward(rs)...); - } - return s; - } - }; - - template - Stream& stream_put_line(Stream& s, First&& a0, Args&&... args) - { - stream_put(s, std::forward(a0)); - stream_put_line_impl::apply(s, separator::space, std::forward(args)...); - return s; + ((*this << Logger::level(level)) << ... << std::forward(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__)