Qt 中日志级别

发布于:2025-08-29 ⋅ 阅读:(19) ⋅ 点赞:(0)

在 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()语句的内容就打印输出。