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

Qt 软件调试(一) Log日志调试

终于这段时间闲下来了,可以系统的编写Qt软件调试的整个系列。前面零零星星的也有部分输出,但终究没有形成体系。借此机会,做一下系统的总结。慎独、精进~

日志是有效帮助我们快速定位,找到程序异常点的实用方法。但是好的日志才能提高问题排查的效率。在代码江湖里闯荡的这些年头了,见独篇写入、日积月累下体态无限臃肿的单日志文件;见过中英文混杂,查个日志还容易语言系统紊乱;见过没有时间节点,更没有文件名、API名的,更别提行号的,如果能反向从代码中找到输出字符的蛛丝马迹,就要谢天谢地的;当然也见过规整清爽、分类清晰的日志系统。日志系统的搭建不是本系列的重点,如果大家有兴趣,我们后面可以开一个系列专门聊聊和深入研究探讨下。

一、Qt下日志模块

基于日志系统的调试,首先必须要有日志才行。开源的日志项目,如glog、log4cpp等,这里不做过多分享。我们先简单说说Qt下的日志。下面先给个自定义Log的例子:

#ifndef CLOG_H
#define CLOG_H#include <QString>
#include <QDate>
#include <QFile>
#include <QThread>
#include <QQueue>
#include <QMutex>
#include <QMutexLocker>
#include <QObject>
#include <QMetaEnum>
#include <QMetaType>
#include <QFlag>class CLog : public QThread
{Q_OBJECT
public:enum LogType{DEBUG,WARNING,Critical,Info,Fatal};Q_ENUM(LogType)Q_DECLARE_FLAGS(LogTypes, LogType)Q_FLAG(LogTypes)public:static CLog* instance();~CLog();bool init(const QString& strLogPath,const QString& logName = "");void uninit();bool add(const QString &strMsg, LogType eLogType);protected:void run() override;void createNewLogFile();
private:QDate                       m_dateCurFile;QString						m_strLogPath;QString						m_strLogName;QFile						m_fileLog;QMutex						m_lock;QQueue<QString>				m_queData;volatile bool				m_bThreadRun;static CLog* instance_;
};using LogType = typename CLog::LogType;
#define _ins_clog_  CLog::instance()#endif
#include "CLog.h"
#include <QDir>
#include <QCoreApplication>
#include <iostream>
#include <memory>CLog* CLog::instance_ = nullptr;CLog *CLog::instance()
{static std::once_flag s_flag;std::call_once(s_flag, [&]() { instance_ = new CLog;});return instance_;
}CLog::~CLog()
{uninit();
}bool CLog::init(const QString &strLogPath, const QString& logName)
{m_strLogPath = strLogPath;if (strLogPath.isEmpty()) {QString strAppDirPath = QCoreApplication::applicationDirPath();m_strLogPath = QString("%1/log").arg(strAppDirPath);}m_strLogName = logName;if (m_strLogName.isEmpty()) {m_strLogName = QCoreApplication::applicationName();}QDir dir(m_strLogPath);if (!dir.exists()) {if(!dir.mkpath(m_strLogPath)) {return false;}}m_dateCurFile = QDate::currentDate();QString strFolder = QString("%1\\%2").arg(m_strLogPath).arg(m_dateCurFile.toString("yyyy-MM-dd"));if (!dir.exists(strFolder)) {if (!dir.mkpath(strFolder)) {return false;}}QString fileName = QString("%1\\%2\\%3_%4_%5.txt").arg(m_strLogPath).arg(m_dateCurFile.toString("yyyy-MM-dd")).arg(m_dateCurFile.toString("yyyy-MM-dd")).arg(QTime::currentTime().toString("HH")).arg(m_strLogName);m_fileLog.setFileName(fileName);if (!m_fileLog.open(QIODevice::Append | QIODevice::Text | QIODevice::WriteOnly)){return false;}m_bThreadRun = true;start();return true;
}void CLog::uninit()
{QMutexLocker locker(&m_lock);m_bThreadRun = false;m_queData.enqueue("");
}bool CLog::add(const QString& strMsg, LogType eLogType)
{QMetaEnum m = QMetaEnum::fromType<LogTypes>();QString strLogInfo = QString("%1 %2 $%3:%4\n").arg(QDate::currentDate().toString("yyyy-MM-dd")).arg(QTime::currentTime().toString("HH:mm:ss.zzz")).arg(m.valueToKey(eLogType)).arg(strMsg);QMutexLocker locker(&m_lock);m_queData.enqueue(strLogInfo);return true;
}void CLog::createNewLogFile()
{QDate curDate = QDate::currentDate();if (curDate > m_dateCurFile){m_dateCurFile = curDate;QDir dir;QString strFolder = QString("%1\\%2").arg(m_strLogPath).arg(m_dateCurFile.toString("yyyy-MM-dd"));if (!dir.exists(strFolder)) {if (!dir.mkpath(strFolder)) {return;}}QString fileName = QString("%1\\%2\\%3_%4_%5.txt").arg(m_strLogPath).arg(m_dateCurFile.toString("yyyy-MM-dd")).arg(m_dateCurFile.toString("yyyy-MM-dd")).arg(QTime::currentTime().toString("HH")).arg(m_strLogName);if (m_fileLog.isOpen()) {m_fileLog.flush();m_fileLog.close();}m_fileLog.setFileName(fileName);m_fileLog.open(QIODevice::Append | QIODevice::Text | QIODevice::WriteOnly);}
}void CLog::run()
{QString strData;while (m_bThreadRun) {strData.clear();if (m_queData.isEmpty()) {msleep(200);continue;}QMutexLocker locker(&m_lock);strData = m_queData.dequeue();createNewLogFile();if (!m_fileLog.isOpen()){continue;}m_fileLog.write(strData.toUtf8());m_fileLog.flush();}
}
#include "mainwindow.h"
#include "iapplication.h"
#include "CLog.h"
#include <QDateTime>
#include <QTime>void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{LogType msgType;qint32 level = -1;switch (type){case QtDebugMsg:msgType = LogType::DEBUG;level = 1;break;case QtWarningMsg:msgType = LogType::WARNING;level = 2;break;case QtCriticalMsg:msgType = LogType::Critical;level = 3;break;case QtFatalMsg:msgType = LogType::Fatal;level = 4;break;case QtInfoMsg:msgType = LogType::Info;level = 1;break;default:break;}QString addMsg = msg;_ins_clog_->add(addMsg, msgType);
}void testMessageOutput()
{qint64 bt = QDateTime::currentMSecsSinceEpoch();for(int i =0; i < 10000;++i){_ins_clog_->add(QString("the %1 times output message.").arg(i),CLog::Info);}qint64 et = QDateTime::currentMSecsSinceEpoch();qDebug() << et -bt;
}int main(int argc, char *argv[])
{QApplication a(argc, argv);/// 设置日志qInstallMessageHandler(outputMessage); QString path;_ins_clog_->init(path);testMessageOutput();return a.exec();
}

