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、软件开发人员在编写打印输出的日志信息时,需要统一输出格式,对问题点输出可靠、可读性强的提示;否则输出过多无关紧要的信息,反而不利于问题的排查和分析。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/166955.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

百度 文心一言 sdk 试用

JMaven Central: com.baidu.aip:java-sdk (sonatype.com) Java sdk地址如上&#xff1a; 文心一言开发者 文心一言 (baidu.com) ERNIE Bot SDK https://yiyan.baidu.com/developer/doc#Fllzznonw ERNIE Bot SDK提供便捷易用的接口&#xff0c;可以调用文心一言的能力&#…

口袋参谋:如何避免宝贝被降权?这招屡试屡爽!

​至少99.99999%的店铺在今年都被降权过&#xff01;各家店铺被降权的原因&#xff0c;无非就一个原因&#xff0c;那就是s单&#xff01; s单的风险也就两种&#xff0c;一是操作问题&#xff0c;二是账号问题。 操作问题被降权&#xff0c;这个大家都心知肚明&#xff0c;s…

5大原因,设备校准为什么是实验室搬迁后的首要任务?

实验室搬迁是一个复杂而紧张的过程。要考虑的事情太多&#xff0c;很容易忽视您最重要的任务之一——检查设备在新环境中的性能。 校准对于确保设备安全运行和遵守监管标准至关重要。 1.保持合规性并遵守法律要求 生物技术和制药等行业有特定的校准要求&#xff0c;实验室必…

Java详解之I/O[BIO、NIO、AIO使用方法和示范代码]

前言&#xff1a; 小弟能力不足&#xff0c;认知有限&#xff0c;难免考虑不全面&#xff0c;希望大佬能给出更好的建议&#xff0c;指出存在的问题和不足&#xff0c;在此跪谢。 IO发展史 Java中对于I/O能力的支持主要分为三个比较关键的阶段&#xff1a; BIO 第一个阶段…

浅谈安科瑞直流电表在印尼某基站的应用

摘要&#xff1a;本文介绍了安科瑞直流电表在印尼的应用。主要用于印尼某基站的电流电压电能的计量&#xff0c;配合霍尔传感器对基站进行计量。 Abstract: This article introduces the application of Acrel DC meters in base station in Indonesia.The device is measuri…

【此时不应有 \anaconda3\envs\ blenderproc \Library\ssl\cacert.pem】问题已解决

conda 创建新环境后&#xff0c;使用conda activate blenderproc命令激活环境时出现以下错误&#xff1a; 此时不应有 \anaconda3\envs\ blenderproc \Library\ssl\cacert.pem 其他博客里面https://blog.csdn.net/weixin_46599926/article/details/132576960解释这个是因为co…

前端 HTML 和 JavaScript 的基础知识有哪些?

前端开发是Web开发的一个重要领域&#xff0c;涉及到HTML&#xff08;Hypertext Markup Language&#xff09;和JavaScript两个主要的技术。HTML用于定义网页的结构和内容&#xff0c;而JavaScript用于实现网页的交互和动态效果。以下是前端HTML和JavaScript的基础知识&#xf…

如何做好测试管理岗?深度分析职业规划

在给学生做职业规划的时候&#xff0c;经常就有同学说&#xff1a;我以后要做管理岗&#xff01;其实对于很多刚入行的同学&#xff0c;可能说这句话的时候并没有真正理解管理岗需要做什么事&#xff0c;以及需要具备什么样的技能。所以&#xff0c;作为资深测试经理&#xff0…

飞翔的小鸟——Java

一、创建文件、包、类、插入图片文件 二、app包 1、Gameapp类&#xff08;运行游戏&#xff09; package app;import main.GameFrame;public class Gameapp {public static void main(String[] args) {//游戏的入口new GameFrame();} } 三、main包 1、Barrier&#xff08…

无需外接显示器,直接使用windows安装树莓派系统并可远程桌面登录

