spdlog

  spdlog是一个常见的第三方日志库,因为诸多优点得到青睐。这篇文章就对spdlog进行一个简单的介绍。内容主要围绕以下几个方面:
  一、spdlog的基本信息
  二、spdlog的基本概念
  三、spdlog的使用相关

一、spdlog的基本信息

  简单点儿说spdlog就是一个开源日志库,支持跨平台(Windows、Linux、Mac、Android),主要开发语言是C++,其整体语言占比如下图:
在这里插入图片描述
  目前为止最新版本是1.10.0
  GitHub的网址是:gabime/spdlog: Fast C++ logging library. (github.com)

二、spdlog的基本概念

  ps:网上很多文章对于spdlog的介绍都是先表明其特点,然后介绍各自特点的实现原理。本文采用自下而上的方法,希望在第二部分之后读者能对spdlog内部有一个清晰的认知。

2.1 spdlog的结构

  spdlog可以分成三级结构,从上而下是logger registry、logger、sink,其各自功能如下:
  logger registry(日志管理器):负责管理所有的logger,用户建立的所有logger都会在registry处进行登记然后统一管理
  logger(日志记录器):是用户直接操作的对象,通过操作logger进行日志逻辑的生成
  sink(日志记录器槽):受logger控制,执行具体的动作(动作包括写入日志文件/输出到控制台)
  三级结构的关系如下图所示:
在这里插入图片描述
  简单来说,就是一个logger registry管多个logger,一个logger管多个sink。logger registry中的logger是通过name进行对应的。后面使用的时候可以直接通过名称获取对应的日志对象。
  有了这种层级结构,在代码调用的时候,logger的每个操作都会下顺到sink层面,调用sink的对象。比如像一些set_pattern()和set_level()。
  说到底,日志库的目的就是把日志信息写到指定地方。从上面对于结构的功能描述,sink才是真正操作日志进行写操作的结构,那sink可以把日志信息写到哪里呢?主要有三个去向:
  1)控制台输出(stdout)——默认输出方式
  2)日志文件
  3)数据库或其他外部实体

  再看这三种去向,控制台输出是为了用户便于即时查看代码状态。通常情况下,日志的数量是比较大的,特别是一些debug的模式。把日志信息存储起来供以后复盘才是更好的方法。从使用的角度上讲,用文件存储日志比直接存储在数据库中更加常用一点。所以本文主要介绍的就是文件的存储方法了。
  当然,存储文件也有多种方式了。比如是全写到一个文件中能还是按照某种方式进行分开存放。spdlog中提供了以下几种存放方式,基本能够覆盖对于日志库的常规需求了。
  1)当天日志(spdlog::daliy_logger):记录当天的所有日志,但在指定时间点会把日志清空
  2)循环日志(spdlog::rotating_logger):日志创建成功后,如果写入的日志大小超过限制就会写入到新日志文件中去。不过同时存在的日志总数是有上限的,达到上限后按指定策略淘汰。需要特别注意的是日志更迭的规则是:当日志A存满时,将日志A名称更改为B,再新建一个日志命名为A,依次类推,直到达到上限数字
  3)单个日志(spdlog::basic_logger):只有一个日志文件,所有日志都会在该文件中累加
  除了3种文件日志外,输出终端(控制台)也比较常用啦
  4)输出终端(spdlog::stdout_color):日志打印至终端,不同等级日志颜色不同

  明确了spdlog的结构,再看看spdlog提供的几个特性吧:

2.2 特性——多种日志等级

  这个不是spdlog特有的,是很常见的功能,对于日志信息分级可以对日志信息进行筛选,对指定用户显示指定信息了。spdlog以枚举的方式提供了七个等级:

enum level_enum {
	trace = SPDLOG_LEVEL_TRACE 0
	debug = SPDLOG_LEVEL_DEBUG 1
	info  = SPDLOG_LEVEL_INFO  2(默认输出等级)
	warn = SPDLOG_LEVEL_WARN 3
	err = SPDLOG_LEVEL_ERROR   4
	critical = SPDLOG_LEVEL_CRITICAL 5
	off  = SPDLOG_LEVEL_OFF 6
}

  等级按照大小进行排序,设定等级A后,小于A的信息将不再输出.

2.3 特性——同步、异步

  这里的同步/异步指日志信息是否直接输出/写入文件,直接写就是同步,稍后写就是异步。spdlog默认的状态就是同步了,同步也没什么好说的。这里介绍下异步的逻辑实现:
  异步状态下,日志会先存入队列,然后由线程从队列中取数据,当队列满的时候会有淘汰策略。如果工作线程中抛出了异常,向队列写入下一条日志时异常会再次抛出,可以在写入队列时捕捉工作者线程的异常,淘汰策略一般两种:
  1)阻塞新来的的日志,直到队列有剩余空间(默认处理方式)
  2)把新的日志丢掉(需要设定:spdlog::set_async_mode(队列大小,spdlog::async_overflow_policy::discard_log_msg))

2.4 特性——单、多线程处理模式

  spdlog中提供了单线程和多线程模式,由使用者在对象创建中自己指定。
  st:单线程版本,不用加锁,效率高,但不保证线程安全
  mt:多线程版本,保证多线程并发情况线程安全,但效率稍低

2.5 特性——个性化输出格式(pattern)

  一般情况下,希望输出的日志信息中带有各类基本信息。但具体情况要具体分析,spdlog中提供了个性化的输出方式,可以自己指定模式进行输出。基本上就是各类“%参数”的组合。具体内容可以参考:Custom formatting · gabime/spdlog Wiki (github.com)

