首先看logger的成员变量,对logger有个大概的了解
const std::string _name; /*有一个名字,名字唯一,不能重复*/
std::vector<sink_ptr> _sinks;/*有一组输出目标*/
formatter_ptr _formatter; /*格式化输出信息*/
spdlog::level_t _level; /*日志等级*/
spdlog::level_t _flush_level;/*冲刷等级,大于此等级的日志会调用flush*/
所以,我们向logger输出日志的时候,它会用相同的格式化输出,同时输出到多个目标。
logger的创建
template<class It>
std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
{
/*锁保护,有单、多线程锁,单线程锁什么都不做*/
std::lock_guard<Mutex> lock(_mutex);
/*如果名字重复会抛出异常*/
throw_if_exists(logger_name);
/*根据是否异步模式创建logger*/
std::shared_ptr<logger> new_logger;
if (_async_mode)
new_logger = std::make_shared<async_logger>(logger_name, sinks_begin, sinks_end, _async_q_size, _overflow_policy, _worker_warmup_cb, _flush_interval_ms, _worker_teardown_cb);
else
new_logger = std::make_shared<logger>(logger_name, sinks_begin, sinks_end);
/*设置格式化输出信息为全局格式化输出信息*/
if (_formatter)
new_logger->set_formatter(_formatter);
/*设置日志等级*/
new_logger->set_level(_level);
//Add to registry
_loggers[logger_name] = new_logger;
return new_logger;
}
logger创建后就可以向它写入日志了
template <typename... Args>
inline void spdlog::logger::log(level::level_enum lvl, const char* fmt, const Args&... args)
{
/*日志等级限制*/
if (!should_log(lvl)) return;
/*格式化基本日志*/
details::log_msg log_msg(&_name, lvl);
try
{
log_msg.raw.write(fmt, args...);
}
catch (fmt::FormatError &ex)
{
throw spdlog::spdlog_ex(std::string("format error in \"") + fmt + "\": " + ex.what());
}
/*遍历输出目标,向每个sink输出一次日志*/
_sink_it(log_msg);
}
inline void spdlog::logger::_sink_it(details::log_msg& msg)
{
_formatter->format(msg);
for (auto &sink : _sinks)
sink->log(msg);
const auto flush_level = _flush_level.load(std::memory_order_relaxed);
if (msg.level >= flush_level)
flush();
}
同时,spdlog提供了一些快捷函数用于创建常用的logger,带后缀mt的是多线程版本,带后缀st的是单线程版本。
//
// Create and register multi/single basic file logger
//
std::shared_ptr<logger> basic_logger_mt(const std::string& logger_name, const filename_t& filename,bool force_flush = false);
std::shared_ptr<logger> basic_logger_st(const std::string& logger_name, const filename_t& filename, bool force_flush = false);
//
// Create and register multi/single threaded rotating file logger
//
std::shared_ptr<logger> rotating_logger_mt(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files, bool force_flush = false);
std::shared_ptr<logger> rotating_logger_st(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files, bool force_flush = false);
//
// Create file logger which creates new file on the given time (default in midnight):
//
std::shared_ptr<logger> daily_logger_mt(const std::string& logger_name, const filename_t& filename, int hour=0, int minute=0, bool force_flush = false);
std::shared_ptr<logger> daily_logger_st(const std::string& logger_name, const filename_t& filename, int hour=0, int minute=0, bool force_flush = false);
//
// Create and register stdout/stderr loggers
//
std::shared_ptr<logger> stdout_logger_mt(const std::string& logger_name, bool color = false);
std::shared_ptr<logger> stdout_logger_st(const std::string& logger_name, bool color = false);
std::shared_ptr<logger> stderr_logger_mt(const std::string& logger_name, bool color = false);
std::shared_ptr<logger> stderr_logger_st(const std::string& logger_name, bool color = false);