1. 程式人生 > >Qt淺談之二十一log除錯日誌

Qt淺談之二十一log除錯日誌

一、簡介

      最近因除錯code時,想了解程式的流程,但苦於沒有一個簡易的日誌記錄,不停使用qDebug列印輸出,而最終提交程式碼時得去多次刪除列印資訊,有時還會出現新修改的程式碼分不清是哪些部分。而使用#ifdef _DEBUG又比較煩這套,因此寫了些簡單的日誌,方便排除問題,暫時不能用於多執行緒中,以後需要再補充。

二、詳解

1、追蹤函式

#ifdef _DEBUG_PRINT
#define DEBUGPRINT DEBUGInfo printinfo(__FILE__, __LINE__, __FUNCTION__);
#else
#define DEBUGPRINT
#endif

class DEBUGInfo
{
public:
    DEBUGInfo(QString file, int line, QString func);
    ~DEBUGInfo();
    
private:
    QString fileName;
    int fileLine;
    QString funcName;
};
DEBUGInfo::DEBUGInfo(QString file, int line, QString func)
    :fileName(file)
    ,fileLine(line)
    ,funcName(func)
{
  QString result = "";
  QString beginTime = QDateTime::currentDateTime().toString("[yyyy-dd-MM hh:mm:ss.zzz] ");
  result += beginTime + "Enter:{" + fileName + ":" + QString::number(fileLine) + "---" + funcName + "}";
  qDebug() << result.toStdString().c_str();
}
DEBUGInfo::~DEBUGInfo()
{
  QString result = "";
  QString beginTime = QDateTime::currentDateTime().toString("[yyyy-dd-MM hh:mm:ss.zzz] ");
  result += beginTime + "Leave:{" + fileName + ":" + QString::number(fileLine) + "---" + funcName + "}";
  qDebug() << result.toStdString().c_str();
}

使用:在需要檢視的函式中加入DEBUGPRINT即可,輸出檔名,所在的行和函式名字。

void HelloWorld()
{
    DEBUGPRINT
}

2、列印資訊和寫日誌檔案

enum LOGLEVEL{          
    LOG_DEBUG = 0,      /**< Debug >**/
    LOG_INFO,           /**< Info >**/
    LOG_WARN,           /**< Warn >**/
    LOG_ERROR           /**< Error >**/
};
class LogWriter{
    public:
        static LogWriter* getLogCenter();
        void PrintLog(LOGLEVEL level, const char* msg, ...);
        void SaveFileLog(LOGLEVEL level, const char* msg, ...);
        void setLogPath(QString logPath);         //defalut: current path
        void setLogLevel(LOGLEVEL logLevel);      //defalut: LOG_DEBUG
    private:
        static LogWriter * _logCenter;
        explicit LogWriter();
        ~LogWriter();
    private:
        QString _logPath;
        LOGLEVEL _logLevel;
    private:
        QString getLevelStr(LOGLEVEL level);
};
LogWriter *LogWriter::getLogCenter()
{
    if (_logCenter == NULL)
        _logCenter = new LogWriter;
    return _logCenter;
}

LogWriter::LogWriter()
{
    _logLevel = LOG_DEBUG;
    _logPath = QDir::currentPath();
}

LogWriter::~LogWriter()
{
    if (_logCenter) {
        delete _logCenter;
        _logCenter = NULL;
    }
}

void LogWriter::PrintLog(LOGLEVEL level, const char *msg,  ...)
{
    if (level < _logLevel)  return;     //low level
    char logBuffer[8192] = {0};
    va_list vl_fmt;                     //buffer
    va_start(vl_fmt, msg);
    vsprintf(logBuffer, msg, vl_fmt);
    va_end(vl_fmt);

    QString fileTime = "";
    QString logTime = "";
    QString logLevel = getLevelStr(level);
    fileTime = QDateTime::currentDateTime().toString("yyyyddMM");
    logTime = QDateTime::currentDateTime().toString("yyyy-dd-MM hh:mm:ss.zzz");
    qDebug("[%s] [%s] {%s}", logTime.toStdString().c_str(), logLevel.toStdString().c_str(), logBuffer);
}

void LogWriter::SaveFileLog(LOGLEVEL level, const char *msg,  ...)
{
    if (level < _logLevel)  return;  //low level
    char logBuffer[8192] = {0};
    va_list vl_fmt;                  //buff
    va_start(vl_fmt, msg);
    vsprintf(logBuffer, msg, vl_fmt);
    va_end(vl_fmt);

    QString logTime = "";
    QString fileTime = "";
    fileTime = QDateTime::currentDateTime().toString("yyyyddMM");
    logTime = QDateTime::currentDateTime().toString("[yyyy-dd-MM hh:mm:ss.zzz]");
    QString logLevel = getLevelStr(level);
    QString logFile = _logPath;
    if (logFile.right(1) != "/") {
        logFile += "/";
    }
    QDir mDir(logFile);
    if (!mDir.exists()) {
        mDir.mkpath(logFile);
    }
    logFile += "isoft_";
    logFile += fileTime;
    logFile += ".log";

    QFile file(logFile);
    file.open(QIODevice::ReadWrite | QIODevice::Append | QIODevice::Text);
    QTextStream out(&file);
    out << logTime << " [" << logLevel << "] " << "{" << logBuffer << "}" << endl;
    file.close();
}

