在 Qt 中,日志级别主要通过 qDebug()
, qInfo()
, qWarning()
, qCritical()
和 qFatal()
这几个宏来区分。它们分别对应不同的严重程度。
一、Qt 内置的日志级别(按严重程度从低到高排序)
宏 / 函数 | 日志级别 | 说明 | 默认行为 |
---|---|---|---|
qDebug() |
Debug | 调试信息。用于程序开发调试阶段输出详细信息,发布版本通常关闭。 | 输出到 stderr(或系统日志)。 |
qInfo() |
Info | 信息消息。用于输出程序正常运行时的状态信息(如启动、配置加载成功)。 | 输出到 stderr(或系统日志)。 |
qWarning() |
Warning | 警告消息。表明发生了意外情况,但应用程序仍能继续运行(如解析配置文件失败使用默认值)。 | 输出到 stderr(或系统日志)。 |
qCritical() |
Critical | 严重错误消息。表明发生了严重错误,应用程序可能无法继续正常运行(如磁盘空间不足、关键功能失效)。 | 输出到 stderr(或系统日志)。 |
qFatal() |
Fatal | 致命错误消息。在输出此消息后,应用程序会自动中止(abort)。用于发生了不可恢复的错误(如断言失败、关键数据损坏)。 | 输出到 stderr 并调用 abort() 终止程序。 |
二、 基本使用示例
cpp
#include <QCoreApplication>
#include <QDebug>
#include <QInfo>
#include <QWarning>
#include <QCritical>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "This is a DEBUG message. Value of argc:" << argc;
qInfo() << "This is an INFO message. Application started successfully.";
qWarning() << "This is a WARNING message. Configuration file not found, using defaults.";
qCritical() << "This is a CRITICAL message. Failed to connect to the database!";
// 下面的语句会终止程序
// if (someCriticalError)
// qFatal("Fatal error: Unable to start the core component. Aborting.");
return a.exec();
}
输出示例:
text
debug: This is a DEBUG message. Value of argc: 1
info: This is an INFO message. Application started successfully.
warning: This is a WARNING message. Configuration file not found, using defaults.
critical: This is a CRITICAL message. Failed to connect to the database!
三、 高级控制:分类日志(Categorized Logging)和规则(Rules)
从 Qt 5.2 开始,引入了更精细的日志控制系统。你可以为不同的日志类别(Category)设置不同的级别和输出规则。
a. 定义日志类别
使用 Q_LOGGING_CATEGORY
宏来定义一个类别。
cpp
// 在头文件中定义
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(myAppCore)
Q_DECLARE_LOGGING_CATEGORY(myAppUi)
// 在源文件中实现
Q_LOGGING_CATEGORY(myAppCore, "myapp.core")
Q_LOGGING_CATEGORY(myAppUi, "myapp.ui")
b. 使用类别日志
使用 qCDebug()
, qCInfo()
, qCWarning()
, qCCritical()
宏。
cpp
qCDebug(myAppCore) << "Core module initialized.";
qCWarning(myAppUi) << "UI component took too long to respond.";
示例
假设你的应用叫 "ChatApp":
cpp
// main.cpp
#include <QApplication>
#include <QLoggingCategory>
// 定义日志类别
Q_LOGGING_CATEGORY(chatapp, "chatapp")
Q_LOGGING_CATEGORY(chatappNetwork, "chatapp.network")
Q_LOGGING_CATEGORY(chatappMessage, "chatapp.message")
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
app.setApplicationName("ChatApp");
qCInfo(chatapp) << "ChatApp started";
qCDebug(chatappNetwork) << "Network module initialized";
return app.exec();
}
输出结果
在 Qt 的 Debug 构建模式下,通常能看到:
text
chatapp.info: ChatApp started
chatapp.network.debug: Network module initialized
在 Release 构建模式下,默认可能只看到:
text
chatapp.info: ChatApp started
c. 通过环境变量配置日志规则
你可以在程序启动前设置 QT_LOGGING_RULES
环境变量来控制哪些类别的日志应该被输出。
示例:
禁用所有调试日志:
bash
export QT_LOGGING_RULES="*.debug=false" ./myapp
启用
myapp.core
类别的调试日志,禁用其他所有调试日志:bash
export QT_LOGGING_RULES="myapp.core.debug=true;*.debug=false" ./myapp
在 Windows 命令提示符中:
cmd
set QT_LOGGING_RULES=myapp.core.debug=true;*.debug=false myapp.exe
d. 在代码中配置规则
你也可以在代码中通过 QLoggingCategory::setFilterRules()
来设置规则。
cpp
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 在代码中设置规则
QString rules;
rules = "*.debug=false\n"
"*.info=true\n"
"*.warning=true\n"
"*.critical=true\n"
"myapp.*.debug=true\n"
"qt.*.debug=false";
QLoggingCategory::setFilterRules(rules);
// ... 其余代码 ...
return a.exec();
}
四、配置文件来控制日志输出
日志级别输出控制权交给logging.conf文件,通过修改文件增加或减少日志打印输出。
1. log规则读取类
logger.h
#ifndef LOGGER_H
#define LOGGER_H
#include <QString>
#include <QMap>
class Logger
{
public:
static bool loadConfig(const QString &configPath);
static void setDefaultConfig();
static void enableDebug(bool enable);
static void enableCategory(const QString &category, bool enable);
static QString getCurrentRules();
private:
Logger() = delete;
// 静态变量用于存储当前规则
static QMap<QString, bool> m_rules;
static void applyRules();
static void parseAndAddRule(const QString &ruleLine);
};
#endif // LOGGER_H
logger.cpp
#include "logger.h"
#include <QLoggingCategory>
#include <QFile>
#include <QTextStream>
#include <QSettings>
#include <QDebug>
#include <QRegularExpression>
// 初始化静态成员变量
QMap<QString, bool> Logger::m_rules;
bool Logger::loadConfig(const QString &configPath)
{
QFile file(configPath);
if (!file.exists()) {
qWarning() << "Logging config file not found:" << configPath;
return false;
}
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning() << "Cannot open logging config:" << configPath;
return false;
}
// 清空现有规则
m_rules.clear();
QTextStream in(&file);
QString rules;
while (!in.atEnd()) {
QString line = in.readLine().trimmed();
// 跳过注释和空行
if (line.startsWith('#') || line.startsWith("//") || line.isEmpty()) {
continue;
}
parseAndAddRule(line);
}
file.close();
applyRules();
qInfo() << "Logging configuration loaded successfully";
return true;
}
void Logger::parseAndAddRule(const QString &ruleLine)
{
QString pattern;
bool enabled = true;
if (ruleLine.contains('=')) {
// 处理 key=value 格式
int equalsIndex = ruleLine.indexOf('=');
pattern = ruleLine.left(equalsIndex).trimmed();
QString value = ruleLine.mid(equalsIndex + 1).trimmed();
if (value.compare("false", Qt::CaseInsensitive) == 0 || value == "0") {
enabled = false;
} else {
enabled = true;
}
} else {
// 处理简单格式
pattern = ruleLine;
enabled = true;
}
if (!pattern.isEmpty()) {
m_rules[pattern] = enabled;
}
}
void Logger::applyRules()
{
QString rulesStr;
QMap<QString, bool>::const_iterator it;
for (it = m_rules.constBegin(); it != m_rules.constEnd(); ++it) {
rulesStr += QString("%1=%2\n").arg(it.key()).arg(it.value() ? "true" : "false");
}
QLoggingCategory::setFilterRules(rulesStr);
}
void Logger::setDefaultConfig()
{
m_rules.clear();
// 设置默认规则
m_rules["*.debug"] = false;
m_rules["*.info"] = true;
m_rules["*.warning"] = true;
m_rules["*.critical"] = true;
m_rules["myapp.*.debug"] = true;
m_rules["myapp.network.info"] = true;
m_rules["myapp.database.warning"] = true;
m_rules["qt.*.debug"] = false;
m_rules["qt.*.info"] = false;
applyRules();
qInfo() << "Using default logging configuration";
}
void Logger::enableDebug(bool enable)
{
// 更新所有debug相关的规则
QMap<QString, bool> newRules = m_rules;
QMap<QString, bool>::iterator it;
for (it = newRules.begin(); it != newRules.end(); ++it) {
if (it.key().endsWith(".debug")) {
it.value() = enable;
}
}
// 也更新全局debug设置
newRules["*.debug"] = enable;
m_rules = newRules;
applyRules();
qInfo() << "Debug mode" << (enable ? "enabled" : "disabled");
}
void Logger::enableCategory(const QString &category, bool enable)
{
// 更新特定类别的所有规则
QMap<QString, bool> newRules = m_rules;
QMap<QString, bool>::iterator it;
for (it = newRules.begin(); it != newRules.end(); ++it) {
if (it.key().startsWith(category + ".")) {
it.value() = enable;
}
}
m_rules = newRules;
applyRules();
qInfo() << "Category" << category << (enable ? "enabled" : "disabled");
}
QString Logger::getCurrentRules()
{
QString rules;
QMap<QString, bool>::const_iterator it;
for (it = m_rules.constBegin(); it != m_rules.constEnd(); ++it) {
rules += QString("%1=%2\n").arg(it.key()).arg(it.value() ? "true" : "false");
}
return rules;
}
2. 配置文件示例
logging.conf
# 日志配置文件
# 注释以 # 或 // 开头
# 全局设置
*.debug=false
*.info=true
*.warning=true
*.critical=true
# 应用程序特定设置
myapp.main.debug=true
myapp.network.info=true
myapp.database.warning=true
# Qt 内部模块
qt.*.debug=false
qt.core.info=false
3. 在应用程序中集成
// 在应用程序初始化时
void initLogger()
{
// 尝试从文件加载配置
QString configPath = QCoreApplication::applicationDirPath() + "/logging.conf";
if (!Logger::loadConfig(configPath)) {
// 使用默认配置
Logger::setDefaultConfig();
}
// 获取当前规则
QString currentRules = Logger::getCurrentRules();
qDebug() << "Current logging rules:" << currentRules;
}
修改logging.conf配置文件debug=flase,debug=true等值,可以控制日志级别输出。
比如:*.debug=true,在程序应用中qDebug()语句的内容就打印输出。*.debug=false,在程序应用中qDebug()语句的内容不会打印输出。*.info=true,在程序应用中qInfo()语句的内容就打印输出。