日志库-spdlog

1,219 阅读3分钟

spdlog

地址:github.com/gabime/spdl…

两种使用方式,一是下载Release中的Latest版本,把其中include文件夹中的spdlog文件复制到你项目中的include文件夹下。(建议在include下面创建一个third_lib文件夹方便管理第三方Header only文件)。

二是自己编译,将编译好的include复制到你项目中的include文件夹下

$ git clone https://github.com/gabime/spdlog.git
$ cd spdlog && mkdir build && cd build
$ cmake .. && make -j

在CMake中添加头文件路径

INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include/third-lib)

spdlog主要由logger(记录器)和sink(接收器)两部分组成。spdlog的高可拓展体现在loggersink的可由用户自定义。 spdlog内部为每个进程都维护一张全局Logger记录表,记载了用户每个进程中通过factory method创建的Logger实例(某些情况需要用户手动注册)。因而,在使用Logger时极其方便,只需要知道创建时指定的名称即可。因此,我们可以通过工厂方法创建一个名为async_file_logger异步Logger,输出到/logs/async_log.txt

auto async_file = spdlog::basic_logger_mtspdlog::async_factory("async_file_logger", "logs/async_log.txt");
auto logger = spdlog::get("async_file_logger");
logger->info("some things want to say.");

logger

基础使用

#include "spdlog/spdlog.h"

int main() 
{
    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");
    
    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
    SPDLOG_TRACE("Some trace message with param {}", 42);
    SPDLOG_DEBUG("Some debug message");
}

控制台日志

stdout_color_mt多线程,stdout_color_st单线程

# 控制台日志
#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
void stdout_example()
{
    // create color multi threaded logger
    auto console = spdlog::stdout_color_mt("console");    
    auto err_logger = spdlog::stderr_color_mt("stderr");    
    spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)");
}

创建logger

使用spdlog自带的logger

auto logger1 = spdlog::stdout_color_st("LoggerName1"); //创建名称为LoggerName1、内容输出到控制台的单线程版本日志记录器

//<2.创建名称为LoggerName2、内容输出到Logs/BasicFileLog.txt的多线程版本日志记录器
auto logger2 = spdlog::basic_logger_mt("LoggerName2", "Logs/BasicFileLog.txt");

//<3.创建名称为LoggerName3、内容输出到Logs/RotatingFileLog.txt的多线程版本日志记录器
//参数1024*1024*5设置了文件最大容量为5mb,参数3设置了文件最大数量为3
//当日志文件存储超过5mb时,将重命名日志文件并且新增另外一个日志文件
//当日志文件数量超过3时,将删除第一个日志文件
auto logger3 = spdlog::rotating_logger_mt("LoggerName3", "Logs/RotatingFileLog.txt", 1024 * 1024 * 5, 3);

//<4.创建名称为LoggerName4、内容输出到Logs/DailyFileLog.txt的多线程版本日志记录器
//参数2和30指定每天生成日志文件的时间为凌晨2点30分
auto logger4 = spdlog::daily_logger_mt("LoggerName4", "Logs/DailyFileLog.txt", 2, 30);

使用sink创建logger

//<1.创建名称为LoggerName1、内容输出到控制台的单线程版本日志记录器
auto logger1 = std::make_shared[spdlog::logger](spdlog::logger)("LoggerName1",
std::make_shared[spdlog::sinks::stdout_color_sink_st](spdlog::sinks::stdout_color_sink_st)());

//<2.创建名称为LoggerName2、内容输出到Logs/BasicFileLog.txt的多线程版本日志记录器
auto logger2 = std::make_shared[spdlog::logger](spdlog::logger)("LoggerName2", std::make_shared[spdlog::sinks::basic_file_sink_mt](spdlog::sinks::basic_file_sink_mt)("Logs/BasicFileLog.txt"));

//<3.创建名称为LoggerName3、内容输出到Logs/RotatingFileLog.txt的多线程版本日志记录器
//参数1024*1024*5设置了文件最大容量为5mb,参数3设置了文件最大数量为3
//当日志文件存储超过5mb时,将重命名日志文件并且新增另外一个日志文件
//当日志文件数量超过3时,将删除第一个日志文件
auto logger3 = std::make_shared[spdlog::logger](spdlog::logger)("LoggerName3", std::make_shared[spdlog::sinks::rotating_file_sink_mt](spdlog::sinks::rotating_file_sink_mt)("Logs/RotatingFileLog.txt",1024 * 1024 * 5, 3));

//<4.创建名称为LoggerName4、内容输出到Logs/DailyFileLog.txt的多线程版本日志记录器
//参数2和30指定每天生成日志文件的时间为凌晨2点30分
auto logger4 = std::make_shared[spdlog::logger](spdlog::logger)("LoggerName4",
std::make_shared[spdlog::sinks::daily_file_sink_mt](spdlog::sinks::daily_file_sink_mt)("Logs/DailyFileLog.txt", 2,30));

创建使用同个sink的多个logger