二、只有打印信息,没有日志输出如何排查

经典神器 Dbgview上场。
在这里插入图片描述
使用比较简单,这里不做概述。

三、关于日志或打印信息排查问题的一些总结和思考

1、日志通常只能作为业务逻辑的辅助排查。当程序由于逻辑上执行异常时,我们可以通过判断打印信息去推断可能产生问题的原因。
2、通过日志排查问题对相关人员有比较高的要求,对于业务逻辑需要比较熟悉才能快速定位
3、软件开发人员在编写打印输出的日志信息时,需要统一输出格式,对问题点输出可靠、可读性强的提示;否则输出过多无关紧要的信息,反而不利于问题的排查和分析。

相关文章:

Qt 软件调试(一) Log日志调试

终于这段时间闲下来了&#xff0c;可以系统的编写Qt软件调试的整个系列。前面零零星星的也有部分输出&#xff0c;但终究没有形成体系。借此机会&#xff0c;做一下系统的总结。慎独、精进~ 日志是有效帮助我们快速定位&#xff0c;找到程序异常点的实用方法。但是好的日志才能…...

docker network容器网络通信

Docker 网络主要有以下两个作用&#xff1a; 容器间的互联和通信以及端口映射容器IP变动时候可以通过服务名直接网络通信而不受到影响 只要是处于同一个Docker 网络下的容器就可以使用服务名直接访问&#xff0c;而无需担心重启。 docker容器网络模式 bridge网络模式&#…...

