在 spdlog
日志库中,register
类是为了管理logger的生命周期并提供方便的全局访问。该类包括以下功能。
单例实现 registry类的构造函数设置成private,并将拷贝构造函数和赋值运算符设置成delete,这是为了避免通过非期望的方式创建registry。registry只能通过instance
方法对其实例化,该方法利用局部静态变量初始化的线程安全性来保证registry的初始化安全。
1 2 3 4 SPDLOG_INLINE registry ®istry::instance () { static registry s_instance; return s_instance; }
提供默认logger Register在构造时会创建一个默认的logger
,并提供get_default_raw
方法来获取默认的logger
对象的裸指针,再通过函数的封装,提供了不需要额外初始化的日志接口。
此外,还可以通过set_default_logger
方法来修改默认的logger对象,并使用智能指针保存该对象,避免内存泄漏。
如果不需要使用默认logger可以使用SPDLOG_DISABLE_DEFAULT_LOGGER
取消相关实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 SPDLOG_INLINE registry::registry () : formatter_(new pattern_formatter()) { #ifndef SPDLOG_DISABLE_DEFAULT_LOGGER #ifdef _WIN32 auto color_sink = std::make_shared <sinks::wincolor_stdout_sink_mt>(); #else auto color_sink = std::make_shared <sinks::ansicolor_stdout_sink_mt>(); #endif const char *default_logger_name = "" ; default_logger_ = std::make_shared <spdlog::logger>(default_logger_name, std::move (color_sink)); loggers_[default_logger_name] = default_logger_; #endif } template <typename ... Args>inline void log (level::level_enum lvl, format_string_t <Args...> fmt, Args &&...args) { default_logger_raw ()->log (source_loc{}, lvl, fmt, std::forward<Args>(args)...); } template <typename ... Args>inline void trace (format_string_t <Args...> fmt, Args &&...args) { default_logger_raw ()->trace (fmt, std::forward<Args>(args)...); } template <typename ... Args>inline void debug (format_string_t <Args...> fmt, Args &&...args) { default_logger_raw ()->debug (fmt, std::forward<Args>(args)...); } SPDLOG_INLINE void registry::set_default_logger (std::shared_ptr<logger> new_default_logger) { std::lock_guard<std::mutex> lock (logger_map_mutex_) ; if (new_default_logger != nullptr ) { loggers_[new_default_logger->name ()] = new_default_logger; } default_logger_ = std::move (new_default_logger); }
logger的统一管理 register提供了logger对象的管理方法,使用std::unordered_map来储存logger对象,并通过logger名称来对其索引。
通过工厂函数创建的logger对象会默认添加进管理,对于手动创建的logger对象可以使用register_logger_方法添加进管理。
register使用get方法来获取相应的logger对象,使用drop方法删除已管理的logger对象,还可以使用drop_all方法删除所有已管理的logger对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 struct synchronous_factory { template <typename Sink, typename ... SinkArgs> static std::shared_ptr<spdlog::logger> create (std::string logger_name, SinkArgs &&...args) { auto sink = std::make_shared <Sink>(std::forward<SinkArgs>(args)...); auto new_logger = std::make_shared <spdlog::logger>(std::move (logger_name), std::move (sink)); details::registry::instance ().initialize_logger (new_logger); return new_logger; } }; SPDLOG_INLINE void registry::initialize_logger (std::shared_ptr<logger> new_logger) { std::lock_guard<std::mutex> lock (logger_map_mutex_) ; new_logger->set_formatter (formatter_->clone ()); if (err_handler_) { new_logger->set_error_handler (err_handler_); } auto it = log_levels_.find (new_logger->name ()); auto new_level = it != log_levels_.end () ? it->second : global_log_level_; new_logger->set_level (new_level); new_logger->flush_on (flush_level_); if (backtrace_n_messages_ > 0 ) { new_logger->enable_backtrace (backtrace_n_messages_); } if (automatic_registration_) { register_logger_ (std::move (new_logger)); } } SPDLOG_INLINE std::shared_ptr<logger> registry::get (const std::string &logger_name) { std::lock_guard<std::mutex> lock (logger_map_mutex_) ; auto found = loggers_.find (logger_name); return found == loggers_.end () ? nullptr : found->second; } SPDLOG_INLINE void registry::drop (const std::string &logger_name) { std::lock_guard<std::mutex> lock (logger_map_mutex_) ; auto is_default_logger = default_logger_ && default_logger_->name () == logger_name; loggers_.erase (logger_name); if (is_default_logger) { default_logger_.reset (); } } SPDLOG_INLINE void registry::drop_all () { std::lock_guard<std::mutex> lock (logger_map_mutex_) ; loggers_.clear (); default_logger_.reset (); }
register实现了一套logger一样的接口,以便实现全局logger设置。实现方法类似,都是遍历所有logger再调用其方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 SPDLOG_INLINE void registry::set_formatter (std::unique_ptr<formatter> formatter) { std::lock_guard<std::mutex> lock (logger_map_mutex_) ; formatter_ = std::move (formatter); for (auto &l : loggers_) { l.second->set_formatter (formatter_->clone ()); } } SPDLOG_INLINE void registry::enable_backtrace (size_t n_messages) { std::lock_guard<std::mutex> lock (logger_map_mutex_) ; backtrace_n_messages_ = n_messages; for (auto &l : loggers_) { l.second->enable_backtrace (n_messages); } } SPDLOG_INLINE void registry::disable_backtrace () { std::lock_guard<std::mutex> lock (logger_map_mutex_) ; backtrace_n_messages_ = 0 ; for (auto &l : loggers_) { l.second->disable_backtrace (); } } SPDLOG_INLINE void registry::set_level (level::level_enum log_level) { std::lock_guard<std::mutex> lock (logger_map_mutex_) ; for (auto &l : loggers_) { l.second->set_level (log_level); } global_log_level_ = log_level; } SPDLOG_INLINE void registry::flush_on (level::level_enum log_level) { std::lock_guard<std::mutex> lock (logger_map_mutex_) ; for (auto &l : loggers_) { l.second->flush_on (log_level); } flush_level_ = log_level; } SPDLOG_INLINE void registry::set_error_handler (err_handler handler) { std::lock_guard<std::mutex> lock (logger_map_mutex_) ; for (auto &l : loggers_) { l.second->set_error_handler (handler); } err_handler_ = std::move (handler); } SPDLOG_INLINE void registry::flush_all () { std::lock_guard<std::mutex> lock (logger_map_mutex_) ; for (auto &l : loggers_) { l.second->flush (); } }
除此之外,还实现了apply_all方法,可以通过传函数对象,实现多样化的管理需求。
1 2 3 4 5 6 7 SPDLOG_INLINE void registry::apply_all ( const std::function<void (const std::shared_ptr<logger>)> &fun) { std::lock_guard<std::mutex> lock (logger_map_mutex_) ; for (auto &l : loggers_) { fun (l.second); } }
线程安全 register单例的实例化使用懒汉模式,并使用局部静态变量初始化来保证线程安全性。
1 2 3 4 SPDLOG_INLINE registry ®istry::instance () { static registry s_instance; return s_instance; }
对logger对象的操作之前使用RAII的锁来保证线程安全性
1 std::lock_guard<std::mutex> lock (logger_map_mutex_) ;
性能优化 频繁加锁会导致日志性能下降,因此register类除了default_logger方法还提供了get_default_raw
方法,提供不加锁的获取默认logger指针的方法。由于不加锁,因此改方法非线程安全,使用时不能与set_default_logger
方法同时使用。