C++高性能日志库spdlog使用指南

本文介绍了spdlog,一个专为C++设计的高性能日志库,其注重速度和易用性,支持跨平台、丰富的日志级别、自定义格式、多目标输出和线程安全。文章详细展示了如何使用spdlog进行控制台和文件日志记录,以及异步和条件日志功能。
摘要由CSDN通过智能技术生成

spdlog库简介

  • spdlog 是一个高性能的 C++ 日志库,它设计时充分考虑了速度和易用性,具有以下特点
    • 高效与快速:Spdlog 专注于提供极致的性能,在大量日志记录场景下也能保持较低的延迟和较高的吞吐量。
    • 轻量化设计:Spdlog 是头文件(header-only)库,这意味着用户只需要包含相应的头文件即可开始使用,无需编译链接额外的库文件。
    • 跨平台支持:它支持多种操作系统,包括但不限于 Windows、Linux 和 macOS,并且在这些平台上都能够良好运行。
    • 丰富的日志级别:Spdlog 支持常见的日志级别,如 TRACE、DEBUG、INFO、WARN、ERROR、CRITICAL 等,用户可以根据需要选择不同级别的日志输出。
    • 格式化与定位信息:通过集成 fmt 库,Spdlog 允许用户自定义日志消息的格式,可以轻松地包含时间戳、线程ID、文件名、行号以及函数名等上下文信息。
    • 多目标输出:可以将日志输出到控制台、普通文本文件、循环写入文件(rotating log files)、每日生成新文件(daily logs)、系统日志等目标,同时也支持异步写入以提高性能。
    • 线程安全:对于多线程环境,Spdlog 提供了线程安全的日志接口,确保在并发环境下日志记录的正确性和完整性。
    • 异步模式:提供可选的异步日志记录机制,能够将日志操作放入后台线程执行,从而避免阻塞主线程。
    • 条件日志:根据预定义的条件开关,可以动态启用或禁用特定级别的日志输出。

使用步骤

  • spdlog库的使用也非常简单,只需要下载源代码,然后把根目录下的include目录下的文件拷贝到我们的工程下,在工程中包含相应的头文件即可。

实例演示

控制台打印

  • 首先看下最简单的使用,如何在控制台打印以及如何进行参数化打印。
  • main.cpp
  •   #include <spdlog/spdlog.h>
      #include <string.h>
      #include <iostream>
      
      int main()
      {
      	// 普通打印
      	spdlog::info("Welcome to info spdlog!");
      
      	// 格式化打印
      	// 打印字符串
      	spdlog::info("Hello World {}", "spdlog!");
      	// 打印数字
      	spdlog::error("spdlog errCode : {}", -10020);
      	// 指定打印数字的占位符
      	spdlog::warn("spdlog format char {:08d}", 12);
      	// 格式化打印不同进制的数据
      	spdlog::critical("Support for int:{0:d} hex:{0:x} oct:{0:o} bin:{0:b}", 42);
      	// 打印浮点型数据
      	spdlog::info("float args are {:03.2f}", 1.23456);
      	// 打印多个参数
      	spdlog::info("string args are {0} {1}..", "too", "supported");
      	spdlog::info("number args are {0} {1} {2}..", 10020, 10040, -100);
      
      	system("pause");
      }
    
  • 执行结果
    在这里插入图片描述
  • 这里参数化打印的实现是通过 {} 实现的,跟常见函数的参数化打印有点不一样。

在文件中打印日志

  • 接下来就看下如何在文件中打印日志
  • main.cpp
  •   #include <spdlog/spdlog.h>
      #include <spdlog/sinks/basic_file_sink.h>
      #include <string.h>
      #include <iostream>
      
      int main()
      {
      	try
      	{
      		// 参数1 日志标识符, 参数2 日志文件名
      		std::shared_ptr<spdlog::logger> mylogger = spdlog::basic_logger_mt("spdlog", "spdlog.log");
      		// 设置日志格式. 参数含义: [日志标识符] [日期] [日志级别] [线程号] [数据]
      		mylogger->set_pattern("[%n][%Y-%m-%d %H:%M:%S.%e] [%l] [%t]  %v");
      		mylogger->set_level(spdlog::level::debug);
      		spdlog::flush_every(std::chrono::seconds(5)); // 定期刷新日志缓冲区
      
      		mylogger->trace("Welcome to info spdlog!");
      		mylogger->debug("Welcome to info spdlog!");
      		mylogger->info("Welcome to info spdlog!");
      		mylogger->warn("Welcome to info spdlog!");
      		mylogger->error("Welcome to info spdlog!");
      		mylogger->critical("Welcome to info spdlog!");
      
      		// 刷新
      		mylogger->flush_on(spdlog::level::debug);
      	}
      	catch (const spdlog::spdlog_ex& ex)
      	{
      		std::cout << "Log initialization failed: " << ex.what() << std::endl;
      	}
      
      	system("pause");
      }
    
  • 执行结果。执行程序后就会在当前目录下生成一个spdlog.log文件,可以看下打印内容
    在这里插入图片描述
    在这里插入图片描述

