spdlog源码阅读 (2): sinks的创建和使用
2. sink创建
2.1 还是rotating_file_sink
我们仍然以rotating_file_sink为例来说明在spdlog中sink的创建过程。
在spdlog-master/tests中能够找到file_log.cpp文件,其中有关于rotate的示例代码,如下:
TEST_CASE("rotating_file_logger1", "[rotating_logger]]")
{
1. prepare_logdir();
2. std::string basename = "logs/rotating_log";
3. auto logger = spdlog::rotating_logger_mt("logger", basename, 1024, 0);
//......
}
line: 3,创建名为"logger",文件名"rotating_log",在文件夹logs下,文件最大为1024(字节),
且只能有一个文件。返回的是logger对象,并且它是支持多线程的(mt)。
2.2 create
继续查看rotating_logger_mt,如下:
inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_mt(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files)
{
1. return create<spdlog::sinks::rotating_file_sink_mt>(logger_name, filename, SPDLOG_FILENAME_T("txt"), max_file_size, max_files);
}
line: 1, 实际创建对象。create是一个模板函数,如下:
template <typename Sink, typename... Args>
inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, Args... args)
{
2. sink_ptr sink = std::make_shared<Sink>(args...);
3. return details::registry::instance().create(logger_name, { sink });
}
Sink在本示例中即spdlog::sinks::rotating_file_sink_mt, 第二个模板参数也就是
rotating_file_sink_mt的构造函数参数。针对每一种sink,都会存在一个对应的create函数。
当然sink的实际创建也是发生在该函数中(line2)。
2.3 单例registry
1.2中 line:3又继续调用了registry执行对象的创建,我们先来看下registry是个什么鬼
#ifdef SPDLOG_NO_REGISTRY_MUTEX
typedef registry_t<spdlog::details::null_mutex> registry;
#else
typedef registry_t<std::mutex> registry;
#endif
可以看出在多线程的情况下,类registry需要锁的支持。
下面来到最需要关心的位置,也就是最后的create, 代码如下:
template<class It>
std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
{
1. std::lock_guard<Mutex> lock(_mutex);
throw_if_exists(logger_name);
std::shared_ptr<logger> new_logger;
2. 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);
3. if (_formatter)
new_logger->set_formatter(_formatter);
if (_err_handler)
new_logger->set_error_handler(_err_handler);
new_logger->set_level(_level);
//Add to registry
4. _loggers[logger_name] = new_logger;
return new_logger;
}
- line1: 在多线程的情况下,创建一个logger对象需要加锁。
- line2: 区分日志同步写/异步写,实际logger对象创建也是发生在这里。
- line3: 有自定义格式时,使用自定义的格式。
- line4: 将新创建的对象加入全局管理(registry是个单例),这也是需要加锁的原因。
2.4 小结
从上述的过程中,可以看到sink的实际创建是发生在create中,创建的sink对象做为参数参与了
logger对象的创建。在logger中sink起到的作用是什么,就是下面要讨论的问题了。
3. sink的使用
仍然以2.1 的例子继续,看下当时省略的代码先:
TEST_CASE("rotating_file_logger1", "[rotating_logger]]")
{
//......
for (int i = 0; i < 10; ++i)
1. logger->info("Test message {}", i);
//......
}
line1: 调用info输出日志,跟踪代码看下info到底是做了什么。
//片段1
template <typename... Args>
inline void spdlog::logger::log(level::level_enum lvl, const char* msg)
{
details::log_msg log_msg(&_name, lvl);
log_msg.raw << msg;
1. _sink_it(log_msg);
}
//片段2
inline void spdlog::logger::_sink_it(details::log_msg& msg)
{
_formatter->format(msg);
2. for (auto &sink : _sinks)
{
if( sink->should_log( msg.level))
{
3. sink->log(msg);
}
}
if(_should_flush_on(msg))
flush();
}
- line1: 创建一个log_msg对象,并将msg存入到该对象中,执行_sink_it
- line2: 遍历当前对象中所有的sink,并对每一个sink执行它的log函数。
到这里,我们已经和上篇中的sink衔接上了。
3.1 小结
本篇已经接近尾声,从之前的分析中,可以得到如下的关键信息:
- log_msg是spdlog真正存储日志信息的位置,自然也是最后的输出对象。
- sink通过base_sink实现对mt/st的区分。
- registry是存储logger对象的单例,而logger是日志输出的真正执行者。
- spdlog通过创建不同的sink决定最后实例化的logger是mt/st,也能够决定最后的输出目标。
- 用户自定义的格式在logger中_sink_it时生效。
下一篇我们从log_msg开始。
spdlog源码阅读 (2): sinks的创建和使用的更多相关文章
- spdlog源码阅读 (1): sinks
0. spdlog简单介绍 spdlog 是一个快速的 C++ 日志库,只包含头文件,兼容 C++11.项目地址 特性: 非常快 只包含头文件 无需依赖第三方库 支持跨平台 - Linux / Win ...
- spdlog源码阅读 (3): log_msg和BasicWriter
4. log_msg和它的打手BasicWriter 在spdlog源码阅读 (2): sinks的创建和使用中,提到log_msg提供了存储日志的功能.那么到底在spdlog中它是怎么 起到这个作用 ...
- SparkConf加载与SparkContext创建(源码阅读一)
即日起开始spark源码阅读之旅,这个过程是相当痛苦的,也许有大量的看不懂,但是每天一个方法,一点点看,相信总归会有极大地提高的.那么下面开始: 创建sparkConf对象,那么究竟它干了什么了类,从 ...
- 【原】FMDB源码阅读(三)
[原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...
- 【原】FMDB源码阅读(一)
[原]FMDB源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 说实话,之前的SDWebImage和AFNetworking这两个组件我还是使用过的,但是对于 ...
- 【原】AFNetworking源码阅读(六)
[原]AFNetworking源码阅读(六) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这一篇的想讲的,一个就是分析一下AFSecurityPolicy文件,看看AF ...
- 【原】AFNetworking源码阅读(五)
[原]AFNetworking源码阅读(五) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇中提及到了Multipart Request的构建方法- [AFHTTP ...
- 【原】AFNetworking源码阅读(四)
[原]AFNetworking源码阅读(四) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇还遗留了很多问题,包括AFURLSessionManagerTaskDe ...
- 【原】AFNetworking源码阅读(三)
[原]AFNetworking源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇的话,主要是讲了如何通过构建一个request来生成一个data tas ...
随机推荐
- java7 invokedynamic命令深入研究
在看java虚拟机字节码执行引擎的时候,里面提到了java虚拟机里调用方法的字节码指令有5种: invokestatic //调用静态方法 invokespecial //调用私有方法.实例构造器方法 ...
- 在ubuntu下编写python(python入门)
在ubuntu下编写python 一般情况下,ubuntu已经安装了python,打开终端,直接输入python,即可进行python编写. 默认为python2 如果想写python3,在终端输入p ...
- python 基础学习小记
Python应该是写起来最舒服的动态语言了,一下是一些读书笔记,本文中安装的是3.0,有几点需要注意: print "xxx" 要换成 print("xxx") ...
- UUID错误
在Archive项目时,出现了“Your build settings specify a provisioning profile with the UUID “”, however, no suc ...
- option触发事件两种方法总结
代码如下: <!doctype html> <html> <head> <meta charset="UTF-8"> <tit ...
- win8 wifi开关显示关闭,且设置里面wifi开关显示灰色的解决办法
只要从华硕官网下载驱动,电源管理驱动,安装下面显示的几个软件即可,然后重启电脑,即可看见wifi热点,另外设置里面的wifi开关也将显示正常(刚开始安装了个驱动人生根本没用,最后在华硕官网下载了个电源 ...
- 快看我解决了一个Nginx的小问题
前言 最近小编写项目的时候,需要用到Nginx服务器,对于Nginx正常安装就好了详情见[我是传送门],正当一切安好的时候问题来了,这台服务器的80端口竟然被占用了,什么鬼?怎么办,只有改端口.具体方 ...
- css4激动人心的新特性及浏览器支持度
CSS3的选择器提供了很多像:nth-child这样有用的选择器,并且得到浏览器支持.CSS的第四代 选择器CSS4选择器),经我们带来了更多有用的选择器. 1.否定伪类:not 否定伪类选择器其实在 ...
- hibernate系列笔记(2)---Hibernate的核心API
Hibernate的核心API 一般我们通过hibernate进行操作的时候,都会遵循下面的流程,那么接下来我对每一个步骤进行讲解: 1 public void testInsert() { 2 // ...
- FineUIMvc随笔 - 怎样在控件中嵌套 HTML
声明:FineUIMvc(基础版)是免费软件,本系列文章适用于基础版. 用户需求 有网友在<FineUI总群1>问这么一个问题:怎么把 HTML 嵌套在控件中? 这是很多刚学习 FineU ...