山东省住房和建设厅网站,wordpress留言簿,shopify建站,免费制作网页的网站终于这段时间闲下来了#xff0c;可以系统的编写Qt软件调试的整个系列。前面零零星星的也有部分输出#xff0c;但终究没有形成体系。借此机会#xff0c;做一下系统的总结。慎独、精进~
日志是有效帮助我们快速定位#xff0c;找到程序异常点的实用方法。但是好的日志才能…终于这段时间闲下来了可以系统的编写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 QFlagclass 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;QQueueQString 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 memoryCLog* 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::fromTypeLogTypes();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 QTimevoid 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、软件开发人员在编写打印输出的日志信息时需要统一输出格式对问题点输出可靠、可读性强的提示否则输出过多无关紧要的信息反而不利于问题的排查和分析。