当前位置: 首页 > news >正文

在 Qt 项目中使用 spdlog 的全攻略

目录

1. 准备工作:安装 spdlog

方法一:使用 CMake 的 FetchContent(推荐)

方法二:手动下载并添加到项目中

2. 在 Qt 项目中集成 spdlog

a. 初始化 spdlog

b. 在 Qt 的各个部分使用 spdlog

3. 基本使用示例

4. 高级配置:多种输出目标和格式化

a. 多种 Sink

b. 自定义格式化

5. 异步日志记录

6. 在 Qt 中处理线程安全

7. 常见问题与解决方案

问题1:日志文件没有生成或写入

问题2:日志级别不正确

问题3:异步日志丢失日志消息


1. 准备工作:安装 spdlog

首先,我们需要将 spdlog 添加到你的 Qt 项目中。spdlog 是一个头文件库,你可以通过以下几种方式来获取它:

方法一:使用 CMake 的 FetchContent(推荐)

如果你的 Qt 项目使用 CMake 构建,这是最简单的方法。

# 在你的 CMakeLists.txt 文件中添加以下内容cmake_minimum_required(VERSION 3.14)
project(MyQtApp)set(CMAKE_CXX_STANDARD 17)# 引入 Qt
find_package(Qt5 COMPONENTS Widgets REQUIRED)# 使用 FetchContent 下载 spdlog
include(FetchContent)
FetchContent_Declare(spdlogGIT_REPOSITORY https://github.com/gabime/spdlog.gitGIT_TAG        v1.11.0 # 选择一个稳定的版本
)
FetchContent_MakeAvailable(spdlog)# 添加可执行文件
add_executable(MyQtApp main.cpp mainwindow.cpp mainwindow.h mainwindow.ui)# 链接 Qt 和 spdlog
target_link_libraries(MyQtApp PRIVATE Qt5::Widgets spdlog::spdlog)
方法二:手动下载并添加到项目中
  1. 前往 spdlog 的 GitHub 仓库。
  2. 下载最新的 release 版本(ZIP 文件)。
  3. spdlog/include 文件夹复制到你的项目目录中(例如,放在 external/spdlog)。
  4. 在你的 CMakeLists.txt 中添加如下内容:
# 添加 spdlog 的包含路径
include_directories(${CMAKE_SOURCE_DIR}/external/spdlog/include)# 假设你不需要构建 spdlog 库,而是作为头文件库使用
add_executable(MyQtApp main.cpp mainwindow.cpp mainwindow.h mainwindow.ui)# 链接 Qt
target_link_libraries(MyQtApp PRIVATE Qt5::Widgets)

2. 在 Qt 项目中集成 spdlog

假设你已经将 spdlog 添加到项目中,接下来我们来配置和使用它。

a. 初始化 spdlog

在你的 Qt 项目的入口处( main.cpp),初始化 spdlog

// main.cpp
#include <QApplication>
#include "mainwindow.h"
#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;w.show();// 初始化 spdlogtry {// 创建一个同时输出到控制台和文件的 loggerauto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/myapp.log", true);std::vector<spdlog::sink_ptr> sinks {console_sink, file_sink};auto logger = std::make_shared<spdlog::logger>("multi_sink", sinks.begin(), sinks.end());// 设置全局日志器spdlog::set_default_logger(logger);spdlog::set_level(spdlog::level::info); // 设置日志级别spdlog::flush_on(spdlog::level::info);  // 设置自动刷新级别}catch (const spdlog::spdlog_ex &ex) {fprintf(stderr, "日志初始化失败: %s\n", ex.what());return 1;}return a.exec();
}
b. 在 Qt 的各个部分使用 spdlog

在你的 MainWindow 或其他类中使用 spdlog 来记录日志:

// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <spdlog/spdlog.h>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);spdlog::info("应用程序已启动");
}MainWindow::~MainWindow()
{spdlog::info("应用程序正在关闭");delete ui;
}void MainWindow::on_someButton_clicked()
{spdlog::info("按钮被点击了!");// 你的其他代码
}void MainWindow::on_errorCondition()
{spdlog::error("发生了一个错误!");// 错误处理代码
}

