当前位置: 首页 > 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證書的…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”

2025年#高考 将在近日拉开帷幕&#xff0c;#AI 监考一度冲上热搜。当AI深度融入高考&#xff0c;#时间同步 不再是辅助功能&#xff0c;而是决定AI监考系统成败的“生命线”。 AI亮相2025高考&#xff0c;40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕&#xff0c;江西、…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中&#xff0c;crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用&#xff0c;用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益&#xff0c;允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

Python 高效图像帧提取与视频编码:实战指南

Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...

2.3 物理层设备

在这个视频中&#xff0c;我们要学习工作在物理层的两种网络设备&#xff0c;分别是中继器和集线器。首先来看中继器。在计算机网络中两个节点之间&#xff0c;需要通过物理传输媒体或者说物理传输介质进行连接。像同轴电缆、双绞线就是典型的传输介质&#xff0c;假设A节点要给…...

用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法

用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法 大家好,我是Echo_Wish。最近刷短视频、看直播,有没有发现,越来越多的应用都开始“懂你”了——它们能感知你的情绪,推荐更合适的内容,甚至帮客服识别用户情绪,提升服务体验。这背后,神经网络在悄悄发力,撑起…...

Python的__call__ 方法

在 Python 中&#xff0c;__call__ 是一个特殊的魔术方法&#xff08;magic method&#xff09;&#xff0c;它允许一个类的实例像函数一样被调用。当你在一个对象后面加上 () 并执行时&#xff08;例如 obj()&#xff09;&#xff0c;Python 会自动调用该对象的 __call__ 方法…...