CVE-2022-4886 ingress命令注入复现与分析

安装 安装ingress-nginx wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.4/deploy/static/provider/cloud/deploy.yamlk apply -f deploy.yaml 原理 nginx.ingress.kubernetes.io/rewrite-target标签会在nginx配置进行插入字符串&#…...

Oracle整体架构

4. Oracle整体架构 所谓整体架构,这里是指保证Oracle数据库系统正常工作和运行所必须的组件及其实现。从大的方面讲,这主要包括实例和数据库。在此基础上细分,实例由相关内存区域和服务进程组成,数据库包括各种相关文件,而这些相关内存区域、服务进程及相关文件又可再进一…...

webpack具体实现--未完

1、前端模块打包工具webpack webpack 是 Webpack 的核心模块&#xff0c;webpack-cli 是 Webpack 的 CLI 程序&#xff0c;用来在命令行中调用 Webpack。webpack-cli 所提供的 CLI 程序就会出现在 node_modules/.bin 目录当中&#xff0c;我们可以通过 npx 快速找到 CLI 并运行…...

【Git】修改提交信息(单次、批量)

文章目录 修改最近一次 commit 的提交信息修改某次 commit 的提交信息方法总结 修改最近一次 commit 的提交信息 git commit --amend -m "new message"修改某次 commit 的提交信息 git log --oneline 运行结果如下2f80f1b commit 4 9ee990a 第三次提交 40f2f03 comm…...

Grafana Panel组件跳转、交互实现

程序员的公众号&#xff1a;源1024&#xff0c;获取更多资料&#xff0c;无加密无套路&#xff01; 最近整理了一份大厂面试资料《史上最全大厂面试题》&#xff0c;Springboot、微服务、算法、数据结构、Zookeeper、Mybatis、Dubbo、linux、Kafka、Elasticsearch、数据库等等 …...

人工智能|机器学习——感知器算法原理与python实现

感知器算法是一种可以直接得到线性判别函数的线性分类方法&#xff0c;它是基于样本线性可分的要求下使用的。 一、线性可分与线性不可分 为了方便讨论&#xff0c;我们蒋样本增加了以为常数&#xff0c;得到增广样向量 y&#xff08;1;;;...;&#xff09;,则n个样本的集合为&a…...

【论文阅读笔记】Prompt-to-Prompt Image Editing with Cross-Attention Control

【论文阅读笔记】Prompt-to-Prompt Image Editing with Cross-Attention Control 个人理解思考基本信息摘要背景挑战方法结果 引言方法论结果讨论引用 个人理解 通过将caption的注意力图注入到目标caption注意力中影响去噪过程以一种直观和便于理解的形式通过修改交叉注意力的…...

Echarts legend图例配置项 设置位置 显示隐藏

Echarts 官网完整配置项 https://echarts.apache.org/zh/option.html#legend 配置项 legend: { }设置图例为圆形 icon: circle,//设置图例为圆形设置图例位置 top: 20%//距离顶部百分之20//y:bottom 在底部显示设置图例 宽度 高度 itemWidth: 10,//设置图例宽度 itemHeight: …...

C#每天复习一个重要小知识day3:随机数的生成