3. 基本使用示例

让我们来看一个简单的示例,展示如何在 Qt 应用中记录不同级别的日志。

// 在你的某个函数中
void MainWindow::performTask()
{spdlog::debug("任务开始");spdlog::info("任务进行中");if (/* 某个条件 */) {spdlog::warn("遇到警告条件");}try {// 可能会抛出异常的代码}catch (const std::exception &e) {spdlog::error("异常捕获: {}", e.what());}spdlog::critical("任务完成,但有严重问题!");
}

4. 高级配置:多种输出目标和格式化

a. 多种 Sink

spdlog 允许你将日志输出到多个目标(sinks),比如文件、控制台、甚至网络。

// 仅输出到控制台
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();// 仅输出到文件
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/myapp.log", true);// 创建包含多个 sinks 的 logger
std::vector<spdlog::sink_ptr> sinks {console_sink, file_sink};
auto logger = std::make_shared<spdlog::logger>("multi_sink", sinks.begin(), sinks.end());// 设置为默认 logger
spdlog::set_default_logger(logger);
b. 自定义格式化

你可以定义日志的输出格式,使其更符合你的需求。

// 设置日志格式
// 例如: [2024-04-27 12:34:56.789] [info] [main.cpp:42] 这是一个信息日志
spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [%s:%#] %v");

常用的格式化标识:

  • %Y-%m-%d %H:%M:%S:日期和时间
  • %l:日志级别(info, error, etc.)
  • %s:源文件名
  • %#:源代码行号
  • %v:日志消息

5. 异步日志记录

对于需要高性能的应用,异步日志记录是个不错的选择。spdlog 提供了简便的异步日志支持。

#include <spdlog/async.h> // 需要包含这个头文件
#include <spdlog/sinks/basic_file_sink.h>int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;w.show();try {// 初始化线程池,队列大小为8192,线程数为1spdlog::init_thread_pool(8192, 1);// 创建一个异步文件日志器auto async_file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/async_log.txt", true);auto async_logger = std::make_shared<spdlog::async_logger>("async_logger", async_file_sink, spdlog::thread_pool(), spdlog::async_overflow_policy::block);// 将异步 logger 添加到默认 loggerspdlog::register_logger(async_logger);spdlog::set_default_logger(async_logger);spdlog::set_level(spdlog::level::info);spdlog::flush_on(spdlog::level::info);}catch (const spdlog::spdlog_ex &ex) {fprintf(stderr, "日志初始化失败: %s\n", ex.what());return 1;}return a.exec();
}

6. 在 Qt 中处理线程安全

Qt 应用通常涉及多线程操作,spdlog 是线程安全的,这意味着你可以在多个线程中安全地记录日志而无需担心竞争条件。

// 在主线程中
void MainWindow::startBackgroundTask()
{std::thread([=]() {spdlog::info("后台任务开始");// 执行一些耗时操作spdlog::info("后台任务完成");}).detach();
}

7. 常见问题与解决方案

问题1:日志文件没有生成或写入

解决方案

  • 确保指定的日志目录存在。例如,如果你指定 logs/myapp.log,确保 logs 目录已创建。
  • 检查文件路径是否正确,尤其是在不同操作系统上的路径格式。
问题2:日志级别不正确

解决方案

  • 确保设置了正确的日志级别。例如,默认级别可能是 info,如果你使用 debug 级别的日志,可能不会输出。通过 spdlog::set_level(spdlog::level::debug); 来调整。
问题3:异步日志丢失日志消息

解决方案

  • 在应用程序退出前,调用 spdlog::shutdown(); 确保所有日志消息被写入。

    int main(int argc, char *argv[])
    {// 初始化代码...int result = a.exec();spdlog::shutdown(); // 确保所有日志被写入return result;
    }
    

参考:

日志的艺术:深入理解 spdlog-CSDN博客

相关文章:

在 Qt 项目中使用 spdlog 的全攻略

目录 1. 准备工作&#xff1a;安装 spdlog 方法一&#xff1a;使用 CMake 的 FetchContent&#xff08;推荐&#xff09; 方法二&#xff1a;手动下载并添加到项目中 2. 在 Qt 项目中集成 spdlog a. 初始化 spdlog b. 在 Qt 的各个部分使用 spdlog 3. 基本使用示例 4. …...

vue的el-button防止重复点击

这样效果仅生效在按钮上...

消息中间件 Kafka 快速入门与实战

1、概述 最近感觉上班实在是太无聊&#xff0c;打算给大家分享一下Kafka的使用&#xff0c;本篇文章首先给大家分享三种方式搭建Kafka环境&#xff0c;接着给大家介绍kafka核心的基础概念以及Java API的使用&#xff0c;最后分享一个SpringBoot的集成案例&#xff0c;希望对大…...

【Unity服务】如何使用Unity Version Control

Unity上的线上服务有很多&#xff0c;我们接触到的第一个一般就是Version Control&#xff0c;用于对项目资源的版本管理。 本文介绍如何为项目添加Version Control&#xff0c;并如何使用&#xff0c;以及如何将项目与Version Control断开链接。 其实如果仅仅是对项目资源进…...

C++ --- 静态多态和动态多态

静态多态和动态多态 静态多态动态多态总结 静态多态和动态多态是面向对象编程中多态性的两种主要形式&#xff0c;它们在实现方式、绑定时机以及应用场景上存在一些显著的区别。 静态多态 静态多态&#xff0c;也被称为编译时多态&#xff0c;是指在编译阶段就已经确定了对象调…...

华为vxlan

VXLAN是什么&#xff1f;VXLAN与VLAN之间有何不同&#xff1f; - 华为...

队列及笔试题

队列 先进先出 使用单链表进行队尾插入 队头删除 其中带头结点直接尾插&#xff0c;不带头结点第一次操作要判断一下 但是带头结点需要malloc和free 函数传需要修改的参数方法 1、二级指针 2、带哨兵位的头结点 3、返回值 4、如果有多个值&#xff0c;用结构体封装起来…...

JAVA TCP协议初体验

文章目录 一、需求概述二、设计选择三、代码结构四、代码放送五、本地调试1. 服务端日志2. 客户端日志3. 断线重连日志 六、服务器部署运行1. 源码下载2. 打包镜像3. 运行容器 一、需求概述 最近开发某数据采集系统&#xff0c;系统整体的数据流程图如下&#xff1a; #mermaid…...

sqlserver迁移数据库文件存储位置

业务背景&#xff1a;由于C盘爆满&#xff0c;需要将数据库文件迁移到别处比如D盘 下面以某一个数据库转移为示例&#xff1a;&#xff08;可以用SSMS工具&#xff0c;新建查询配合使用&#xff09; 1.查询数据库文件存储路径 sql语句&#xff1a; -- 查询路径 USE QiangTes…...

配置项取值给静态类用

在 Java 中&#xff0c;如果要从 application.yml 文件中取值并供静态类使用&#xff0c;可以考虑以下几种方法&#xff1a; 一、使用 Spring 的 Environment 类 1. 首先确保你的项目是一个 Spring 项目&#xff0c;并且配置文件被正确加载。 2. 在需要获取配置值的类中注入…...

【vs code(cursor) ssh连不上服务器】但是 Terminal 可以连上,问题解决 ✅

问题描述 通过 vs code 的 ssh 原本方式无法连接&#xff0c;但是通过 Terminal 使用相同的 bash 却可以连接上服务器。 ssh -p 4xx username14.xxx.3 问题解决方法 在 vs code 的 config 里&#xff0c;将该服务器&#xff08;14.xxx.3&#xff09;的相关配置全部清空或注释…...

Go基础学习06-Golang标准库container/list(双向链表)深入讲解;延迟初始化技术;Element;List;Ring

基础介绍 单向链表中的每个节点包含数据和指向下一个节点的指针。其特点是每个节点只知道下一个节点的位置&#xff0c;使得数据只能单向遍历。 示意图如下&#xff1a; 双向链表中的每个节点都包含指向前一个节点和后一个节点的指针。这使得在双向链表中可以从前向后或从后…...

多层时间轮原理以及使用

文章目录 背景常用定时器实现 任务队列时间轮介绍基本结构指针移动定时任务插入循环任务插入代码示例 多层时间轮使用流程 代码 背景 在软件开发中&#xff0c;定时器是一个极为常用的组件&#xff0c;它发挥着至关重要的作用。通过定时器&#xff0c;开发者能够精确地控制程序…...

鸿蒙HarmonyOS开发生态

1、官网 华为开发者联盟-HarmonyOS开发者官网&#xff0c;共建鸿蒙生态 2、开发工具IDE下载及使用 https://developer.huawei.com/consumer/cn/ 3、使用帮助文档 4、发布到华为应用商店 文档中心...

vue中使用jsencrypt加密

vue中封装并使用jsencrypt加密 一般在项目搭建过程中用户注册、登录、修改密码、重置密码等功能都需要用到密码加密的功能&#xff0c;所以把jsencrypt进行封装使用&#xff0c;使代码更加简洁&#xff0c;流程如下&#xff1a; 1、安装jsencrypt npm install jsencrypt2、在…...

SpirngBoot核心思想之一AOP

简介&#xff1a; AOP&#xff08;Aspect-Oriented Programming&#xff0c;面向切面编程&#xff09; 是一种用于解决软件系统中横切关注点的编程范式。在企业级开发中&#xff0c;很多非业务功能&#xff08;如日志、事务、权限、安全等&#xff09;需要在多个模块中执行&am…...

足球预测推荐软件:百万数据阐述百年足球历史-大数据模型量化球员成就值

我开始创建这个模型是从梅西22世界杯夺冠第二天开始准备的&#xff0c;当时互联网上充斥了太多了个人情感的输出&#xff0c;有的人借题对C罗冷嘲热讽&#xff0c;有的人质疑梅西的阿根廷被安排夺冠不配超越马拉多纳做GOAT。作为一个从2002年开始看球的球迷&#xff0c;说实话有…...

AD中如何批量修改丝印的大小,节省layout时间

先选中一个元器件的丝印&#xff0c;然后右键&#xff0c;选择“查找相似项” 直接点击OK&#xff0c;这时会发现所有的丝印都会被选中 然后点击右上角的按键&#xff0c;修改其属性。...

Ps:堆栈

将多张类似的图像图层堆叠在一起形成图像堆栈 Stack&#xff0c;通过应用不同的堆栈模式&#xff0c;可以从这些图像中提取有用的信息或达到特定的视觉效果。 Photoshop 中的堆栈技术被广泛应用于摄影后期处理、科学研究、环境监测与分析等领域。 例如&#xff0c;它常用于减少…...

獨立IP和共用IP有什麼區別?

什麼是獨立IP&#xff1f; 獨立IP指的是一個IP地址專屬於一個用戶或設備。無論是網站、伺服器還是其他線上服務&#xff0c;獨立IP都意味著該IP地址不會與其他用戶或設備共用。獨立IP通常用於需要高安全性和穩定性的場景&#xff0c;比如企業網站、電子商務平臺和需要SSL證書的…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

C++ 设计模式 《小明的奶茶加料风波》

&#x1f468;‍&#x1f393; 模式名称&#xff1a;装饰器模式&#xff08;Decorator Pattern&#xff09; &#x1f466; 小明最近上线了校园奶茶配送功能&#xff0c;业务火爆&#xff0c;大家都在加料&#xff1a; 有的同学要加波霸 &#x1f7e4;&#xff0c;有的要加椰果…...

CppCon 2015 学习:Time Programming Fundamentals

Civil Time 公历时间 特点&#xff1a; 共 6 个字段&#xff1a; Year&#xff08;年&#xff09;Month&#xff08;月&#xff09;Day&#xff08;日&#xff09;Hour&#xff08;小时&#xff09;Minute&#xff08;分钟&#xff09;Second&#xff08;秒&#xff09; 表示…...