// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include "spdlog/details/fmt_helper.h" #include #include #define SPDLOG_CATCH_AND_HANDLE \ catch (const std::exception &ex) \ { \ err_handler_(ex.what()); \ } \ catch (...) \ { \ err_handler_("Unknown exception in logger"); \ } // create logger with given name, sinks and the default pattern formatter // all other ctors will call this one template inline spdlog::logger::logger(std::string logger_name, It begin, It end) : name_(std::move(logger_name)) , sinks_(begin, end) { } // ctor with sinks as init list inline spdlog::logger::logger(std::string logger_name, sinks_init_list sinks_list) : logger(std::move(logger_name), sinks_list.begin(), sinks_list.end()) { } // ctor with single sink inline spdlog::logger::logger(std::string logger_name, spdlog::sink_ptr single_sink) : logger(std::move(logger_name), {std::move(single_sink)}) { } inline spdlog::logger::~logger() = default; inline void spdlog::logger::set_formatter(std::unique_ptr f) { for (auto &sink : sinks_) { sink->set_formatter(f->clone()); } } inline void spdlog::logger::set_pattern(std::string pattern, pattern_time_type time_type) { auto new_formatter = details::make_unique(std::move(pattern), time_type); set_formatter(std::move(new_formatter)); } template inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const char *fmt, const Args &... args) { if (!should_log(lvl)) { return; } try { using details::fmt_helper::to_string_view; fmt::memory_buffer buf; fmt::format_to(buf, fmt, args...); details::log_msg log_msg(source, &name_, lvl, to_string_view(buf)); sink_it_(log_msg); } SPDLOG_CATCH_AND_HANDLE } template inline void spdlog::logger::log(level::level_enum lvl, const char *fmt, const Args &... args) { log(source_loc{}, lvl, fmt, args...); } inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const char *msg) { if (!should_log(lvl)) { return; } try { details::log_msg log_msg(source, &name_, lvl, spdlog::string_view_t(msg)); sink_it_(log_msg); } SPDLOG_CATCH_AND_HANDLE } inline void spdlog::logger::log(level::level_enum lvl, const char *msg) { log(source_loc{}, lvl, msg); } template::value, T>::type *> inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const T &msg) { if (!should_log(lvl)) { return; } try { details::log_msg log_msg(source, &name_, lvl, msg); sink_it_(log_msg); } SPDLOG_CATCH_AND_HANDLE } template::value, T>::type *> inline void spdlog::logger::log(level::level_enum lvl, const T &msg) { log(source_loc{}, lvl, msg); } template::value, T>::type *> inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const T &msg) { if (!should_log(lvl)) { return; } try { using details::fmt_helper::to_string_view; fmt::memory_buffer buf; fmt::format_to(buf, "{}", msg); details::log_msg log_msg(source, &name_, lvl, to_string_view(buf)); sink_it_(log_msg); } SPDLOG_CATCH_AND_HANDLE } template::value, T>::type *> inline void spdlog::logger::log(level::level_enum lvl, const T &msg) { log(source_loc{}, lvl, msg); } template inline void spdlog::logger::trace(const char *fmt, const Args &... args) { log(level::trace, fmt, args...); } template inline void spdlog::logger::debug(const char *fmt, const Args &... args) { log(level::debug, fmt, args...); } template inline void spdlog::logger::info(const char *fmt, const Args &... args) { log(level::info, fmt, args...); } template inline void spdlog::logger::warn(const char *fmt, const Args &... args) { log(level::warn, fmt, args...); } template inline void spdlog::logger::error(const char *fmt, const Args &... args) { log(level::err, fmt, args...); } template inline void spdlog::logger::critical(const char *fmt, const Args &... args) { log(level::critical, fmt, args...); } template inline void spdlog::logger::trace(const T &msg) { log(level::trace, msg); } template inline void spdlog::logger::debug(const T &msg) { log(level::debug, msg); } template inline void spdlog::logger::info(const T &msg) { log(level::info, msg); } template inline void spdlog::logger::warn(const T &msg) { log(level::warn, msg); } template inline void spdlog::logger::error(const T &msg) { log(level::err, msg); } template inline void spdlog::logger::critical(const T &msg) { log(level::critical, msg); } #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT inline void wbuf_to_utf8buf(const fmt::wmemory_buffer &wbuf, fmt::memory_buffer &target) { int wbuf_size = static_cast(wbuf.size()); if (wbuf_size == 0) { return; } auto result_size = ::WideCharToMultiByte(CP_UTF8, 0, wbuf.data(), wbuf_size, NULL, 0, NULL, NULL); if (result_size > 0) { target.resize(result_size); ::WideCharToMultiByte(CP_UTF8, 0, wbuf.data(), wbuf_size, &target.data()[0], result_size, NULL, NULL); } else { throw spdlog::spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())); } } template inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const wchar_t *fmt, const Args &... args) { if (!should_log(lvl)) { return; } try { // format to wmemory_buffer and convert to utf8 using details::fmt_helper::to_string_view; fmt::wmemory_buffer wbuf; fmt::format_to(wbuf, fmt, args...); fmt::memory_buffer buf; wbuf_to_utf8buf(wbuf, buf); details::log_msg log_msg(source, &name_, lvl, to_string_view(buf)); sink_it_(log_msg); } SPDLOG_CATCH_AND_HANDLE } template inline void spdlog::logger::log(level::level_enum lvl, const wchar_t *fmt, const Args &... args) { log(source_loc{}, lvl, fmt, args...); } template inline void spdlog::logger::trace(const wchar_t *fmt, const Args &... args) { log(level::trace, fmt, args...); } template inline void spdlog::logger::debug(const wchar_t *fmt, const Args &... args) { log(level::debug, fmt, args...); } template inline void spdlog::logger::info(const wchar_t *fmt, const Args &... args) { log(level::info, fmt, args...); } template inline void spdlog::logger::warn(const wchar_t *fmt, const Args &... args) { log(level::warn, fmt, args...); } template inline void spdlog::logger::error(const wchar_t *fmt, const Args &... args) { log(level::err, fmt, args...); } template inline void spdlog::logger::critical(const wchar_t *fmt, const Args &... args) { log(level::critical, fmt, args...); } #endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT // // name and level // inline const std::string &spdlog::logger::name() const { return name_; } inline void spdlog::logger::set_level(spdlog::level::level_enum log_level) { level_.store(log_level); } inline void spdlog::logger::set_error_handler(spdlog::log_err_handler err_handler) { err_handler_ = std::move(err_handler); } inline spdlog::log_err_handler spdlog::logger::error_handler() const { return err_handler_; } inline void spdlog::logger::flush() { try { flush_(); } SPDLOG_CATCH_AND_HANDLE } inline void spdlog::logger::flush_on(level::level_enum log_level) { flush_level_.store(log_level); } inline spdlog::level::level_enum spdlog::logger::flush_level() const { return static_cast(flush_level_.load(std::memory_order_relaxed)); } inline bool spdlog::logger::should_flush_(const details::log_msg &msg) { auto flush_level = flush_level_.load(std::memory_order_relaxed); return (msg.level >= flush_level) && (msg.level != level::off); } inline spdlog::level::level_enum spdlog::logger::default_level() { return static_cast(SPDLOG_ACTIVE_LEVEL); } inline spdlog::level::level_enum spdlog::logger::level() const { return static_cast(level_.load(std::memory_order_relaxed)); } inline bool spdlog::logger::should_log(spdlog::level::level_enum msg_level) const { return msg_level >= level_.load(std::memory_order_relaxed); } // // protected virtual called at end of each user log call (if enabled) by the // line_logger // inline void spdlog::logger::sink_it_(details::log_msg &msg) { #if defined(SPDLOG_ENABLE_MESSAGE_COUNTER) incr_msg_counter_(msg); #endif for (auto &sink : sinks_) { if (sink->should_log(msg.level)) { sink->log(msg); } } if (should_flush_(msg)) { flush_(); } } inline void spdlog::logger::flush_() { for (auto &sink : sinks_) { sink->flush(); } } inline void spdlog::logger::default_err_handler_(const std::string &msg) { auto now = time(nullptr); if (now - last_err_time_ < 60) { return; } last_err_time_ = now; auto tm_time = details::os::localtime(now); char date_buf[100]; std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time); fmt::print(stderr, "[*** LOG ERROR ***] [{}] [{}] {}\n", date_buf, name(), msg); } inline void spdlog::logger::incr_msg_counter_(details::log_msg &msg) { msg.msg_id = msg_counter_.fetch_add(1, std::memory_order_relaxed); } inline const std::vector &spdlog::logger::sinks() const { return sinks_; } inline std::vector &spdlog::logger::sinks() { return sinks_; } inline std::shared_ptr spdlog::logger::clone(std::string logger_name) { auto cloned = std::make_shared(std::move(logger_name), sinks_.begin(), sinks_.end()); cloned->set_level(this->level()); cloned->flush_on(this->flush_level()); cloned->set_error_handler(this->error_handler()); return cloned; }