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();
}