//<1.创建sink
auto sink = std::make_sharedspdlog::sinks::rotating_file_sink_mt("Logs/RotatingFileLog.txt", 1024 * 1024 * 5, 3);

//<2.创建共同使用sink的多个logger,这些logger把内容一起输出到RotatingFileLog.txt中
auto logger1 = std::make_shared[spdlog::logger](spdlog::logger)("LoggerName1", sink);
auto logger2 = std::make_shared[spdlog::logger](spdlog::logger)("LoggerName2", sink);
auto logger3 = std::make_shared[spdlog::logger](spdlog::logger)("LoggerName3", sink);

创建使用多个sink的单个logger

//<1.创建多个sink
auto sink1 = std::make_sharedspdlog::sinks::stdout_color_sink_mt();
auto sink2 = std::make_sharedspdlog::sinks::rotating_file_sink_mt("Logs/RotatingFileLog.txt", 1024 * 1024 * 5, 3);
std::vector< spdlog::sink_ptr> sinks = { sink1,sink2 };

//<2.创建使用多个sink的单个logger,logger会把内容输出到不同位置,此处是控制台以及RotatingFileLog.txt
auto logger = std::make_sharedspdlog::logger("LoggerName", sinks.begin(), sinks.end());

设置logger

//<1.创建多个sink

auto sink1 = std::make_shared[spdlog::sinks::stdout_color_sink_mt](spdlog::sinks::stdout_color_sink_mt)();

auto sink2 = std::make_shared[spdlog::sinks::rotating_file_sink_mt](spdlog::sinks::rotating_file_sink_mt)("Logs/RotatingFileLog.txt", 1024 * 1024 * 5, 3);

std::vector< spdlog::sink_ptr> sinks = { sink1,sink2 };

//<2.创建使用多个sink的单个logger,logger会把内容输出到不同位置,此处是控制台以及RotatingFileLog.txt
auto logger = std::make_shared[spdlog::logger](spdlog::logger)("LoggerName", sinks.begin(), sinks.end());

//<3.设置sink的pattern和level
sink1->set_pattern("[%Y-%m-%d %H:%M:%S.%e][%l]>>>%v");
sink1->set_level(spdlog::level::debug);
sink2->set_pattern("[%Y-%m-%d][%L]%v");
sink2->set_level(spdlog::level::info);

//<4.输出日志
logger->debug("The message will only be shown on stdout.");//因为日志等级为debug,所以只会调用sink1进行输出
logger->info("The message will only be shown on stdout.");//日志等级为info,sink1与sink2都会进行输出

使用logger

通过spdlog::get(std::string)获取指定名称的logger进行使用

//<1.创建logger
//A.cpp
auto logger1 = std::make_shared<spdlog::logger>("LoggerName1", 
std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
auto logger2 = std::make_shared<spdlog::logger>("LoggerName2", 
std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
spdlog::register(logger2);
auto logger3 = spdlog::stdout_color_st("LoggerName3");

//<2.使用spdlog::get(std::string)获取logger
//B.cpp
auto logger1 = spdlog::get("LoggerName1");//logger1为空,因为logger1在A.cpp中没被注册
if (logger1)
{
    logger1->info("Hello world!");
}
auto logger2 = spdlog::get("LoggerName2");//logger2不为空,因为logger2在A.cpp中已被注册
if (logger2)
{
    logger2->info("Good night.");//输出
}
auto logger3 = spdlog::get("LoggerName3");//logger2不为空,因为spdlog自带的logger对象在构造时会自动注册
if (logger3)
{
    logger3->info("Good night.");//输出
}

日志级别

spdlog中显示信息的级别

trace = SPDLOG_LEVEL_TRACE // 最低级(用来记录代码执行轨迹)
debug = SPDLOG_LEVEL_DEBUG //      (用来记录debug信息)
info = SPDLOG_LEVEL_INFO   
warn = SPDLOG_LEVEL_WARN
err = SPDLOG_LEVEL_ERROR
critical = SPDLOG_LEVEL_CRITICAL
off = SPDLOG_LEVEL_OFF     // 最高级

设定日志级别的作用在在于,我们可以在程序运行前就指定我们想要显示哪些信息,为此我们可以用如下代码来控制显示级别

spdlog::set_level(spdlog::level::info); // 只显示info及比info高级的信息,trace 和 debug 

输出文件

// include 相关头文件
// include "spdlog/sinks/basic_file_sink.h"
// 开启并创建本地日志
auto my_logger = spdlog::basic_logger_mt("file_logger", "logs/basic-log.txt");

// 设置该日志的显示级别
my_logger->set_level(spdlog::level::warn);

// 向该日志中写入信息
my_logger->info("Hello, {}!", "World");

// 实时刷新日志
my_logger->flush_on(spdlog::level::trace);

用上面的方法输出的日志仅在程序正常退出时才写入。但有时候,我们希望在程序不正常退出时查看日志以帮助我们锁定错误所在位置,由此可以加入下方代码。