2.qt调试日志输出

发布于:2025-07-28 ⋅ 阅读:(13) ⋅ 点赞:(0)

1.他们是什么?

qCDebug 和 qDebug 都是 Qt 提供的日志输出宏,但它们的用途和功能有所不同。

本质上就是一个宏定义来着,调用栈对象的一个接口

#define qDebug QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug
#define qInfo QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).info
#define qWarning QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).warning
#define qCritical QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).critical
#define qFatal QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).fatal


#if !defined(QT_NO_DEBUG_OUTPUT)
#  define qCDebug(category, ...) \
    for (bool qt_category_enabled = category().isDebugEnabled(); qt_category_enabled; qt_category_enabled = false) \
        QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC, category().categoryName()).debug(__VA_ARGS__)
#else
#  define qCDebug(category, ...) QT_NO_QDEBUG_MACRO()
#endif

#if !defined(QT_NO_INFO_OUTPUT)
#  define qCInfo(category, ...) \
    for (bool qt_category_enabled = category().isInfoEnabled(); qt_category_enabled; qt_category_enabled = false) \
        QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC, category().categoryName()).info(__VA_ARGS__)
#else
#  define qCInfo(category, ...) QT_NO_QDEBUG_MACRO()
#endif

#if !defined(QT_NO_WARNING_OUTPUT)
#  define qCWarning(category, ...) \
    for (bool qt_category_enabled = category().isWarningEnabled(); qt_category_enabled; qt_category_enabled = false) \
        QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC, category().categoryName()).warning(__VA_ARGS__)
#else
#  define qCWarning(category, ...) QT_NO_QDEBUG_MACRO()
#endif

#define qCCritical(category, ...) \
    for (bool qt_category_enabled = category().isCriticalEnabled(); qt_category_enabled; qt_category_enabled = false) \
        QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC, category().categoryName()).critical(__VA_ARGS__)

2.全局日志QDebug

不设置QLoggingCategory 输出的就是全局日志

#include <QDebug>  //引入头文件

他们有不同的输出等级

qDebug()<< “qDebug”; //调试信息
qWarning()<< “qWarning”; //警告信息
qInfo()<<“qInfo”; //普通信息
qCritical()<< “qCritical”; //错误信息
//qFatal()<<“qFatal”; //致命错误,终止程序

3.模块化日志QLoggingCategory

Q_LOGGING_CATEGORY(myCategory, “my.module”); //创建一个分类对象
使用qDebug可以不传,但是qCDebug必须传入分类对象

  #include <QLoggingCategory>
  Q_LOGGING_CATEGORY(myCategory, "my.module");
qCDebug(myCategory)
qCInfo(myCategory)
qCWarning(myCategory)
qCCritical(myCategory)
#include <QLoggingCategory>
Q_LOGGING_CATEGORY(myCategory, "my.module");
QString successText(){
    qWarning()<< "123123";
    return "4444";
}

int main(int argc, char *argv[])
{
	qCDebug(myCategory)<< successText();
    qCDebug(myCategory)<< successText();    //无损耗
}

根据输出结果可以发现输出有个前缀my.module

这样子我们开发插件或者模块 就可以通过此方法
知道是那部分代码输出的日志

在这里插入图片描述

3.使用案例

#include "widget.h"
#include <QDebug>
#include <QLoggingCategory>

#include <QApplication>
// Q_DECLARE_LOGGING_CATEGORY(myAppCore)
Q_LOGGING_CATEGORY(myAppCore, "myapp.core")

QString logstr()
{
    qWarning()<< "qWarning";
    qInfo()<<"qInfo";
    qCritical()<< "qCritical";
    return "222";
}

int main(int argc, char *argv[])
{
    qCDebug(myAppCore)<< logstr(); //模块化日志
    qDebug()<< logstr();



    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

4.全局宏开关控制

通过工程文件中设置日志禁用宏

编译器会优化掉日志代码,​零运行时开销。

意思就是使用案例中logstr()函数是不会执行的
无论是qCDebug还是qDebug都会被优化掉,无损耗

    qDebug()<< logstr();

DEFINES += QT_NO_DEBUG_OUTPUT
DEFINES += QT_NO_INFO_OUTPUT
DEFINES += QT_NO_WARNING_OUTPUT

5.环境变量开关控制

无需重新编译​:修改后直接重启应用即可生效。
​灵活控制​:可针对不同模块、不同日志级别(Debug/Info/Warning等)单独开关。

qDebug还是会执行案例中logstr,有损耗
qCDbug设置禁用后,是会被替换成空操作

# 关闭 "myapp.core" 分类的所有日志
export QT_LOGGING_RULES="myapp.core.*=false"

# 仅关闭 "myapp.network" 的 debug 日志,保留其他级别
export QT_LOGGING_RULES="myapp.network.debug=false"

# 同时控制多个分类
export QT_LOGGING_RULES="myapp.core.debug=false; myapp.network.warning=true"

6.使用建议

​发布版本​:结合编译期禁用(QT_NO_DEBUG_OUTPUT)彻底移除日志开销。
​开发阶段​:使用运行时禁用,灵活调试不同模块的日志。
如果需要动态控制输出,优先使用qCDebug进行日志输出,性能更好

7.日志重定向

可结合 QtMessageHandler 自定义处理函数

QtMessageHandler qInstallMessageHandler(QtMessageHandler);
多线程如果写入同一个文件记得加锁

#include <QApplication>
#include <QFile>
#include <QTextStream>

void myMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
    // 自定义处理逻辑(示例:写入文件 + 控制台)
    QFile logFile("app_log.txt");
    if (logFile.open(QIODevice::WriteOnly | QIODevice::Append)) {
        QTextStream stream(&logFile);
        stream << "[" << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") << "] "
               << msg << "\n";
    }
    // 可选:同时输出到标准错误(控制台)
    QTextStream(stderr) << msg << "\n";
}

int main(int argc, char *argv[]) {
    qInstallMessageHandler(myMessageHandler); // 注册自定义处理器
	//qInstallMessageHandler(nullptr); // 恢复默认处理器

    QApplication app(argc, argv);
    qDebug() << "This is a debug message";   // 会被 myMessageHandler 处理
    qCritical() << "Something went wrong!"; // 同上

    return app.exec();
}

网站公告

今日签到

点亮在社区的每一天
去签到