spdlog 简介与基础示例

本文详细介绍了spdlog库的安装、基本使用方法以及不同类型的sink(如屏幕输出、文件记录、日志大小限制、时间周期刷新等)的示例,展示了如何设置log级别、多sink配置和使用syslog。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0. 概况

0.1 源码搭建环境

源码网址:

GitHub - gabime/spdlog: Fast C++ logging library.

可以只是用头文件,也可以先编译后使用;后面的示例都是直接使用头文件的方式。

编译方法:

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

0.2 一些情况

spdlog 的 6 个log等级,定义在 spdlog/include/spdlog/common.h 中,如下;
平时打开的是 INFO,小于INFO等级的log将不被记录,这起到了filter的作用。


#define SPDLOG_LEVEL_TRACE 0
#define SPDLOG_LEVEL_DEBUG 1
#define SPDLOG_LEVEL_INFO 2
#define SPDLOG_LEVEL_WARN 3
#define SPDLOG_LEVEL_ERROR 4
#define SPDLOG_LEVEL_CRITICAL 5
#define SPDLOG_LEVEL_OFF 6


通过SPDLOG_ACTIVE_LEVEL这个宏来打开默认log等级:
#if !defined(SPDLOG_ACTIVE_LEVEL)
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
#endif


可以通过调用函数
#include "spdlog/spdlog.h"
spdlog::set_level(spdlog::level::debug);


来将log等级降低到SPDLOG_LEVEL_DEBUG
因为有这样的定义:


enum level_enum
{
    trace = SPDLOG_LEVEL_TRACE,
    debug = SPDLOG_LEVEL_DEBUG,
    info = SPDLOG_LEVEL_INFO,
    warn = SPDLOG_LEVEL_WARN,
    err = SPDLOG_LEVEL_ERROR,
    critical = SPDLOG_LEVEL_CRITICAL,
    off = SPDLOG_LEVEL_OFF,
    n_levels
};


1. 第一个示例

这是最基础的使用,打印在显示器上

test.cpp

#include "spdlog/spdlog.h"

int main() 
{
    //如下方式是直接打印到屏幕上的log信息
    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");
}


build:
Makefile

TARGETS = test test_stdout_stderr test_logfile example rotate_log_test daily_log_test  backtrace_log stopwatch_log

all: $(TARGETS)

%: %.cpp
	g++ $< -o $@ -I../spdlog/include

.PHONY:clean
clean:
	-rm -f $(TARGETS)


2. 第二个示例

test_logfile.cpp

#include "spdlog/sinks/basic_file_sink.h"
//#include "spdlog/spdlog.h"
#include <iostream>
//using namespace

void basic_logfile_example()
{
    try 
    {
        // 这句返回一个指针类型 std::shared_ptr<logger>,具体定义在 spdlog/include/spdlog/sinks/basic_file_sink.h 中
        auto logger = spdlog::basic_logger_mt("writer ID", "logs/basic-log.txt");
        
        //这句将使用追加的方式,向文件logs/basic-log.txt中写入信息;格式是四个字段[time][writer ID][type][message]
        logger->info("hello spdlog world\n {}", 3.345);
        logger->error("hello error log {}", 78.9);
        logger->critical("hello critical log {}", 12,34);
        //spdlog::set_level(spdlog::level::debug);//需要打开#include "spdlog/spdlog.h"
        logger->debug("hello debug log {}  ",11.11);//这句不会被记录,因为记录等级不到debug,除非事前设置记录log的等级
        logger->warn("hello warn log {}",77.77);
        //spdlog::get("logger")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)");

	
    }
    catch (const spdlog::spdlog_ex &ex)
    {
        std::cout << "Log init failed: " << ex.what() << std::endl;
    }
}

int main()
{
	basic_logfile_example();

	return 0;
}


3. 第三个示例

rotate_log_test.cpp

#include "spdlog/sinks/rotating_file_sink.h"
void rotating_example()
{
    //如果log足够多,那么最多创建3个log文件,分别在文件名后缀加 log.1.txt  log.2.txt  log.3.txt,每个文件最大到5MB
    // Create a file rotating logger with 5 MB size max and 3 rotated files
    auto max_size = 1048576 * 5;
    auto max_files = 3;
    //这句会创建一个log文件 logs/rotating_test.txt
    auto logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating_test.txt", max_size, max_files);
    //如果一次log缓冲的数据量足够大,使用logs/rotating_test.txt的过程中,当 logs/rotating_test.txt 的文件等于5MB时,将会被首先移动(mv)成 logs/rotating_test.1.txt
    //如果log在logs/rotating_test.txt中再次达到5MB时,将会先把 logs/rotating_test.1.txt 移动(shell mv)成 logs/rotating_test.2.txt,再将 logs/rotating_test.txt 移动(mv)成 logs/rotating_test.1.txt
    //以此类推,总之直接写入的文件是logs/rotating_test.txt
    
    //下面的循环执行结束后,超过5MB,会被移动成.1.txt文件
    for(int i=0; i<1024*16*5;i++){
        logger->info("111111111");
        //{printf("1");}
        //logger->error("llo rotate errhelllllllll");
    }
    
    for(int i=0; i<1024*16*5;i++){
        logger->info("211111111");
        //logger->error("hello rotate errhelllllllll");
    }

    for(int i=0; i<1024*16*5;i++){
        //logger->info("3");
        logger->error("311111111");
    }
}

int main()
{
	rotating_example();

	return 0;
}

4. 第四个示例


daily_log_test.cpp  


