spdlog
日志库说明文档(超详细)
spdlog
是一个开源、快速、只有头文件的C++11日志库,code地址在https://github.com/gabime/spdlog,基础示例在https://github.com/gabime/spdlog#readme
优点
- 只包含头文件
- 速度很快
- 无需依赖第三方库
- 支持跨平台 - Linux / Windows on 32/64 bits
- 支持多线程
- 可对日志文件进行循环输出
- 可每日生成日志文件
- 可支持控制台日志输出
- 可选的异步日志
- 可定义日志格式
如何使用
首先将代码下载下来https://github.com/gabime/spdlog,解压后会得到以下文件,其中include文件夹里是所需的头文件和源码
新建一个C++控制台应用程序项目,然后在项目属性页C/C++中常规的附加包含目录中加上include的路径,然后在.cpp
中就可以开始测试了
最简单的使用场景
直接在控制台输出,比较低级。
#include "spdlog/spdlog.h"
int main()
{
//输出不同级别的日志
spdlog::info("Hello, {}!", "World");
spdlog::info("Welcome to spdlog!");
spdlog::error("Some error message with arg: {}", 1);
spdlog::warn("Easy padding in numbers like {:08d}", 12);
spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
spdlog::info("Support for floats {:03.2f}", 1.23456);
spdlog::info("Positional args are {1} {0}..", "too", "supported");
spdlog::info("{:<30}", "left aligned");
}
warn,critical,info为不同等级的log,输出在控制台会以不同颜色表示
单一日志文件的使用场景
my_logger作为日志的生产者可以初始化为一个全局变量,这种用法功能也比较少
#include <iostream>
#include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h" // support for basic file logging
int main()
{
try
{
//在logs/basic.txt中写下Hello world
auto my_logger = spdlog::basic_logger_mt("sbasic_logger", "logs/basic.txt");
my_logger->info("Hello {}", "world");
}
catch (const spdlog::spdlog_ex& ex)
{
std::cout << "Log initialization failed: " << ex.what() << std::endl;
}
}
auto my_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic.txt");
中”my_logger“为logger名称,可以随意命名
注意,logger使用完,程序关闭之前需要调用drop函数释放logger对象,如果程序没有关闭,就无法建立同样名称的logger
这种basic log
不带滚动,日志文件会一直被写入,不断变大
函数名带后缀_mt的意思是multi thread(速度稍微慢一点点,考虑了多线程并发),_st的意思是single thread(速度较快)
循环日志文件的使用场景
循环日志文件可以解决两个问题:
- 当日志达到一定量后必须分割为多文件
- 保证日志文件的数量不会无限增长
#include <iostream>
#include "spdlog/spdlog.h"
#include "spdlog/sinks/rotating_file_sink.h" // support for rotating file logging
int main()
{
try
{
auto file_logger = spdlog::rotating_logger_mt("file_logger", "myfilename",
1024 * 1024 * 5, 10);
file_logger->set_level(spdlog::level::debug);
int i = 0;
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个参数。
- 生产者的名字,自定义即可;
- 日志文件路径,相对和绝对均可;
- 单一文件的大小,超过了设置大小就生成一个新的文件。上面代码中设置为
5MB
; - 保留文件数量,超过数量的文件会直接删掉以节省空间。正常使用的时候此数字大一些较好。
代码中生成100万条日志,数据大约是65MB
。那么在根目录下就会出现10个日志文件,后缀名由1~9。
rotating log
滚动日志,当日志文件超出规定大小时,会删除当前日志文件中所有内容,重新开始写入
daily log的使用
每天会新建一个日志文件,新建日志文件的时间可以自己设定
#include <iostream>
#include "spdlog/spdlog.h"
#include "spdlog/sinks/daily_file_sink.h"
int main() {
// Create a daily logger - a new file is created every day on 2:30am
auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
// trigger flush if the log severity is error or higher
daily_logger->flush_on(spdlog::level::err);
daily_logger->info(123.44);
return 0;
}
如果程序不退出,每天2:30
会创建新的文件
异步打印日志文件
大型项目中经常有很多场景是对时间有着严苛要求的,此时异步调用打印日志功能就显得十分重要了。
#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
进行初始化即可。
缺点
目前这个库有一大缺陷就是不支持日志压缩,要知道项目中如果打开了Debug级别的日志,日志量可能是非常恐怖的,如果分割文件的时候不能压缩文件将是对硬盘空间的极大浪费(日志压缩率一般在95%左右)。