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

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

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

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"); 
    
  • 打印结果
  • 在这里插入图片描述

参考

/****************************************************************************** Module: VC-Logger Purpose: 记录程序日志。 1. 把日志信息输出到指定文件 2. 对于 GUI 程序,可以把日志信息发送到指定窗口 3. 对于Console应用程序,可以把日志信息发往标准输出 (std::cout) Desc: 1、功能: -------------------------------------------------------------------------------------- a) 把日志信息输出到指定文件 b) 每日生成一个日志文件 c) 对于 GUI 程序,可以把日志信息发送到指定窗口 d) 对于Console应用程序,可以把日志信息发往标准输出 (std::cout) e) 支持 MBCS / UNICODE,Console / GUI,win32 / x64 程序 f) 支持动态加载和静态加载日志组件 DLL g) 支持 DEBUG/TRACE/INFO/WARN/ERROR/FATAL 等多个日志级别 2、可用性: -------------------------------------------------------------------------------------- a) 简单纯净:不依赖任何程序库或框架 b) 使用接口简单,不需复杂的配置或设置工作 c) 提供 CStaticLogger 和 CDynamicLogger 包装类用于静态或动态加载以及操作日志组件,用户无需关注加载细节 d) 程序如果要记录多个日志文件只需为每个日志文件创建相应的 CStaticLogger 或 CDynamicLogger 对象 e) 只需调用 Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法记录日志 f) 日志记录方法支持可变参数 g) 日志输出格式: 3、性能: -------------------------------------------------------------------------------------- a) 支持多线程同时发送写日志请求 b) 使用单独线程在后台写日志,不影响工作线程的正常执行 c) 采用批处理方式批量记录日志 Usage: 方法一:(静态加载 Logger DLL) -------------------------------------------------------------------------------------- 0. 应用程序包含 StaticLogger.h 头文件 1. 创建 CStaticLogger 对象(通常为全局对象) 2. 调用 CStaticLogger->Init(...) 初始化日志组件 3. 使用 CStaticLogger->Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法写日志 4. 调用 CStaticLogger->UnInit(...) 清理日志组件(CStaticLogger 对象析构时也会自动清理日志组件) 方法二:(动态加载 Logger DLL) -------------------------------------------------------------------------------------- 0. 应用程序包含 DynamicLogger.h 头文件 1. 创建 CDynamicLogger 对象(通常为全局对象) 2. 调用 CDynamicLogger->Init(...) 初始化日志组件 3. 使用 CDynamicLogger->Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法写日志 4. 调用 CDynamicLogger->UnInit(...) 清理日志组件(CDynamicLogger 对象析构时也会自动清理日志组件) 方法三:(直接用导出函数加载 Logger DLL) -------------------------------------------------------------------------
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大草原的小灰灰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值