#include "spdlog/sinks/daily_file_sink.h"
void daily_example()
{
    //如果是一个常驻的程序,比如服务器守护进程,那么每天都会重现创建一个log文件,即删除以前的内容,只记录当天创建之后的log信息;
    // Create a daily logger - a new file is created every day at 2:30 am
    auto logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 12, 56);
    logger->info("hello 01");
    logger->info("hello 02");
}


int main()
{
    daily_example();

    return 0;


}

5. 第五个示例


backtrace_log.cpp

#include "spdlog/spdlog.h"

int main()
{
  //这个 case 是一个场景应用案例,可以这么来用,仅记录本逻辑线路的最后几条log而已,记录在内存中;在需要的时候,将其dump出来。本逻辑线路的
// Debug messages can be stored in a ring buffer instead of being logged immediately.
// This is useful to display debug logs only when needed (e.g. when an error happens).
// When needed, call dump_backtrace() to dump them to your log.

  spdlog::enable_backtrace(32); // Store the latest 32 messages in a buffer. 
// or my_logger->enable_backtrace(32)..
  for(int i = 0; i < 100; i++)
  {
    spdlog::debug("Backtrace message {}", i); // not logged yet..
  }
// e.g. if some error happened:
  spdlog::dump_backtrace(); // log them now! show the last 32 messages
// or my_logger->dump_backtrace(32)..
//
	return 0;
}

6. 第六个示例


stopwatch_log.cpp

#include "spdlog/spdlog.h"
// Stopwatch support for spdlog
#include "spdlog/stopwatch.h"

//码表,用于统计时间
void stopwatch_example()
{
    spdlog::stopwatch sw, sw2;
    spdlog::info("Elapsed {}    {}", sw, sw2);//输出的单位是秒S
    spdlog::info("Elapsed {:.3}     {:.3}", sw, sw2);

    //重置为0,从新计时
    sw.reset();
    spdlog::info("Elapsed {:.3}     {:.3}", sw, sw2);
    std::this_thread::sleep_for(std::chrono::milliseconds(123));//线程休眠123ms
    spdlog::info("Elapsed {:.3}     {:.3}", sw, sw2);
    //float s=0.0f;
    //
}

int main()
{
	stopwatch_example();

	return 0;
}

7. 第七个示例

sinks_log.cpp

建立多个信息渠道,绑定到同一个logger上,对信息进行区别对待,根据不同的级别设置过滤本sink对信息的接受或拒绝;

#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/basic_file_sink.h"

// create a logger with 2 targets, with different log levels and formats.
// The console will show only warnings or errors, while the file will log all.
void multi_sink_example()
{
    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    console_sink->set_level(spdlog::level::warn);
    console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v");

    auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt", true);
    file_sink->set_level(spdlog::level::trace);

    spdlog::logger logger("multi_sink", {console_sink, file_sink});
    //如果总体重新设计,将会导致前面的单独设置失效
    //logger.set_level(spdlog::level::debug);//
    logger.warn("this should appear in both console and file");
    logger.info("this message should not appear in the console, only in the file");
}

int main()
{
	multi_sink_example();
	
	return 0;
}

sinks_log的效果:

8. 一个比较尴尬的case,拿出来晒晒

#include <spdlog/sinks/syslog_sink.h>

int main() {
    std::string logger_name = "my_logger";
    std::string syslog_ident = "my_syslog_ident";

    auto syslog_sink = std::make_shared<spdlog::sinks::syslog_sink_mt>(syslog_ident, LOG_USER);
    auto logger = std::make_shared<spdlog::logger>(logger_name, syslog_sink);

//    spdlog::register_logger(logger);

    logger->info("Hello, syslog!");

    return 0;
}



#if 0 


#include <chrono>

#include <spdlog/spdlog.h>
#include <spdlog/sinks/syslog_sink.h>
#include <spdlog/sinks/dup_filter_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>

int main() {
    auto dup_filter = std::make_shared<spdlog::sinks::dup_filter_sink_mt>(std::chrono::seconds(5));
    dup_filter->add_sink(std::make_shared<spdlog::sinks::syslog_sink_mt> ("filtered_syslog_sink_mt"));
    spdlog::logger l("logger", dup_filter);
    l.info("Hello");
    l.info("Hello");
    l.info("Hello");
    l.info("Different Hello");
}

//#else
// 本实例适合于v1.3.1 版本的spdlog
#include<string>
#include "spdlog/spdlog.h"
#include "spdlog/sinks/syslog_sink.h"

int main() {
    std::string logger_name = "my_logger";
    std::string syslog_ident = "my_syslog_ident";

    //auto syslog_sink = std::make_shared<spdlog::sinks::syslog_sink_mt>(syslog_ident, LOG_PID, LOG_USER);//v1.3.1
    auto syslog_sink = std::make_shared<spdlog::sinks::syslog_sink_mt>(syslog_ident,  LOG_USER);
    auto logger = std::make_shared<spdlog::logger>(logger_name, syslog_sink);

    spdlog::register_logger(logger);
//log信息需要到系统目录下查看: cat /var/log/syslog
    logger->info("Hello, syslog!");

    return 0;
}
#endif

另外为了及时全部存盘,还有如下函数 flush_every()
//用来控制强制存盘的时间周期,用来防止断电丢失太多日志信息。
// periodically flush all *registered* loggers every 3 seconds:
// warning: only use if all your loggers are thread-safe ("_mt" loggers)
spdlog::flush_every(std::chrono::seconds(3));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值