目录 格式&#xff1a; 生成随机数&#xff1a; 生成一个0-100的随机数&#xff1a; 以下是更详细的代码示例&#xff1a; 在C#中&#xff0c;可以使用Random类来生成随机数。这个类提供了多种方法来生成不同类型的随机数。 格式&#xff1a; Random 随机变量名(r) new …...

Java后端使用XWPFDocument生成word文档,踩坑

以下都是借鉴网上内容: 环境 纯后端, java, spring项目 maven管理. maven内容: <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.16</version></dependency><dependency>…...

asp.net core HttpContextAccessor类

在 ASP.NET Core 中 &#xff0c;HttpContextAccessor 是一个用于访问当前 HTTP 请求的工具类。它通常用于在应用程序中获取当前 HTTP 请求的上下文信息&#xff0c;例如请求的路由、头部信息、用户身份验证状态等。 HttpContextAccessor 类通常在需要访问当前 HTTP 请求上下文…...

微服务--04--SpringCloudGateway 网关

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.网关路由1.1 认识网关在SpringCloud当中&#xff0c;提供了两种网关实现方案&#xff1a; 1.2.快速入门1.3.路由过滤 2.网关登录校验2.1.鉴权思路分析2.2.网关过滤…...

Java程序连接 nacos集群

我们在bootstrap.yml文件里可以直接连一个nacos集群的. 架构如下 没错,我们程序直连的是通过Nginx的,利用nginx的反向代理来做到连接nacos集群. 我们先把nginx的配置贴上来 upstream cluster{server 127.0.0.1:8848;server 127.0.0.1:8849;server 127.0.0.1:8850; }server{l…...

【深度学习】参数优化和训练技巧

寻找合适的学习率(learning rate) 学习率是一个非常非常重要的超参数&#xff0c;这个参数呢&#xff0c;面对不同规模、不同batch-size、不同优化方式、不同数据集&#xff0c;其最合适的值都是不确定的&#xff0c;我们无法光凭经验来准确地确定lr的值&#xff0c;我们唯一可…...

CeresPCL 曲线拟合之三次多项式

文章目录 一、简介2.1 实现步骤二、实现代码三、实现效果参考资料一、简介 2.1 实现步骤 (1)构建代价函数。假设我们得到了一组数据,也知晓该数据是用曲线方程: y = a x 3 + b x 2 + c x +...

小白备战蓝桥杯:Java基础语法

一、注释 IDEA注释快捷键&#xff1a;Ctrl / 单行注释&#xff1a; //注释信息 多行注释&#xff1a; /* 注释信息 */ 二、字面量 常用数据&#xff1a;整数、小数、字符串&#xff08;双引号&#xff09;、字符&#xff08;单引号&#xff09;、布尔值&#xff08;tr…...

C#面向对象

过程类似函数只能执行没有返回值 函数不仅能执行&#xff0c;还可以返回结果 1、面向过程 a 把完成某一需求的所有步骤 从头到尾 逐步实现 b 根据开发需求&#xff0c;将某些 功能独立 的代码 封装 成一个又一个 函数 c 最后完成的代码就是顺序的调用不同的函数 特点 1、…...

智能优化算法应用:基于蝙蝠算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于蝙蝠算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于蝙蝠算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蝙蝠算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议&#xff0c;专门用于在数字音频设备之间传输数字音频数据。它由飞利浦&#xff08;Philips&#xff09;公司开发&#xff0c;以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

uniapp手机号一键登录保姆级教程(包含前端和后端)

目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号&#xff08;第三种&#xff09;后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing

Muffin 论文 现有方法 CRADLE 和 LEMON&#xff0c;依赖模型推理阶段输出进行差分测试&#xff0c;但在训练阶段是不可行的&#xff0c;因为训练阶段直到最后才有固定输出&#xff0c;中间过程是不断变化的。API 库覆盖低&#xff0c;因为各个 API 都是在各种具体场景下使用。…...

MySQL 主从同步异常处理

阅读原文&#xff1a;https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主&#xff0c;遇到的这个错误&#xff1a; Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一&#xff0c;通常表示&#xff…...