Qt implements log file log

Overview

Qt has two ways to record logs. The first is to install a custom Qt message handler to automatically output debugging messages, warnings, critical and fatal error messages generated by the program; the second is to customize a class, You can print out the specified content at the specified location of the program.

The first qInstallMessageHandler method

Customize the message processing function, and then install the function. Note that QDebug messages will be output in the log file at this time, and will not be printed when the Qt program is debugged.
main.cpp

#include "widget.h"
#include <QApplication>
#include <QMutex>
#include <QFile>
#include <QMessageLogContext>
#include <QDebug>
#include <QDateTime>

void outputMessage(QtMsgType type,const QMessageLogContext &context,const QString &msg);
int main(int argc, char *argv[])
{
    
    
    qInstallMessageHandler(outputMessage);//安装消息处理程序
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}

void outputMessage(QtMsgType type,const QMessageLogContext &context,const QString &msg)
{
    
    
    static QMutex mutex;
    mutex.lock();
    QByteArray localMsg = msg.toLocal8Bit();
    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:");
            break;
        default:
            text = QString("Debug:");
    }

    // 设置输出信息格式
       QString context_info = QString("File:(%1) Line:(%2)").arg(QString(context.file)).arg(context.line); // F文件L行数
       QString strDateTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
       //QString strMessage = QString("%1 %2 \t%3 \t%4").arg(text).arg(context_info).arg(strDateTime).arg(msg);
       QString strMessage = QString("%1 \t%2 \t%3").arg(text).arg(strDateTime).arg(msg);
       // 输出信息至文件中(读写、追加形式)
       QFile file(QString(QDateTime::currentDateTime().toString("yyyy-MM-dd").append("-log.txt")));
       file.open(QIODevice::ReadWrite | QIODevice::Append);
       QTextStream stream(&file);
       stream << strMessage << "\r\n";
       file.flush();
       file.close();
       // 解锁
        mutex.unlock();
}

The second type: customize a class to implement the output log interface

Define a log class to implement the interface for outputting logs to the specified file, and just call the interface where the log needs to be output.
clog.h

#ifndef CLOG_H
#define CLOG_H

#include <QFile>

class  CLog : public QObject
{
    
    
    Q_OBJECT
public:

    /*!
     *  @brief 日志等级
     */
    enum CLOG_LEVEL
    {
    
    
        RINFO,               /*!<    提示  */
        RWARNING,            /*!<    警告  */
        RERROR               /*!<    错误  */
    };
    Q_FLAG(CLOG_LEVEL)

    struct LogConfig
    {
    
    
        bool isRecord2File;     /*!< 是否记录到文件 */
        int level;              /*!< 记录日志等级,大于等于此level的日志将被记录 */
    };

    CLog();

    void setLogLevel(const CLog::CLOG_LEVEL & level);
    CLog::CLOG_LEVEL getLogLevel(){
    
    return logLevel;}

    static bool init(CLog::LogConfig & logConfig);
    static bool createDir(QString dirPath);

    static void log(CLOG_LEVEL nLevel,const char * fileDesc,const char * functionDesc, int lineNum,const char* data, ...);

private:
    static QString getLeveDesc(CLOG_LEVEL level);

private:
    static bool isRecord2File;
    static bool isFileReady;
    static CLOG_LEVEL logLevel;
};

#ifdef Q_OS_WIN
#define FILE_SEPARATOR '\\'
#else
#define FILE_SEPARATOR '/'
#endif

#define FUNC_SEPARATOR '::'

#ifndef QT_NO_DEBUG
#define __FILENAME__ (strrchr(__FILE__, FILE_SEPARATOR) ? (strrchr(__FILE__, FILE_SEPARATOR) + 1):__FILE__)
#define __FUNNAME__ (strrchr(__FUNCTION__,FUNC_SEPARATOR)?(strrchr(__FUNCTION__, FUNC_SEPARATOR) + 1):__FUNCTION__)
#else
#define __FILENAME__ NULL
#define __FUNNAME__ NULL
#endif