准备工作: 1.安装树莓派官方烧录工具 raspberry pi imager 2.下载树莓派系统镜像(也可选择在线下载安装) 打开imager工具&#xff0c;选择需要安装包树莓派版本 点击"NEXT"&#xff0c;在弹出的选项中选择编辑设置。 设置登录名和密码&#xff0c;已经所连接的wif…

统一用户桌面壁纸怎么设置

统一用户桌面壁纸的设置方法有多种&#xff0c;以下列举两种&#xff1a; 方法一&#xff1a;个人更换壁纸 1、右键桌面&#xff0c;鼠标选择“个性化”。 2、进入个性化之后&#xff0c;单击下面的“桌面背景”图标。 3、点击“浏览”选择自己备好的桌面壁纸&#xff0c;点击…

昇腾Atlas 200I DK A2实现安全帽识别

文章目录 环境依赖编译测试总结 环境依赖 软件版本说明获取方式mxVision5.0.RC2mxVision软件包获取方式Ascend-CANN-toolkit6.2.RC2Ascend-cann-toolkit开发套件包获取方式Ubuntu22.04 代码仓库地址&#xff1a; https://gitee.com/ascend/ascend_community_projects/tree/31…

01_原理-事件循环

01_原理-事件循环 文章目录 01_原理-事件循环一、浏览器的进程模型①&#xff1a;何为进程&#xff1f;②&#xff1a;何为线程&#xff1f;③&#xff1a;浏览器有哪些进程和线程&#xff1f; 二、渲染主线程是如何工作的&#xff1f;三、若干解释①&#xff1a;何为异步&…

不展现报表直接打印

不展现直接打印可以考虑这么几种方式&#xff1a;1、如果使用自带 demo 下的 jsp&#xff0c;可以把展现报表的 div 设置为隐藏&#xff0c;点击打印按钮可以打印&#xff1b;如果按钮都不想点&#xff0c;看下 toolbar.jsp 内打印按钮的 js 函数&#xff0c;在 jsp 末尾调用一…

LaTeX引文.bib方式插入报错 misplaced alignment tab character \end

写latex报了个莫名的错误&#xff0c;找了好久才找到原因。 参考文章 简单记录一下 在LaTeX中&符号有特殊含义&#xff0c;不能直接写。 直接复制生成的bibtex可能会有&&#xff0c;这种情况下可能会报错。 解决方法就是在&符号前面加一个斜杠\一定删除之前编译产生…

量子计算突破云渲染资源调度!真机测试完整报告公开!

​摘要&#xff1a;在影视领域中&#xff0c;经常会涉及大量的视频图像渲染工作&#xff0c;而往往在这种大规模、动态渲染场景下&#xff0c;普遍存在着冗余渲染现象。究其原因在于大规模的图像渲染通常要求在短时间内做出渲染任务的算力分配决策&#xff0c;而经典计算机无法…

【周报2023-11-24】

周报2023-11-24 本周主要工作下周工作计划 本周主要工作 本周的话一个主要工作有&#xff1a; 前后端进行联调接口&#xff1a; 那么目前为止的话&#xff0c;已经调通的接口 可以使用的是个人中心 历史生成的接口 选择新模板 新模板详情 ps: 下周工作计划 主要的话就是将…

金风玉露一相逢|实在智能联手浪潮信息合力致新生成式AI产业生态

近日&#xff0c;实在智能正式加入浪潮信息元脑生态AIStore。 实在智能是一家基于AGI大模型超自动化技术&#xff0c;领跑人机协同时代的人工智能科技公司&#xff0c;以其自研垂直的“TARS&#xff08;塔斯&#xff09;大语言模型”技术、实在RPA Agent智能体数字员工产品和超…

PSP - 蛋白质真实长序列查找 PDB 结构短序列的算法

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/134599076 在蛋白质结构预测的过程中&#xff0c;输入一般是蛋白质序列(长序列)&#xff0c;预测出 PDB 三维结构&#xff0c;再和 Ground Truth …

Android:控制按键灯亮灭【button-backlight】

/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java 1.导包 import java.io.DataOutputStream; import java.io.FileOutputStream; Handler mHandler3; 2.新建handler对象 public void init(Context context, IWindowManager windowMan…