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.pswp.cn/news/166955.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/166955.shtml
英文地址,請注明出處:http://en.pswp.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…