QString LogWriter::getLevelStr(LOGLEVEL level)
{
    switch(level) {
        case LOG_DEBUG: return "LOG_DEBUG"; break;
        case LOG_INFO: return "LOG_INFO"; break;
        case LOG_WARN: return "LOG_WARN"; break;
        case LOG_ERROR: return "LOG_ERROR"; break;
    }
}

void LogWriter::setLogPath(QString logPath)
{
    _logPath = logPath;
}

void LogWriter::setLogLevel(LOGLEVEL logLevel)
{
    _logLevel = logLevel;
}
可以設定日誌的級別和日誌檔案的路徑。

在函式中使用:

LogWriter::getLogCenter()->PrintLog(LOG_DEBUG, "hello world");
LogWriter::getLogCenter()->PrintLog(LOG_INFO, "%s:%s,%d", "hello", "world", 1234);
LogWriter::getLogCenter()->SaveFileLog(LOG_WARN, "hello world");
LogWriter::getLogCenter()->SaveFileLog(LOG_ERROR, "%s:%s,%d", "hello", "world", 1234);

也會在當前路徑下生成檔案。

3、Qt自帶例子

Qt官方例子:
 #include <qapplication.h>
 #include <stdio.h>
 #include <stdlib.h>

 void myMessageOutput(QtMsgType type, const char *msg)
 {
     switch (type) {
     case QtDebugMsg:
         fprintf(stderr, "Debug: %s\n", msg);
         break;
     case QtWarningMsg:
         fprintf(stderr, "Warning: %s\n", msg);
         break;
     case QtCriticalMsg:
         fprintf(stderr, "Critical: %s\n", msg);
         break;
     case QtFatalMsg:
         fprintf(stderr, "Fatal: %s\n", msg);
         abort();
     }
 }

 int main(int argc, char **argv)
 {
     qInstallMsgHandler(myMessageOutput);
     QApplication app(argc, argv);
     ...
     return app.exec();
 }
自定義修改:
void outputMessage(QtMsgType type, const char *msg)
{
    static QMutex mutex;
    mutex.lock();

    QString text;
    switch(type)
    {
    case QtDebugMsg:
        text = QString("Debug:");
        break;

    case QtWarningMsg:
        text = QString("Warning:");
        break;

    case QtCriticalMsg:
        text = QString("Critical:");
        break;

    case QtFatalMsg:
        text = QString("Fatal:");
        abort();
    }
    QString message = QString("[%1] %2 %3").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss ddd")).arg(text).arg(msg);

    QFile file("log.txt");
    file.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream text_stream(&file);
    text_stream << message << endl;
    file.flush();
    file.close();

    mutex.unlock();
}
qInstallMsgHandler(outputMessage);
qWarning("This is a warning message");
qCritical("This is a critical message");
//qInstallMsgHandler(0)    //To restore the message handler, call
執行結果:

三、總結

(1)本文只是一個簡單的日誌記錄,還可以設計成非同步的多執行緒式的,甚至可以加入到執行緒池,對效能要求較高的系統還得考慮檔案的大小控制、儲存空間的控制、檔案的級別控制、檔案的日期控制和自動清除等操作。
(2)本人思路有限,若有更好的設計建議,也可發郵件溝通,在此先感謝!郵箱地址[email protected]

相關推薦

Qtlog除錯日誌

一、簡介       最近因除錯code時,想了解程式的流程,但苦於沒有一個簡易的日誌記錄,不停使用qDebug列印輸出,而最終提交程式碼時得去多次刪除列印資訊,有時還會出現新修改的程式碼分不清是哪些部分。而使用#ifdef _DEBUG又比較煩這套,因此寫了些簡單的日誌

Qtlog調試日誌

gms 生成文件 _file__ ica 沒有 rest delet mar 排除 一、簡單介紹 近期因調試code時,想了解程序的流程,但苦於沒有一個簡易的日誌記錄,不停使用qDebug打印輸出,而終於提交代碼時得去多次刪除信息打印,有時還會出現新改動

QtQT_OpenGL

一、簡介           最近想了解些Qt的OpenGL程式設計,可能以後會使用。Opengl是對2D和3D圖形支援很好,有非常多的優化函式,而且是個跨平臺的開源庫。Qt的Opengl封裝的很好,通過Qt的QGLWidget類,將opengl的函式和Qt的介面結合了

Qt五2048遊戲(原始程式碼來自網路)

一、簡介         Qt改寫2048遊戲,在linux系統下找尋android的視覺效果。 二、執行圖         啟動執行圖: 三、詳解 1、程式碼 (1)widget.h #ifndef WIDGET_H #define WIDGET_H #inclu

QtQLineEdit的新樣式和補全歷史記錄

一、簡介        利用背景圖片設計出QLineEdit新的樣式,起到美化介面的效果,並增加自動補全歷史記錄的功能,就可以作為一個完整的庫。  二、詳解 1、知識點 (1)切換QLineEdit的背景 void InnerLineEdit::setNormal()

