第三部分:Spdlog 日志库的实现原理
! https://zhuanlan.zhihu.com/p/617432495
Spdlog 是一个快速、异步的 C++ 日志库,被广泛应用于 C++ 项目中。在这篇文章中,我们将探讨 Spdlog 日志库的实现原理。
Spdlog 的结构
Spdlog 由五个主要组件构成:Loggers、Sinks、Formatters、Async Logger 和 Registry。每个组件都扮演着不同的角色,共同协作记录并输出日志消息。
- Loggers :是 Spdlog 最基本的组件,负责记录日志消息。在 Spdlog 中,一个 Logger 对象代表着一个日志记录器,应用程序可以使用 Logger 对象记录不同级别的日志消息。
- Sinks :决定了日志消息的输出位置。在 Spdlog 中,一个 Sink 对象代表着一个输出位置,例如控制台、文件、网络等。应用程序可以将不同的日志消息发送到不同的 Sink 中。
- Formatters :负责将日志消息转换为特定格式。在 Spdlog 中,一个 Formatter 对象代表着一个消息格式器,应用程序可以使用不同的 Formatter 对象将日志消息转换为不同的格式。
- Async Logger :是 Spdlog 的异步记录器,它负责将日志消息异步地写入到目标 Sink 中。当应用程序调用 Logger 对象记录一个日志消息时,该消息会被加入到一个队列中,然后异步地写入目标 Sink 中。这样可以避免多个线程同时访问 Sink,从而确保线程安全性。
- Registry :用于管理 Spdlog 的所有组件。在 Spdlog 中,所有的 Loggers、Sinks、Formatters 和 Async Logger 都在一个全局注册表中注册,Registry 用于管理这些组件。

