Qt | 实现输出日志文件 qInstallMessageHandler

191 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情

前言

之前一直是写纯C++程序的,MFC搭界面。程序中打印日志的方式,是通过创建一个日志类,在需要打印日志的地方,调用日志类的写入方法,将日志写到log.txt文件中,实现日志的记录功能。C++的代码实现起来还是比较繁琐的。

现在写Qt程序,Qt自己封装了很多功能,所以实现输出日志文件是比较方便的。它主要有两种方式:

第一种就是和纯C++输入日志的方法一样,自定义一个日志类,在程序想要输出日志的位置通过文件写入方式,按照指定的形式打印输出指定的内容。这种方法是需要我们手动完成的。

第二种是安装自定义的Qt消息处理程序,自动输出程序产生的调试消息、警告、关键和致命错误消息的函数。这种方法的好处是,你不需要在同一个地方既输出调试信息,又要输出日志信息。它可以直接将调试信息写入到日志文件中作为日志信息。

安装Qt消息处理程序 qInstallMessageHandler

qInstallMessageHandler介绍

qInstallMessageHandler(QtMessageHandlerhandler):

  • 消息处理程序是一个输出调试消息、警告、关键和致命错误消息的函数。
  • Qt库(调试模式)包含数百条警告消息,当发生内部错误(通常是无效函数参数)时,会打印这些警告消息。
  • 在发布模式中内置的Qt也包含此类警告,除非在编译期间设置了QT_NO_WARNING_OUTPUT和/或QT_NO_DEBUG_OUTPUT。如果实现自己的消息处理程序,则可以完全控制这些消息。
  • 默认消息处理程序将消息打印到X11下的标准输出或Windows下的调试器。如果是致命消息,应用程序立即终止。
  • 只能定义一个消息处理程序,因为这通常是在应用程序范围内完成的,以控制调试输出。

日志功能实现

1.首先自定义消息处理函数

void LogMsgOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    // 加锁
    QMutex mutex;
    mutex.lock();
    
    // 时间
    QString strTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    
    // 根据消息类型设置输出信息格式
    QByteArray localMsg = msg.toLocal8Bit();
    QString log;
    switch (type) {
    case QtDebugMsg:
        log.append(QString("[%1] Debug Content: %2").arg(strTime).arg(msg));
        break;
    case QtInfoMsg:
        log.append(QString("[%1] Info: %2").arg(strTime).arg(msg));
        break;
    case QtWarningMsg:
        log.append(QString("Warning: %1  %2  %3  %4").arg(localMsg.constData()).arg(context.file).arg(context.line).arg(context.function));
        break;
    case QtCriticalMsg:
        log.append(QString("Critical: %1  %2  %3  %4").arg(localMsg.constData()).arg(context.file).arg(context.line).arg(context.function));
        break;
    case QtFatalMsg:
        log.append(QString("Fatal: %1  %2  %3  %4").arg(localMsg.constData()).arg(context.file).arg(context.line).arg(context.function));
        abort();
    }
    
    // 创建日志文件并用时间信息命名
    QFile file;
    QString path = QCoreApplication::applicationDirPath() + QString("/Log/%1.log").arg(strTime);
    file.setFileName(path);
    
    // 输出信息至文件中(读写、追加形式)
    if (!file.open(QIODevice::ReadWrite | QIODevice::Append))
    {
        QString erinfo = file.errorString();
    }
    else
    {
        QTextStream outStream(&file);
        outStream << log << "\n\r";
        file.flush();
        file.close();
    }
    
    // 解锁
    mutex.unlock();
}

2.然后调用qInstallMessageHandler安装该函数

// 在main函数中安装该函数。
int main(int argc, char *argv[])
{
    bWriteLog = true;
    if(bWriteLog)
    {
        qInstallMessageHandler(LogMsgOutput);
    }
}

这样你在程序中所有调用qDebug、qInfo、qWarning、qCritical、qFatal的地方,都会打印到日志文件中。
通过bWriteLog标志位来设置是否输出日志信息。

3.消息类型讲解 QtMsgType这个枚举描述可以发送到消息处理程序(QtMessageHandler)的消息。可以使用枚举来标识各种消息类型,并将它们与适当的操作关联起来。

  • QtDebugMsg:由qDebug()函数生成的消息。
  • QtInfoMsg:由qInfo()函数生成的消息。
  • QtCriticalMsg:由qCritical()函数生成的消息。
  • QtFatalMsg:由qFatal()函数生成的消息。