Qt八解析XML檔案

一、簡介         QtXml模組提供了一個讀寫XML檔案的流,解析方法包含DOM和SAX。DOM(Document ObjectModel):將XML檔案表示成一棵樹,便於隨機訪問其中的節點,但消耗記憶體相對多一些。SAX(Simple APIfor XML):一

QtQt樣式表

一、簡介       不斷總結好的樣式表,美化自己的介面(在實際工作中會不斷的更新)。 二、詳解 1、載入樣式表文件 QFile file(":/qss/stylesheet.qss"); file.open(QFile::ReadOnly); QString sty

Qt維碼條形碼解析

一、簡介         二維條碼/二維碼(2-dimensional bar code)是用某種特定的幾何圖形按一定規律在平面(二維方向上)分佈的黑白相間的圖形記錄資料符號資訊的,其應用廣泛,如:產品防偽/溯源、廣告推送、網站連結、資料下載、商品交易、定位/導航、電子憑

Qt八視窗下方彈出提示資訊

一、簡介       在專案中一般都會彈出新的子對話方塊顯示提示資訊,但對於一些因後臺資料變化引發的提示還是在視窗下方彈出提示資訊比較合理。點選按鈕彈出提示資訊,當滑鼠放在提示資訊對話方塊上時,暫停動畫可長時間檢視提示資訊。 二、詳解 1、程式碼 (1)fader

Qt介面自定義

一、簡介       Qt自帶的介面不利於樣式的調整和美化,自定義介面便於設計風格。 二、詳解 1、程式碼 (1)pagenumbercontrol.h #ifndef PAGENUMBERCONTROL_H #define PAGENUMBERCONTROL_H

QtCentos下Qt結合v4l2實現的視訊顯示

一、簡介        v4l2是針對uvc免驅usb裝置的程式設計框架,主要用於採集usb攝像頭。 可從網上下載最新的原始碼(包括v4l2.c和v4l2.h兩個檔案),本文中修改過。       Qt執行介面如下(動態變化的): 二、詳解 1、準備 (1)插入usb攝

Qt:拖拽文字圖片

一、簡介        首先選擇窗體顯示風格,接著顯現拖拽效果,文字和圖示都可以作為拖拽的物件,在窗體中的文字圖示可以拖拽到視窗的任意位置,它們在兩個獨立執行的程式間也可相互拖拽(此時是複製一份到拖拽目的程式視窗中),文字拖拽的範圍更廣(須注意字符集的轉換)。本文解決這種

Qt六:TCP和UDP(之一)

一、簡介        Qt使用QtNetwork模組來進行網路程式設計,提供了一層統一的套接字抽象用於編寫不同層次的網路程式,避免了應用套接字進行網路編的繁瑣(因有時需引用底層作業系統的相關資料結構)。有較底層次的類如QTcpSocket、QTcpServer和QUdp

轉: 【Java並發編程】:並發新特性—阻塞隊列和阻塞棧(含代碼)

err 退出 link rac gb2312 com void throws pbo 轉載請註明出處:http://blog.csdn.net/ns_code/article/details/17511147 阻塞隊列 阻塞隊列是Java 5並發新特性中的內容

C#設計模式訪問者模式(Visitor Pattern)【行為型】

href 集中 動態 元素 lis 聲明 風格 on() 封裝 原文:C#設計模式之二十一訪問者模式(Visitor Pattern)【行為型】一、引言 今天我們開始講“行為型”設計模式的第九個模式,該模式是【訪問者模式】,英文名稱是:Visitor Pattern。如

Linux學習-shell編程基礎

用法 htm 如果 重定向 -a 創建 過去 .html 編寫代碼 Shell編程基礎 Shell 是一個用 C 語言編寫的程序,它是用戶使用 Linux 的橋梁。Shell 既是一種命令語言,又是一種程序設計語言。Shell 是指一種應用程序,這個應用程序提供了一個界面,

42.回文數——C語言初學者百題大戰

pre clu class printf sca tdi == c語言 pan #include<stdio.h> int main() { int a,b,c,d,e,n; scanf("%d",&n); a=n/10000;

ElasticSearch學習筆記 指標聚合

ElasticSearch學習筆記之二十一 指標聚合 指標聚合 Avg Aggregation Script Value Script Missing value Weighted Avg Agg

UART串列埠通訊()--暫存器設定

1.1 通訊的三種基本型別 常用的通訊通常可以分為單工、半雙工、全雙工通訊。 單工就是指只允許一方向另外一方傳送資訊,而另一方不能回傳資訊。比如我們的電視遙控器,我們的收音機廣播等,都是單工通訊技術。 半雙工是指資料可以在雙方之間相互傳播,但是同一時刻只能其中一方發給另外一方,

Swift 學習:?和 !(詳解)

新更新的內容請移步閱讀: Swift語言使用var定義變數,但和別的語言不同,Swift裡不會自動給變數賦初始值, 也就是說變數不會有預設值,所以要求使用變數之前必須要對其初始化 。如果在使用變數之前不進行初始化就會報錯: var stringValue : Stri