在 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)
方法二:手动下载并添加到项目中
- 前往 spdlog 的 GitHub 仓库。
- 下载最新的 release 版本(ZIP 文件)。
- 将
spdlog/include文件夹复制到你的项目目录中(例如,放在external/spdlog)。 - 在你的
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. 准备工作:安装 spdlog 方法一:使用 CMake 的 FetchContent(推荐) 方法二:手动下载并添加到项目中 2. 在 Qt 项目中集成 spdlog a. 初始化 spdlog b. 在 Qt 的各个部分使用 spdlog 3. 基本使用示例 4. …...
vue的el-button防止重复点击
这样效果仅生效在按钮上...
消息中间件 Kafka 快速入门与实战
1、概述 最近感觉上班实在是太无聊,打算给大家分享一下Kafka的使用,本篇文章首先给大家分享三种方式搭建Kafka环境,接着给大家介绍kafka核心的基础概念以及Java API的使用,最后分享一个SpringBoot的集成案例,希望对大…...
【Unity服务】如何使用Unity Version Control
Unity上的线上服务有很多,我们接触到的第一个一般就是Version Control,用于对项目资源的版本管理。 本文介绍如何为项目添加Version Control,并如何使用,以及如何将项目与Version Control断开链接。 其实如果仅仅是对项目资源进…...
C++ --- 静态多态和动态多态
静态多态和动态多态 静态多态动态多态总结 静态多态和动态多态是面向对象编程中多态性的两种主要形式,它们在实现方式、绑定时机以及应用场景上存在一些显著的区别。 静态多态 静态多态,也被称为编译时多态,是指在编译阶段就已经确定了对象调…...
华为vxlan
VXLAN是什么?VXLAN与VLAN之间有何不同? - 华为...
队列及笔试题
队列 先进先出 使用单链表进行队尾插入 队头删除 其中带头结点直接尾插,不带头结点第一次操作要判断一下 但是带头结点需要malloc和free 函数传需要修改的参数方法 1、二级指针 2、带哨兵位的头结点 3、返回值 4、如果有多个值,用结构体封装起来…...
JAVA TCP协议初体验
文章目录 一、需求概述二、设计选择三、代码结构四、代码放送五、本地调试1. 服务端日志2. 客户端日志3. 断线重连日志 六、服务器部署运行1. 源码下载2. 打包镜像3. 运行容器 一、需求概述 最近开发某数据采集系统,系统整体的数据流程图如下: #mermaid…...
sqlserver迁移数据库文件存储位置
业务背景:由于C盘爆满,需要将数据库文件迁移到别处比如D盘 下面以某一个数据库转移为示例:(可以用SSMS工具,新建查询配合使用) 1.查询数据库文件存储路径 sql语句: -- 查询路径 USE QiangTes…...
配置项取值给静态类用
在 Java 中,如果要从 application.yml 文件中取值并供静态类使用,可以考虑以下几种方法: 一、使用 Spring 的 Environment 类 1. 首先确保你的项目是一个 Spring 项目,并且配置文件被正确加载。 2. 在需要获取配置值的类中注入…...
【vs code(cursor) ssh连不上服务器】但是 Terminal 可以连上,问题解决 ✅
问题描述 通过 vs code 的 ssh 原本方式无法连接,但是通过 Terminal 使用相同的 bash 却可以连接上服务器。 ssh -p 4xx username14.xxx.3 问题解决方法 在 vs code 的 config 里,将该服务器(14.xxx.3)的相关配置全部清空或注释…...
Go基础学习06-Golang标准库container/list(双向链表)深入讲解;延迟初始化技术;Element;List;Ring
基础介绍 单向链表中的每个节点包含数据和指向下一个节点的指针。其特点是每个节点只知道下一个节点的位置,使得数据只能单向遍历。 示意图如下: 双向链表中的每个节点都包含指向前一个节点和后一个节点的指针。这使得在双向链表中可以从前向后或从后…...
多层时间轮原理以及使用
文章目录 背景常用定时器实现 任务队列时间轮介绍基本结构指针移动定时任务插入循环任务插入代码示例 多层时间轮使用流程 代码 背景 在软件开发中,定时器是一个极为常用的组件,它发挥着至关重要的作用。通过定时器,开发者能够精确地控制程序…...
鸿蒙HarmonyOS开发生态
1、官网 华为开发者联盟-HarmonyOS开发者官网,共建鸿蒙生态 2、开发工具IDE下载及使用 https://developer.huawei.com/consumer/cn/ 3、使用帮助文档 4、发布到华为应用商店 文档中心...
vue中使用jsencrypt加密
vue中封装并使用jsencrypt加密 一般在项目搭建过程中用户注册、登录、修改密码、重置密码等功能都需要用到密码加密的功能,所以把jsencrypt进行封装使用,使代码更加简洁,流程如下: 1、安装jsencrypt npm install jsencrypt2、在…...
SpirngBoot核心思想之一AOP
简介: AOP(Aspect-Oriented Programming,面向切面编程) 是一种用于解决软件系统中横切关注点的编程范式。在企业级开发中,很多非业务功能(如日志、事务、权限、安全等)需要在多个模块中执行&am…...
足球预测推荐软件:百万数据阐述百年足球历史-大数据模型量化球员成就值
我开始创建这个模型是从梅西22世界杯夺冠第二天开始准备的,当时互联网上充斥了太多了个人情感的输出,有的人借题对C罗冷嘲热讽,有的人质疑梅西的阿根廷被安排夺冠不配超越马拉多纳做GOAT。作为一个从2002年开始看球的球迷,说实话有…...
AD中如何批量修改丝印的大小,节省layout时间
先选中一个元器件的丝印,然后右键,选择“查找相似项” 直接点击OK,这时会发现所有的丝印都会被选中 然后点击右上角的按键,修改其属性。...
Ps:堆栈
将多张类似的图像图层堆叠在一起形成图像堆栈 Stack,通过应用不同的堆栈模式,可以从这些图像中提取有用的信息或达到特定的视觉效果。 Photoshop 中的堆栈技术被广泛应用于摄影后期处理、科学研究、环境监测与分析等领域。 例如,它常用于减少…...
獨立IP和共用IP有什麼區別?
什麼是獨立IP? 獨立IP指的是一個IP地址專屬於一個用戶或設備。無論是網站、伺服器還是其他線上服務,獨立IP都意味著該IP地址不會與其他用戶或設備共用。獨立IP通常用於需要高安全性和穩定性的場景,比如企業網站、電子商務平臺和需要SSL證書的…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
