Qt杂谈7.浅谈Qt日志框架那些事

发布时间 2023-12-25 18:31:21作者: Qt小罗

1 概述

Qt日志框架是Qt提供的用于日志记录和输出的模块。它提供了灵活而强大的日志系统,可以帮助开发者在应用程序中有效地管理和记录日志。

它的主要特性包括:

  • 日志类别和级别: 可以定义不同的日志类别和级别,例如调试、信息、警告、错误等。这样可以更好地组织和分类日志消息。
  • 过滤和记录控制: 可以基于日志级别和类别设置过滤规则,选择记录哪些日志消息并输出到哪些目标,如控制台、文件、网络等。
  • 动态调整: 在运行时可以动态调整日志的过滤规则和记录目标,以满足不同阶段和需求的日志记录需求。
  • 多线程支持: 可以在多线程环境中安全使用日志系统,确保日志消息的正确记录和输出。

Qt 的日志框架是建立在 QLoggingCategory 类的基础上的。QLoggingCategory 类是用来管理和控制 Qt 日志输出的核心类,它提供了控制日志消息输出级别、设置过滤规则、安装自定义过滤器等功能,以便开发人员能够更灵活地控制应用程序的日志输出,从而方便调试、问题排查和日志输出的定制化。

2 实际应用

2.1 基本流程

假设有一个使用Qt编写的图形用户界面应用程序,其中包含网络模块和数据库模块。我们可以在每个模块的头文件中使用Q_DECLARE_LOGGING_CATEGORY宏来声明相应的日志类别:

// networkmodule.h
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(networkModule)

// databasemodule.h
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(databaseModule)

然后,在对应的源文件中使用Q_LOGGING_CATEGORY宏定义日志类别的实例:

// networkmodule.cpp
#include "networkmodule.h"
Q_LOGGING_CATEGORY(networkModule, "networkmodule")

// databasemodule.cpp
#include "databasemodule.h"
Q_LOGGING_CATEGORY(databaseModule, "databasemodule")

现在假设我们想要将网络模块的日志消息输出到控制台,并只保留警告级别以上的消息,而数据库模块的日志消息则同时输出到控制台和日志文件中。

可以按照如下方式进行配置:

QLoggingCategory::setFilterRules("networkmodule.debug=false\n"
                                "networkmodule.warning=true\n"
                                "databasemodule.debug=true\n"
                                "databasemodule.warning=true");

在这个例子中,设置了日志类别的过滤规则。对于网络模块,禁用了调试级别的日志消息输出,只允许警告级别的消息输出;而对于数据库模块,允许所有级别的消息输出。

随后,使用qCDebug或qCWarning等宏输出的日志消息将根据这些过滤规则进行处理,符合规则的消息将被输出到指定的日志目标中。这种灵活的配置方式可以根据实际需求,定制化地管理不同模块的日志输出行为。

2.2 涉及的宏

Q_DECLARE_LOGGING_CATEGORY 和 Q_LOGGING_CATEGORY 是 Qt 框架中用于日志记录的两个宏,它们分别用于不同的场景。

  • Q_DECLARE_LOGGING_CATEGORY:用于类的声明中声明日志类别,通常情况下,会将这个宏放在类的定义中,以便在类的实现文件中使用声明的日志类别进行日志输出。这样可以让每个类都有自己的日志类别,并进行更细粒度的日志控制。

  • Q_LOGGING_CATEGORY:用于在全局范围内定义全局的日志类别,通常情况下,会将这个宏放在全局范围的一个源文件中,以定义全局的日志类别供整个项目使用。

Q_LOGGING_CATEGORY接受两个参数来定义一个自定义的日志类别:Q_LOGGING_CATEGORY(category, categoryName),category指定日志类别的名称,通常是一个全局变量,它必须是一个有效的标识符;categoryName指定日志类别的显示名称,是一个字符串,用于在日志输出中标识该类别。

这两个宏一起使用,可以更好地管理和组织项目中的日志输出,提高日志的可维护性和灵活性。