2.6 特性——刷新方式

  刷新方式指日志何时写入文件中,spdlog提供了两种刷新方式:
  1)程序正常退出时写入(默认)
  2)程序运行中,在指定位置进行写入(实时刷新日志,便于锁定错误所在位置)

  要想使用实时刷新日志,spdlog提供了两种方法:
  方法一:logger对象->flush_on(设定等级),flush_on是一次性刷新,执行到此时按照设定等级进行日志刷新。
  方法二:logger对象->flush_every(周期时间),flush_every是设置刷新周期,定时进行刷新。刷新的级别采取默认了。

2.7 特性——异常处理

  对于日志库来说,当异常发生时,应该要输出异常出现的位置。spdlog会向std::err打印一条语句(终端可显示)。为了防止异常语句刷屏,打印的频率固定在每分钟一条。

三、spdlog的使用相关

  上一部分介绍了spdlog一些特性,下面结合具体代码明确下各特性的体现。
  使用spdlog一定要明确它的各种头文件,常用的头文件如下所示,使用时选择相关的就可以:
在这里插入图片描述
  最简单的使用:

#include "spdlog/spdlog.h"
 int main()
 {
  //Use the default logger (stdout, multi-threaded, colored)
  spdlog::info("Hello, {}!", "World");
 }

  上面这个代码里面info函数中的格式看上去有点儿奇怪,具体的教程在spdlog输出格式详解_1 - 哔哩哔哩 (bilibili.com)

  日志等级显示:

#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG
#include "spdlog/spdlog.h"

int main()
{
    spdlog::info("{:<30}", "left aligned");
    spdlog::warn("Easy padding in numbers like {:08d}", 12);
    spdlog::error("Some error message with arg: {}", 1);
    spdlog::critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);

    spdlog::set_level(spdlog::level::debug); // Set global log level to debug
    spdlog::debug("This message should be displayed..");

    // change log pattern
    spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v");

    // Compile time log levels
    // define SPDLOG_ACTIVE_LEVEL to desired level,if not define, don't show
    SPDLOG_TRACE("Some trace message with param {}", 42);
    SPDLOG_DEBUG("Some debug message");
    return 0;
}

  三种文件写入方式:

#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/daily_file_sink.h"
#include <iostream>
void basic_logfile_example()
{
    try
    {
        auto logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt");
    }
    catch (const spdlog::spdlog_ex &ex)
    {
        std::cout << "Log init failed: " << ex.what() << std::endl;
    }
}

void rotating_example()
{
    // Create a file rotating logger with 5mb size max and 3 rotated files
    //auto max_size = 1024*1024 * 5;
    auto max_size = 256;
    auto max_files = 3;
    auto logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", max_size, max_files);
    for (int i=0; i<10000; i++) {
        logger->info("{} * {} equals {:>10}",i, i, i*i);
    }
}

void daily_example()
{
    // Create a daily logger - a new file is created every day on 2:30am
    auto logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
}

int main() {
        basic_logfile_example();
        rotating_example();
        daily_example();
        return 0;
}

  再从代码使用上看同时操作所有logger
  1)apply_all操作所有logger进行输出:

spd::apply_all([&](std::shared_ptr<spdlog::logger> l) {
	l->info(“hello world!);
})

  2)drop_all释放所有logger

spdlog::drop_all();

  以上说了spdlog这么多,来总结下它的优点吧(其实也就是特性了):
  1)丰富的日志输出格式,自定义
  2)多种输出文件日志类型,支持控制台
  3)支持单多线程、支持同步异步
  4)清晰的代码结构,便于读者阅读
  5)写日志非常的快,效果很好

留一些学习过程中的参考资料:
参考:spdlog使用_蜗牛单行道的博客-CSDN博客_spdlog
参考:spdlog学习笔记_haojie_superstar的博客-CSDN博客_spdlog
参考(内部有多个demo测试):[C++]-日志记录库SPDLog简介[通俗易懂] - 全栈程序员必看 (javaforall.cn)
参考:spdlog简介_JontyZh的博客-CSDN博客_spdlog 输出格式
源码阅读:spdlog 基本结构分析 - 小胖西瓜 - 博客园 (cnblogs.com)
多线程使用:c++ 日志输出库 spdlog 简介(4)- 多线程txt输出日志 (shuzhiduo.com)

因作者水平有限,如有错误之处,请在下方评论区指正,谢谢!

  • 14
    点赞
  • 87
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
C++中的spdlog是一个快速、易于使用的日志记录库。它提供了多种日志记录模式,支持多线程,具有灵活的格式化选项,并且在性能上表现出色。你可以使用spdlog来记录应用程序中的各种事件、错误和调试信息。 要使用spdlog,首先你需要在你的C++项目中包含spdlog头文件,并将spdlog库链接到你的项目中。你可以通过下载spdlog的源代码并手动添加到你的项目中,或者使用包管理工具(如vcpkg)来安装spdlog。 下面是一个简单的示例,展示了如何在C++中使用spdlog进行日志记录: ```cpp #include <spdlog/spdlog.h> int main() { // 创建一个名为"my_logger"的日志记录器 auto logger = spdlog::stdout_logger_mt("my_logger"); // 设置日志记录级别为调试 spdlog::set_level(spdlog::level::debug); // 记录不同级别的日志信息 logger->info("This is an info message"); logger->warn("This is a warning message"); logger->error("This is an error message"); return 0; } ``` 在上面的示例中,我们创建了一个名为"my_logger"的日志记录器,并将其输出到控制台(stdout)。然后,我们设置日志记录级别为调试(debug),这意味着所有调试级别及更高级别的日志消息都会被记录。 最后,我们使用logger对象记录了一些不同级别的日志消息。日志消息的格式可以根据你的需要进行自定义。 这只是一个简单的示例,你可以根据你的具体需求使用spdlog进行更复杂的日志记录。你可以查看spdlog的文档以获取更多详细信息和示例:https://github.com/gabime/spdlog

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值