Spdlog 记录日志的流程
当应用程序调用 Spdlog 记录日志时,Spdlog 的流程如下:
- 获取一个 Logger 对象。
- 使用该 Logger 对象记录一个日志消息,该消息包括日志级别、时间戳、线程 ID、文件名和行号等信息。
- 将日志消息传递给 Formatter,将消息转换为特定格式。
- 将格式化后的消息传递给 Async Logger。
- Async Logger 将消息写入目标 Sink,完成日志记录。
Spdlog 的流程非常简单,但是每个组件都扮演着重要的角色。Loggers 负责记录日志消息,Sinks 决定了日志消息的输出位置,Formatters 负责将日志消息转换为特定格式,Async Logger 异步地将日志消息写入到目标 Sink 中,Registry 用于管理这些组件。
Spdlog 的线程安全性
spdlog 允许我们自由创建线程安全和非线程安全(单线程)的日志,其设置在基类base_skin 中,
template<typename Mutex>
class SPDLOG_API base_sink : public sink
{
public:
void log(const details::log_msg &msg) final;
protected:
Mutex mutex_;
}
template<typename Mutex>
void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::log(const details::log_msg &msg)
{
std::lock_guard<Mutex> lock(mutex_);
sink_it_(msg);
}
每个sink都会继承 base_sink,通过模板参数 Mutex 传入锁。可以看到写日志函数 log 调用了 std::lock_guard 来使用锁。
Mutex 可以自定义,需要提供下面两个接口:
void lock();
void unlock();
在实际使用中如果想要线程安全,可以传入c++的 mutex(c++11开始支持),也可以自定义。如下是一个声明线程安全例子:
using kafka_sink_mt = kafka_sink<std::mutex>;
当然spdlog 也为我们提供了单线程的 mutex:
struct null_mutex
{
void lock() const {}
void unlock() const {}
};
using kafka_sink_st = kafka_sink<spdlog::details::null_mutex>;
Spdlog 的同步和异步模式
同步模式
在同步模式下,Spdlog 将日志消息直接写入目标 Sink,不使用内存队列。这种模式下,应用程序在记录日志消息时,必须等待消息写入目标 Sink 后才能继续执行。同步模式可以保证日志消息的实时性,但是可能会影响程序的性能,特别是在大量记录日志消息时。如果应用程序不需要实时记录日志消息,可以使用异步模式来提高性能。
异步模式
在异步模式下,日志消息被加入到一个内存队列中,然后异步地写入目标 Sink。异步模式可以提高日志记录的性能,尤其是在多线程环境下,因为它可以避免多个线程同时访问 Sink,从而提高线程安全性。
在 Spdlog 中,异步模式由 Async Logger 实现。Async Logger 在后台运行一个线程,负责从内存队列中获取日志消息,并将其写入目标 Sink 中。Async Logger 可以配置多个 Sink,每个 Sink 都会有一个独立的内存队列。
Spdlog 提供了两种内存队列实现:unbounded 和 bounded。unbounded 内存队列没有大小限制,可以一直增长,直到内存耗尽。bounded 内存队列有一个固定的大小,超过大小限制后,新的消息将被丢弃。
在使用异步模式时,需要注意以下事项:
- 处理内存队列时可能会出现内存分配问题和锁竞争问题,需要谨慎设计和测试。
- 如果内存队列大小有限制,需要根据应用程序的需求和硬件资源进行适当的调整。
- 在应用程序退出时,需要等待所有日志消息写入完成,否则可能会丢失一些日志消息。
异步模式可以大大提高日志记录的性能,但是也需要谨慎使用和测试。如果内存队列大小限制不当或处理不当,可能会导致内存占用过高或日志消息丢失等问题。
Spdlog 的性能
Spdlog 是一个高性能的日志库,它的性能优于其他许多日志库。Spdlog 的异步记录器和多线程支持使得它能够快速地记录大量的日志消息。
下面是spdlog性能:
同步模式:
[info] **************************************************************
[info] Single thread, 1,000,000 iterations
[info] **************************************************************
[info] basic_st Elapsed: 0.17 secs 5,777,626/sec
[info] rotating_st Elapsed: 0.18 secs 5,475,894/sec
[info] daily_st Elapsed: 0.20 secs 5,062,659/sec
[info] empty_logger Elapsed: 0.07 secs 14,127,300/sec
[info] **************************************************************
[info] C-string (400 bytes). Single thread, 1,000,000 iterations
[info] **************************************************************
[info] basic_st Elapsed: 0.41 secs 2,412,483/sec
[info] rotating_st Elapsed: 0.72 secs 1,389,196/sec
[info] daily_st Elapsed: 0.42 secs 2,393,298/sec
[info] null_st Elapsed: 0.04 secs 27,446,957/sec
[info] **************************************************************
[info] 10 threads, competing over the same logger object, 1,000,000 iterations
[info] **************************************************************
[info] basic_mt Elapsed: 0.60 secs 1,659,613/sec
[info] rotating_mt Elapsed: 0.62 secs 1,612,493/sec
[info] daily_mt Elapsed: 0.61 secs 1,638,305/sec
[info] null_mt Elapsed: 0.16 secs 6,272,758/sec
异步模式:
[info] -------------------------------------------------
[info] Messages : 1,000,000
[info] Threads : 10
[info] Queue : 8,192 slots
[info] Queue memory : 8,192 x 272 = 2,176 KB
[info] -------------------------------------------------
[info]
[info] *********************************
[info] Queue Overflow Policy: block
[info] *********************************
[info] Elapsed: 1.70784 secs 585,535/sec
[info] Elapsed: 1.69805 secs 588,910/sec
[info] Elapsed: 1.7026 secs 587,337/sec
[info]
[info] *********************************
[info] Queue Overflow Policy: overrun
[info] *********************************
[info] Elapsed: 0.372816 secs 2,682,285/sec
[info] Elapsed: 0.379758 secs 2,633,255/sec
[info] Elapsed: 0.373532 secs 2,677,147/sec
第三部分:Spdlog 日志库的实现原理的更多相关文章
- 日志服务Python消费组实战(三):实时跨域监测多日志库数据
解决问题 使用日志服务进行数据处理与传递的过程中,你是否遇到如下监测场景不能很好的解决: 特定数据上传到日志服务中需要检查数据内的异常情况,而没有现成监控工具? 需要检索数据里面的关键字,但数据没有建 ...
- C++的开源跨平台日志库glog学习研究(三)--杂项
在前面对glog分别做了两次学习,请看C++的开源跨平台日志库glog学习研究(一).C++的开源跨平台日志库glog学习研究(二)--宏的使用,这篇再做个扫尾工作,算是基本完成了. 编译期断言 动态 ...
- 开源日志库log4cplus+VS2008使用
一.简介 log4cplus是C++编写的开源的日志系统,功能非常全面.本文介绍如何在Windows+VS2008中使用该日志库. 二.下载 可从网站[url]http://log ...
- 这可能是php世界中最好的日志库——monolog
由于一些历史原因,php中并没有内建的日志接口,故长期以来也没一个功能完备并且应用广泛的日志库.在我的工作生涯中,如果系统需要记录一些应用日志的话,基本上就是封装一个日志类,然后把一些要记录的字段写入 ...
- glog日志库使用笔记
日志能方便地诊断程序原因.统计程序运行数据,是大型软件系统必不可少的组件之一.glog 是google的开源日志系统,相比较log4系列的日志系统,它更加轻巧灵活. 在Github上下载glog,解压 ...
- easylog -- Linux 下的简单日志库
之前使用 log4c 或者 log4cpp 的时候, 总需要配置一些文件和链接库之类复杂的配置. 虽然越复杂越说明这个软件支持的功能多.可选择性强, 但是对于一个小的项目,或者要研究他人的代码而加点儿 ...
- C/C++log日志库比较
事实上,在C的世界里面没有特别好的日志函数库(就像Java里面的的log4j,或者C++的log4cxx).C程序员都喜欢用自己的轮子.printf就是个挺好的轮子,但没办法通过配置改变日志的格式或者 ...
- Logan:美团点评的开源移动端基础日志库
前言 Logan是美团点评集团移动端基础日志组件,这个名称是Log和An的组合,代表个体日志服务.同时Logan也是“金刚狼”大叔的名号,当然我们更希望这个产品能像金刚狼大叔一样犀利. Logan已经 ...
- [转]开源日志库<log4cplus+VS2008使用>整理
转 开源日志库<log4cplus+VS2008使用>整理 转http://pyhcx.blog.51cto.com/713166/143549 一.简介 log4cplus是C+ ...
- python找寻合适的日志库logging Handler——Handler自定义实现
最近在用python tornado开发一个app的服务端.投产的系统肯定需要包含日志功能,这里就自然想到了用python自带的logging库. logging中日志内容的输出都交由Handle ...
随机推荐
- 解决word表格中文字无法居中的一个方法
情况:试过许多方法,如表格属性->单元格居中:表格布局中的居中对齐都无效:虽然利用段落中的单倍行距可以实现居中效果,但我不想单倍行距. 原因:有时候我们表格上下行距比较大,而使用居中的按钮只能让 ...
- vue 项目打包 遇到问题 npm run build 无法打包
npm run build 打包 直接报错!!! 发现package.json中build的打包后边多了一个:prod 因此打包直接使用 npm run build:prod
- input设置自定义属性,并获取值。
HTML代码: JavaScript代码: 因为busCode不是input标签原生的属性,所以不能使用"点"操作. 非标准属性,要用:obj.getAttribute(" ...
- Two Sum:给出一个整数数组,返回两个数的下标值,令其和等于一个指定的目标值 #Leetcode
// Given nums = [2, 7, 11, 15], target = 9, // Because nums[0] + nums[1] = 2 + 7 = 9, // return [0, ...
- Linux系列---【设置ssh连接超时时间】
设置ssh连接超时时间 shell工具总是不断的超时,上个厕所就断开了,很不方便,这里根据自己习惯设置一下. echo "export TMOUT=600" >> /e ...
- python excel使用
python excel使用 https://blog.csdn.net/m0_59235508/article/details/122808875 pandas不覆盖写入 https://blog. ...
- 自学JavaDay02_class01
注释 单行注释: //单行注释 多行注释 /** 多行注释* 多行注释* */ 文档注释 /** * 文档注释 * 文档注释 */ 标识符 关键字 标识符 所有的标识符都应该以字母(A-Z 或者 a- ...
- flink 启动job命令
0. 启动flink-session ./bin/yarn-session.sh -n 4 -s 3 -jm 2048 -tm 6144 高版本 bin/yarn-session.sh -d -s 3 ...
- PHP接受json数据
PHP接受json数据 获取请求的参数 $input = file_get_contents("php://input"); $input = json_decode($input ...
- 9.Java的LinkedList/Deque相关方法
Java的LinkedList/Deque中add/offer/push,remove/pop/poll的区别 它们来自不同的接口 add/remove源自集合,所以添加到队尾,从队头删除: offe ...