2.3 完整示例

  1. 首先,在头文件中使用 Q_DECLARE_LOGGING_CATEGORY 宏声明一个日志类别。通常,将它放在类的声明中,以便每个类都有自己的日志类别。
// myclass.h
#include <QObject>
#include <QLoggingCategory>

Q_DECLARE_LOGGING_CATEGORY(myClassLog)

class MyClass : public QObject
{
    Q_OBJECT

public:
    MyClass(QObject *parent = nullptr);

public slots:
    void doSomething();
};
  1. 在实现文件中使用 Q_LOGGING_CATEGORY 宏来定义并初始化日志类别。通常,将它放在全局范围的一个源文件中。
// myclass.cpp
#include "myclass.h"

Q_LOGGING_CATEGORY(myClassLog, "myclass")

MyClass::MyClass(QObject *parent)
    : QObject(parent)
{
    //qCDebug(<日志类别>) << "日志消息"
    qCDebug(myClassLog) << "MyClass constructor called";
}

void MyClass::doSomething()
{
    qCInfo(myClassLog) << "Doing something";
    // ...
}

qCDebug是Qt框架提供的宏,用于输出调试级别的日志消息,与qDebug相比,qCDebug允许通过Qt的日志类别和过滤规则来控制是否输出日志消息,并可以进一步定制化日志的行为;qDebug通常用于快速调试和测试,而qCDebug更适合在较大的项目中使用,并且对于调试输出有更多的配置需求。

  1. 在代码的其他位置,使用类中声明的日志类别进行日志输出。
#include <QCoreApplication>
#include "myclass.h"

Q_LOGGING_CATEGORY(globalLog, "global")

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

    qCInfo(globalLog) << "Application started";

    MyClass myObject;
    myObject.doSomething();

    qCWarning(myClassLog) << "Warning message";

    qCInfo(globalLog) << "Application finished";

    return a.exec();
}

注意:对于全局日志类别 globalLog,通常来说是不需要显式声明的。在许多情况下,Qt 应用程序中的全局日志类别不需要单独声明,而是直接在全局范围内使用 Q_LOGGING_CATEGORY 宏进行定义。

  1. 结果输出
global: Application started
myclass: MyClass constructor called
myclass: Doing something
myclass: Warning message
global: Application finished

2.4 日志过滤

前面也有提及到,QLoggingCategory 类可以使用 setFilterRules() 方法来配置日志过滤规则,该方法允许定义哪些日志类别和级别应该被记录。配置规则的格式如下:

QLoggingCategory::setFilterRules("categoryName.rule=type");

其中,每个规则由以下部分组成:

  • categoryName:日志类别的名称,可以是预定义的类别,也可以是自定义类别。
  • rule:日志级别或特定的过滤规则。
  • type:要应用于该类别的规则类型,可以是 true(记录该级别),false(不记录该级别),或者整数值(记录特定级别及比它更高的级别)。

例如:

QLoggingCategory::setFilterRules("myapp.debug=false\nmyapp.warning=true");

在这个示例中,规则表示对于名为 myapp 的日志类别,不记录调试级别的日志消息,只记录警告级别的日志消息。

针对2.3节的例子,大家可以自行配置过滤规则,看看是否和预期效果一致。

3 总结

Qt日志框架提供了强大的日志功能,可以方便地在应用程序中输出日志消息并进行管理。使用 Q_DECLARE_LOGGING_CATEGORY 宏可以在类中声明日志类别,使用 Q_LOGGING_CATEGORY 宏可以在全局范围内定义和初始化日志类别。通过这些日志类别,我们可以利用 qCDebug()、qCInfo()、qCWarning() 等函数输出不同级别的日志信息。此外,可以根据需要设置特定的过滤条件,过滤出需要的日志消息。总的来说,Qt日志框架提供了一种简洁、灵活和可配置的方法来管理和输出日志,有助于开发人员进行调试、错误排查以及日志记录等工作。