多个文件中打印

  • 一般都需要在多个文件中打印,下面都通过两个文件演示下
  • main.cpp
  •   #include <spdlog/spdlog.h>
      #include <spdlog/sinks/basic_file_sink.h>
      #include <string.h>
      #include <iostream>
      #include "myfunc.h"
      
      
      int main()
      {
      	try
      	{
      		// 基本文件
      		std::shared_ptr<spdlog::logger> my_logger = spdlog::basic_logger_mt("spdlog", "spdlog.txt");
      		// 设置日志格式. 参数含义: [日志标识符] [日期] [日志级别] [线程号] [数据]
      		my_logger->set_pattern("[%n][%Y-%m-%d %H:%M:%S.%e] [%l] [%t] %v");
      		my_logger->set_level(spdlog::level::debug);
      		spdlog::flush_every(std::chrono::seconds(5)); // 定期刷新日志缓冲区
      
      		my_logger->trace("Welcome to info spdlog!");
      		my_logger->debug("Welcome to info spdlog!");
      		my_logger->info("Welcome to info spdlog!");
      		my_logger->error("Welcome to info spdlog!");
      
      		myFuncTest();
      
      		my_logger->flush();
      
      		system("pause");
      	}
      	catch (const spdlog::spdlog_ex& ex)
      	{
      		std::cout << "Log initialization failed: " << ex.what() << std::endl;
      	}
      }
    
    
  • myfunc.cpp
  •   #include "myfunc.h"
      #include <spdlog/spdlog.h>
      
      void myFuncTest(){
      	std::shared_ptr<spdlog::logger> mylogger = spdlog::get("spdlog");
      
      	mylogger->trace("Welcome to myFuncTest!");
      	mylogger->debug("Welcome to myFuncTest!");
      	mylogger->info("Welcome to myFuncTest!");
      	mylogger->error("Welcome to myFuncTest!");
      }
    
  • 在main函数中定义了 mylogger 对象后,在其他文件中通过 spdlog::get 获取到这个对象,就可以打印了。
  • 打印结果
  • 在这里插入图片描述

打印文件名和行号

  • main.cpp
  •   #define SPDLOG_ACTIVE_LEVEL SPDLOG_LOGGER_TRACE
      #include <spdlog/spdlog.h>
      #include <spdlog/sinks/basic_file_sink.h>
      #include <string.h>
      #include <iostream>
      
      int main()
      {
      	try
      	{
      		std::shared_ptr<spdlog::logger> my_logger = spdlog::basic_logger_mt("spdlog", "basic.txt");
      		// 设置日志格式. 参数含义: [日志标识符] [日期] [日志级别] [线程号] [文件名 函数名:行号] [数据]
      		my_logger->set_pattern("[%n] [%Y-%m-%d %H:%M:%S.%e] [%l] [%t] [%s %!:%#]  %v");
      		my_logger->set_level(spdlog::level::debug);
      		spdlog::flush_every(std::chrono::seconds(5)); // 定期刷新日志缓冲区
      
      		SPDLOG_LOGGER_TRACE(my_logger, "Welcome to trace spdlog");
      		SPDLOG_LOGGER_DEBUG(my_logger, "Welcome to debug spdlog");
      		SPDLOG_LOGGER_INFO(my_logger, "Welcome to info spdlog");
      		SPDLOG_LOGGER_WARN(my_logger, "Welcome to warn spdlog");
      		SPDLOG_LOGGER_ERROR(my_logger, "Welcome to error spdlog");
      
      		my_logger->flush();
      	}
      	catch (const spdlog::spdlog_ex& ex)
      	{
      		std::cout << "Log initialization failed: " << ex.what() << std::endl;
      	}
      }
    
  • 特别说明
    • 如果需要打印文件名、函数名和行号,必须在文件开头定义以下宏。如果要在多个文件中打印,也必须在文件开头定义这个宏。否则只会打印默认级别,set_level 设置的日志级别不会生效。
    •   #define SPDLOG_ACTIVE_LEVEL SPDLOG_LOGGER_TRACE
      
    • 并且要使用 SPDLOG_LOGGER* 系列函数打印。
  • 打印结果
  • 在这里插入图片描述

