zoukankan      html  css  js  c++  java
  • 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
    ", msg);
             break;
         case QtWarningMsg:
             fprintf(stderr, "Warning: %s
    ", msg);
             break;
         case QtCriticalMsg:
             fprintf(stderr, "Critical: %s
    ", msg);
             break;
         case QtFatalMsg:
             fprintf(stderr, "Fatal: %s
    ", 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)本人思路有限,若有更好的设计建议。也可发邮件沟通,在此先感谢。邮箱地址yang.ao@i-soft.com.cn。

  • 相关阅读:
    什么是守护线程?
    如何优雅地停止一个线程?
    如何创建、启动 Java 线程?
    什么是线程?什么是进程?为什么要有线程?有什么关系与区别?
    并行是什么意思?与并发的区别是什么?
    并发编程的缺点?
    BZOJ_3058_四叶草魔杖_kruscal+状压DP
    BZOJ_3476_[Usaco2014 Mar]The Lazy Cow_扫描线+切比雪夫距离
    BZOJ_1511_[POI2006]OKR-Periods of Words_KMP
    BZOJ_3479_[Usaco2014 Mar]Watering the Fields_Prim
  • 原文地址:https://www.cnblogs.com/jhcelue/p/6851596.html
Copyright © 2011-2022 走看看