#define CLOG_INFO(...)       CLog::log(CLog::RINFO,__FILENAME__,__FUNNAME__,__LINE__, __VA_ARGS__)
#define CLOG_WARNING(...)    CLog::log(CLog::RWARNING, __FILENAME__,__FUNNAME__, __LINE__,__VA_ARGS__)
#define CLOG_ERROR(...)      CLog::log(CLog::RERROR,__FILENAME__,__FUNNAME__,__LINE__,__VA_ARGS__)

#endif // CLOG_H

clog.cpp

#include "clog.h"

#include <QApplication>
#include <QDir>
#include <QDate>
#include <QMetaEnum>
#include <QThread>
#include <QMutex>
#include <QMutexLocker>
#include <stdarg.h>

#include <QDebug>

const char PATH_LogPath[] = "/../logs";
const char Suffix[] = ".log";

#define MAX_LOG_LENGH 1024

bool CLog::isFileReady = false;
bool CLog::isRecord2File = true;
CLog::CLOG_LEVEL CLog::logLevel = CLog::RINFO;           //默认是info级

QFile localFile;
QMutex mutex;

CLog::CLog()
{
    
    
}

void CLog::setLogLevel(const CLog::CLOG_LEVEL &level)
{
    
    
    logLevel = level;
}

bool CLog::init(LogConfig &logConfig)
{
    
    
    isRecord2File = logConfig.isRecord2File;
    logLevel = (CLog::CLOG_LEVEL)logConfig.level;

    QString logDir = qApp->applicationDirPath() +  QString(PATH_LogPath);
    if(createDir(logDir))
    {
    
    
        QString fileName = logDir + QDir::separator() + QDate::currentDate().toString("yyyy-MM-dd") + QString(Suffix);
        localFile.setFileName(fileName);
        if(localFile.open(QFile::WriteOnly|QFile::Append|QFile::Text))
        {
    
    
            isFileReady = true;
        }
    }
    return isFileReady;
}

bool CLog::createDir(QString dirPath)
{
    
    
    QFileInfo fileInfo(dirPath);
    if(!fileInfo.exists())
    {
    
    
        QDir tmpDir;
        return tmpDir.mkpath(dirPath);
    }

    return true;
}

void CLog::log(CLOG_LEVEL nLevel, const char *fileDesc, const char *functionDesc, int lineNum, const char* data, ...)
{
    
    
    QMutexLocker locker(&mutex);
    if(isFileReady && nLevel >= logLevel)
    {
    
    
        QString recordInfo = QString("[%1]").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz"));
        recordInfo.append(getLeveDesc(nLevel));

#ifndef QT_NO_DEBUG
        recordInfo.append(QString("[%1:%2:%3]").arg(fileDesc).arg(functionDesc).arg(lineNum));
#endif
        va_list vlist;
        va_start(vlist,data);

        QByteArray byteArray;
#if defined(Q_OS_WIN)
        int recordLen = _vscprintf(data,vlist);
        byteArray.resize(recordLen);
#else
        byteArray.resize(1024);
#endif
        vsprintf(byteArray.data(),data,vlist);
        recordInfo.append(byteArray);
        va_end(vlist);

        recordInfo.append("\n");

        if(isRecord2File){
    
    
            localFile.write(recordInfo.toLocal8Bit().data(),recordInfo.toLocal8Bit().length());
            localFile.flush();
        }else{
    
    
//            qDebug()<<recordInfo;
        }
    }
}

QString CLog::getLeveDesc(CLog::CLOG_LEVEL level)
{
    
    
#if (QT_VERSION > 0x050500)
    static QMetaEnum metaEnum = QMetaEnum::fromType<CLog::CLOG_LEVEL>();
    return QString("[%1]").arg(metaEnum.key(level));
#else
    switch(level)
    {
    
    
        case CLOG_LEVEL::INFO:
                                return "[INFO]";
        case CLOG_LEVEL::INFO:
                                return "[WARNING]";
        case CLOG_LEVEL::INFO:
                                return "[ERROR]";
    }
#endif
}

Simple call example:

    CLog::LogConfig logConfig;
    logConfig.isRecord2File = true;
    logConfig.level = 0;
    CLog::init(logConfig);
    CLOG_INFO("df2008");

Output log:
[2020-12-03 13:15:14:549][RINFO][widget.cpp:Widget:17]df2008

Guess you like

Origin blog.csdn.net/weixin_40355471/article/details/110527027