开源日志库spdlog的使用心得

发布时间 2023-06-28 16:26:42作者: DoubleLi

所有大型项目中都需要实现日志功能。此功能看似简单实则不然,实现一个高速、稳定、功能完善的日志中心是每一个大型项目的必经之路。spdlog是目前Github上一款基于C/C++的开源日志库。它有以下特点:

  • 速度非常快

  • 只包含头文件

  • 无需依赖第三方库

  • 支持跨平台 - Linux / Windows on 32/64 bits / Mac OS

  • 支持多线程

  • 可对日志文件进行循环输出

  • 可每日生成日志文件

  • 支持控制台日志输出

  • 可选的异步日志

  • 支持日志输出级别

  • 可自定义日志格式

    实际使用下来确实比较舒服。首先spdlog不需要编译,引入头文件就行,用起来非常简单。其次它的循环日志文件和异步打印日志这两个功能也非常好用,让整个日志功能变得非常的优雅。

最简单的使用场景

这种场景下日志直接在控制台输出,一般不会用这个的,比较的低级。但是可以看出spdlog的格式化输出形式和传统的C/C++不太相像,更偏向于Python一点。实际用起来也更简单。

#include "spdlog/spdlog.h"
int main()
{
    spdlog::info("Hello, {}!", "World");
}

单一日志文件的使用场景

my_logger作为日志的生产者可以初始化为一个全局变量。这种用法也不会常用,功能太少。

#include <iostream>
#include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h" // support for basic file logging

int main(int, char* [])
{
    try 
    {
        auto my_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic.txt");
        my_logger->info("Hello {}", "world");
    }
    catch (const spdlog::spdlog_ex& ex)
    {
        std::cout << "Log initialization failed: " << ex.what() << std::endl;
    }
}

循环日志文件的使用场景

​ 这种场景就比较常见了。首先日志不能一直不限量的增长,达到一定量必须分割为多文件;其次日志文件的数量也不能无限增长,否则日志量一大会把硬盘撑爆。循环日志文件能轻易解决以上两个问题。

#include <iostream>
#include "spdlog/spdlog.h"
#include "spdlog/sinks/rotating_file_sink.h" // support for rotating file logging

int main(int, char* [])
{
    try 
    {
        auto file_logger = spdlog::rotating_logger_mt("file_logger", "myfilename", 
                                                      1024 * 1024 * 5, 10);
	    file_logger->set_level(spdlog::level::debug);
        while (i < 1000000)
        {
            file_logger->debug("Async message #{}", i);
            i++;
        }
    }
    catch (const spdlog::spdlog_ex& ex)
    {
        std::cout << "Log initialization failed: " << ex.what() << std::endl;
    }
}

区别于单一文件,循环日志的生产者类是rotating_logger_mt。rotating_logger_mt初始化的时候需要4个参数。

  1. 生产者的名字,自定义即可;
  2. 日志文件路径,相对和绝对均可;
  3. 单一文件的大小,超过了设置大小就生成一个新的文件。上面代码中设置为5MB;
  4. 保留文件数量,超过数量的文件会直接删掉以节省空间。正常使用的时候此数字大一些较好。

代码中生成100万条日志,数据大约是65MB。那么在根目录下就会出现10个日志文件,后缀名由1~9。最初的3个文件则会被删除。

异步打印日志文件

​ 大型项目中经常有很多场景是对时间有着严苛要求的,此时异步调用打印日志功能就显得十分重要了。spdlog实现异步打印日志的功能也是非常地简单。

#include <iostream>
#include "spdlog/spdlog.h"
#include "spdlog/async.h"
#include "spdlog/sinks/rotating_file_sink.h"

int main(){
    spdlog::init_thread_pool(10000, 1);
    auto file_logger = spdlog::rotating_logger_mt<spdlog::async_factory>("file_logger", "mylogs", 1024 * 1024 * 5, 100);
    int i = 0;
    file_logger->set_level(spdlog::level::debug);
    while (i < 1000000)
    {
        file_logger->debug("Async message #{}", i);
        i++;
    }
    spdlog::drop_all();
    return 0;
}

​ 在初始化的时候使用异步工厂spdlog::async_factory进行初始化即可。

其他功能

​ spdlog除了以上功能,还可以按天分割文件,多源写入同条日志,自定义日志格式等功能。

缺点

​ 目前这个库有一大缺陷就是不支持日志压缩,要知道项目中如果打开了Debug级别的日志,日志量可能是非常恐怖的,如果分割文件的时候不能压缩文件将是对硬盘空间的极大浪费(日志压缩率一般在95%左右)。但是既然是开源项目,自己改源代码也是可以的。