在线程中打印

  • main.cpp
  •   #include <spdlog/spdlog.h>
      #include <spdlog/sinks/basic_file_sink.h>
      #include <string.h>
      #include <iostream>
      #include <windows.h>
      #include <process.h>
      
      unsigned int __stdcall ThreadFun(PVOID lpParam) {
      	std::shared_ptr<spdlog::logger> mylogger = spdlog::get("spdlog");
      
      	mylogger->trace("Welcome to ThreadFun!");
      	mylogger->debug("Welcome to ThreadFun!");
      	mylogger->info("Welcome to ThreadFun!");
      	mylogger->error("Welcome to ThreadFun!");
      
      	return 0;
      }
      
      
      int main()
      {
      	try
      	{
      		// 基本文件
      		std::shared_ptr<spdlog::logger> my_logger = spdlog::basic_logger_mt("spdlog", "spdlog.txt");
      		// 设置日志格式. 参数含义: [日志标识符] [日期] [日志级别] [线程号] [数据]
      		my_logger->set_pattern("[%n][%Y-%m-%d %H:%M:%S.%e] [%l] [%t] %v");
      		my_logger->set_level(spdlog::level::debug);
      		spdlog::flush_every(std::chrono::seconds(5)); // 定期刷新日志缓冲区
      
      		my_logger->trace("Welcome to trace spdlog!");
      		my_logger->debug("Welcome to debug spdlog!");
      		my_logger->info("Welcome to info spdlog!");
      		my_logger->error("Welcome to error spdlog!");
      
      		HANDLE handle1 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun, NULL, 0, NULL);
      		HANDLE handle2 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun, NULL, 0, NULL);
      		HANDLE handle3 = (HANDLE)_beginthreadex(NULL, 0, ThreadFun, NULL, 0, NULL);
      
      		//永久等待线程运行结束
      		WaitForSingleObject(handle1, INFINITE);
      		WaitForSingleObject(handle2, INFINITE);
      		WaitForSingleObject(handle3, INFINITE);
      
      		// 刷新缓冲区
      		my_logger->flush();
      
      		system("pause");
      	}
      	catch (const spdlog::spdlog_ex& ex)
      	{
      		std::cout << "Log initialization failed: " << ex.what() << std::endl;
      	}
      }
    
  • 打印结果
    在这里插入图片描述

按日志大小回滚

  • 可通过以下这个初始化函数实现日志以大小进行回滚。
  •   // 包含此头文件
      #include <spdlog/sinks/rotating_file_sink.h>
      // 参数3:日志大小(字节)
      // 参数4:回滚数
      std::shared_ptr<spdlog::logger> file_logger = spdlog::rotating_logger_mt("spdlog", "spdlog.log", 1024, 5);
    
  • 打印结果
  • 在这里插入图片描述

按日期回滚

  • 可通过以下两个初始化函数分别实现按天和按小时进行日志回滚。
  •   // 包含头文件
      #include <spdlog/sinks/daily_file_sink.h>
      #include <spdlog/sinks/hourly_file_sink.h>
      
      // 按天回滚
      std::shared_ptr<spdlog::logger> dailylogger = spdlog::daily_logger_mt("daily", "daily.log");
      // 按小时回滚
      std::shared_ptr<spdlog::logger> my_logger = spdlog::hourly_logger_mt("hourly", "hourly.log"); 
    
  • 打印结果
  • 在这里插入图片描述

参考

  • 23
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
spdlog是一个快速、异步的C++日志,支持多线程和跨平台,具有简单易用的接口和高性能日志记录能力。以下是spdlog的一些主要特点: 1. 快速:spdlog使用高效的缓冲区实现快速的日志记录,可以轻松处理高负载的日志记录场景。 2. 异步:spdlog支持异步日志记录,可以将日志写入缓冲区后立即返回,不会阻塞主线程。 3. 多线程:spdlog可以安全地在多个线程中使用,支持多个线程同时进行日志记录,且不需要额外的同步机制。 4. 跨平台:spdlog可以在多个平台上运行,包括Windows、Linux、OS X等。 5. 简单易用:spdlog提供简洁明了的API,可以轻松地实现日志记录功能。 以下是spdlog的使用示例: ```cpp #include "spdlog/spdlog.h" void log_example() { // 创建一个控制台日志记录器 auto console = spdlog::stdout_color_mt("console"); // 创建一个文件日志记录器 auto file = spdlog::basic_logger_mt("file_logger", "logs/mylogfile.txt"); // 设置日志记录级别 console->set_level(spdlog::level::info); file->set_level(spdlog::level::trace); // 记录日志 console->info("Hello, spdlog!"); file->trace("This is a trace message."); } ``` 以上代码演示了如何创建一个控制台日志记录器和一个文件日志记录器,并设置不同的日志记录级别,最后分别记录了一条信息和一条跟踪信息。 更多关于spdlog的使用说明,请参考spdlog的官方文档。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值