Qt C++实战:如何捕捉Qt调试信息,统一格式化,并保存到日志文件?

本文介绍了如何在Qt开发中使用qInstallMessageHandler捕获所有调试信息,并通过自定义的日志处理类MyLogging添加时间戳、等级等格式,将信息保存到日志文件,便于后续追踪和数据分析。
摘要由CSDN通过智能技术生成

01 背景说明

做Qt开发经常需要用到qDebug、qWarning这些来查看输出信息,配合调试程序,但这些输出信息只输出到调试窗口,或者是程序执行的控制台窗口上。

今天我们来学习,如何捕捉所有的Qt调试信息,并统一对调试信息加上时间戳、消息等级、文件名、行号等,最后将消息内容保存到日志文件,方便日后程序的跟踪、和数据分析。

02 关键技术点

关键技术点是使用Qt提供的一个qInstallMessageHandler()函数,qInstallMessageHandler()用于注册消息处理函数,注册后消息处理函数将会捕捉所有的调试信息,并进行统一处理。函数原型和使用示例如下:

// 消息处理函数原型
typedef void (*QtMessageHandler)(QtMsgType, const QMessageLogContext &, const QString );
QtMessageHandler qInstallMessageHandler(QtMessageHandler);

// 例子:

// 定义信息处理函数
void MyMessageHandler(QtMsgType eMsgType, const QMessageLogContext& logContext, const QString &text)
{
    // ...
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    
    // 注册消息处理函数
    qInstallMessageHandler(MyMessageHandler);
    
}

03 增加一个日志处理类来处理

关键点我们都懂了,但为了方便使用,我们封装一个日志处理类MyLogging,该日志处理类除了实现捕捉调试信息外,还统一给调试信息加上日期、时间,消息等级等格式化内容,并保存到日志文件。

  • MyLogging类设计:
#ifndef MYLOGGING_H
#define MYLOGGING_H

#include <QFile>


// 日志处理类
class MyLogging
{
public:
    MyLogging();

    // 做成单实例
    static MyLogging& getInstance();

    // 打开日志功能
    bool openLogging(const QString& qstrFileName);

    // 关闭日志功能
    void closeLogging();

    // 保存消息到日志文件
    bool saveMsgToLogFile(const QString& qstrMsgText);

private:
    static MyLogging gLogging;
    // 日志文件对象
    QFile m_logFile;
};

#endif // MYLOGGING_H
  • 消息处理函数核心代码:

捕捉消息函数入口,在这里可以格式化消息内容,如增加消息时间戳、等级等内容。

#include <QDateTime>
#include <iostream>

// 消息处理函数,用来格式化消息文本,输出屏幕和保存到文件
void MyMessageHandler(QtMsgType eMsgType, const QMessageLogContext& logContext, const QString &msg)
{
    // 时间戳:yyyy-MM-dd hh:mm:ss zzz
    const QString qstrLogTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss zzz");

    // 消息类型
    QString qstrMsgType;
    switch (eMsgType)
    {
    case QtMsgType::QtDebugMsg:
        qstrMsgType = "Debug";
        break;
    case QtMsgType::QtWarningMsg:
        qstrMsgType = "Warning";
        break;
    case QtMsgType::QtCriticalMsg:
        qstrMsgType = "Critical";
        break;
    case QtMsgType::QtFatalMsg:
        qstrMsgType = "Fatal";
        break;
    case QtMsgType::QtInfoMsg:
        qstrMsgType = "Info";
        break;
    default: break;
    }

    // 消息文本日志内容
    const QString qstrLogText = QString("%0 [%1] (%2:%3 %4) %5")
                                    .arg(qstrLogTime)
                                    .arg(qstrMsgType)
                                    .arg(logContext.file)
                                    .arg(logContext.line)
                                    .arg(logContext.function)
                                    .arg(msg);
    // 打印到屏幕
    std::cout << qstrLogText.toStdString() << std::endl;
    // 保存到日志文件
    MyLogging::getInstance().saveMsgToLogFile(qstrLogText);
}
  • 打开日志文件代码:
bool MyLogging::openLogging(const QString &qstrFileName)
{
    if (m_logFile.isOpen())
    {
        // 已经打开,返回true
        return true;
    }

    m_logFile.setFileName(qstrFileName);
    QIODevice::OpenMode e_open_mode = QIODevice::WriteOnly | QIODevice::Text;
    if (QFile::exists(qstrFileName))
    {
        // 日志文件已经存在
        e_open_mode |= QIODevice::Append;
    }
    // 打开日志文件
    if (!m_logFile.open(e_open_mode))
    {
        return false;
    }

    // 注册消息处理函数
    qInstallMessageHandler(MyMessageHandler);
    return true;
}
  • 关闭日志文件代码:
void MyLogging::closeLogging()
{
    qInstallMessageHandler(nullptr);
    m_logFile.close();
}
  • 保存消息到日志文件
bool MyLogging::saveMsgToLogFile(const QString &qstrMsgText)
{
    if (!m_logFile.isOpen())
    {
        return false;
    }

    // 加上回车符(一条消息,一条日志)
    QString qstrLog = qstrMsgText+"\n";
    m_logFile.write(qstrLog.toUtf8());
    return true;
}

04 使用日志处理类应用到项目

#include <QCoreApplication>
#include <locale>
#include "MyLogging.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 支持 UTF8 编码
    std::locale loc{ "el_GR.utf8" };
    std::locale::global(loc);

    // 打开日志文件功能
    MyLogging::getInstance().openLogging("qt_message_handler_log.txt");

    // 输出日志信息
    qDebug() << "这是一条 debug 调试消息。";
    qWarning() << "这是一条 warning 警告消息。";
    qCritical() << "这是一条 critical 严重消息。";

    // 关闭日志文件功能
    MyLogging::getInstance().closeLogging();
    return a.exec();
}

执行输出日志如下:

生成日志文件内容:

05 附录:完整源码

关注公众号下载本示例完整源码(07_Qt_MessageHandler_practical.zip)。

-【End】-

#想了解更多精彩内容,关注下方公众号,还有示例源码、开发工具免费下载。

喜欢本文章,记得点赞、分享、关注哦~

  • 33
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是一个简单的示例程序,演示了如何使用Qt保存学生信息到XML文件中。 ```cpp #include <QCoreApplication> #include <QXmlStreamWriter> #include <QFile> #include <QDebug> struct Student { int id; QString name; int score; }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 创建一个学生列表 QList<Student> students; students.append({1, "Alice", 90}); students.append({2, "Bob", 80}); students.append({3, "Charlie", 70}); // 创建一个XML文件 QFile file("students.xml"); if (!file.open(QIODevice::WriteOnly)) { qWarning() << "Failed to open file"; return 1; } // 写入XML数据 QXmlStreamWriter writer(&file); writer.setAutoFormatting(true); writer.writeStartDocument(); writer.writeStartElement("students"); for (const auto &student : students) { writer.writeStartElement("student"); writer.writeAttribute("id", QString::number(student.id)); writer.writeTextElement("name", student.name); writer.writeTextElement("score", QString::number(student.score)); writer.writeEndElement(); } writer.writeEndElement(); writer.writeEndDocument(); // 关闭文件 file.close(); qDebug() << "Students saved to XML file."; return 0; } ``` 这个程序使用了`QXmlStreamWriter`类来写入XML数据。它可以自动格式化输出并处理特殊字符。在本例中,我们创建一个`QList`来保存学生列表,并将其写入XML文件中。我们使用`writeStartDocument`和`writeEndDocument`方法来写入XML文件的头和尾,并使用`writeStartElement`和`writeEndElement`方法来写入元素。我们使用`writeAttribute`方法来写入学生ID,使用`writeTextElement`方法来写入学生姓名和分数。 通过运行程序,我们会在根目录下生成一个名为`students.xml`的XML文件,包含以下内容: ```xml <?xml version="1.0"?> <students> <student id="1"> <name>Alice</name> <score>90</score> </student> <student id="2"> <name>Bob</name> <score>80</score> </student> <student id="3"> <name>Charlie</name> <score>70</score> </student> </students> ``` 这个XML文件包含了学生列表中每个学生的ID、姓名和分数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天恩软件工作室

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值