Log4Qt 中的 rootLogger、logLogger、qtLogger

来源:互联网 发布:ubuntu 16.04 mongodb 编辑:程序博客网 时间:2024/05/18 23:13

简述

使用 Log4Qt 时,你会发现有一系列的 Logger - rootLogger、logLogger、qtLogger。。。蒙圈,有木有?简直傻傻分不清楚!

Why?这么多 Logger,它们到底有什么关系?均适用于哪种场景?

  • 简述
  • 相互关系
    • 关系链
    • 等价调用
    • 验证
  • 适用场景
    • logLogger
    • qtLogger

版权所有:一去丶二三里,转载请注明出处:http://blog.csdn.net/liang19890820

相互关系

要了解它们之间的关系,最直接的方法就是从源码着手 - 源码面前,了无秘密!

关系链

从 Logger 类开始,查看相关源码:

Logger *Logger::rootLogger(){    return LogManager::rootLogger();}Logger *Logger::logger(const QString &rName){    return LogManager::logger(rName);}

可以看到,它们在内部调用的是 LogManager 类的相关接口:

Logger *LogManager::rootLogger(){    return instance()->mpLoggerRepository->rootLogger();}Logger *LogManager::logger(const QString &rName){    return instance()->mpLoggerRepository->logger(rName);}inline Logger *LogManager::logLogger(){    return logger(QLatin1String("Log4Qt"));}inline Logger *LogManager::qtLogger(){    return logger(QLatin1String("Qt"));}

而这些最终都是由 Hierarchy 类来决定:

inline Logger *Hierarchy::rootLogger() const{    // QReadLocker locker(&mObjectGuard); // Constant for object lifetime    return mpRootLogger;}Logger *Hierarchy::logger(const QString &rName){    QWriteLocker locker(&mObjectGuard);    return createLogger(rName);}

由于 rootLogger() 返回的是 mpRootLogger,根据 Hierarchy 的构造函数:

Hierarchy::Hierarchy() :    mObjectGuard(QReadWriteLock::Recursive),    mLoggers(),    mThreshold(Level::NULL_INT),    mpRootLogger(logger(QString())){    // Store root logger to allow rootLogger() to be const}

可以发现,mpRootLogger 最终也是调用了 Hierarchy::logger(const QString &rName),只不过传递的是一个空字符串而已。

到这里,可以很直观地得到这样一个调用关系:

  • Logger::rootLogger() -> LogManager::rootLogger() -> Hierarchy::logger(QString())
  • LogManager::logLogger() -> LogManager::logger("Log4Qt") -> Hierarchy::logger("Log4Qt")
  • LogManager::qtLogger() -> LogManager::logger("Qt") -> Hierarchy::logger("Qt")

等价调用

通过上述调用关系,最终定位 Hierarchy::logger(const QString &rName),而它内部则调用了 Hierarchy::createLogger(const QString &orgName)

Logger *Hierarchy::createLogger(const QString &orgName){    static const char binaryIndicator[] = "@@binary@@";    QString rName(OptionConverter::classNameJavaToCpp(orgName));    bool needBinaryLogger = orgName.contains(binaryIndicator);    if (needBinaryLogger)        rName.remove(binaryIndicator);    const QString name_separator = QLatin1String("::");    Logger *p_logger = mLoggers.value(rName, nullptr);    if (p_logger != nullptr)        return p_logger;    if (rName.isEmpty())    {        p_logger = new Logger(this, Level::DEBUG_INT, QLatin1String("root"), nullptr);        mLoggers.insert(QString(), p_logger);        return p_logger;    }    QString parent_name;    int index = rName.lastIndexOf(name_separator);    if (index >= 0)        parent_name = rName.left(index);    if (needBinaryLogger)        p_logger = new BinaryLogger(this, Level::NULL_INT, rName, createLogger(parent_name));    else        p_logger = new Logger(this, Level::NULL_INT, rName, createLogger(parent_name));    mLoggers.insert(rName, p_logger);    return p_logger;}

根据源码可知,Logger 的创建是由形参 rName 的值来决定的:

  • 空字符串:用于创建 rootLogger,其 name 被设置为了“root”,而 mLoggers(QHash 类型)中对应的 key 为 QString()。
  • 非空字符串:用于创建其他 Logger(包括:logLogger、qtLogger),并将其 parentLogger 设置为 rootLogger(注意构造时的递归调用 createLogger(parent_name))。

所以,最终得出以下结论:

  • rootLogger():等价于 logger(QString()),其 name()objectName() 都是“root”。
  • logLogger():等价于 logger(“Log4Qt”),其 name()objectName() 都是“Log4Qt”。
  • qtLogger():等价于 logger(“Qt”),其 name()objectName() 都是“Qt”。
  • rootLogger 是根 Logger,而其他 Logger(包括:logLogger、qtLogger)的 parentLogger 是 rootLogger。

验证

实践出真知,求证一下吧!

这里写图片描述

对各个 Logger 分类,并进行输出:

#include <QCoreApplication>#include <qDebug>#include <log4qt/basicconfigurator.h>#include <log4qt/logger.h>#include <log4qt/logmanager.h>int main(int argc, char *argv[]){    QCoreApplication a(argc, argv);    // 一个简单的基础配置    Log4Qt::BasicConfigurator::configure();    // 获取 rootLogger    Log4Qt::Logger *rootLogger = Log4Qt::Logger::rootLogger();    Log4Qt::Logger *rootLogger2 = Log4Qt::LogManager::rootLogger();    Log4Qt::Logger *rootLogger3 = Log4Qt::Logger::logger("");    Log4Qt::Logger *rootLogger4 = Log4Qt::LogManager::logger("");    Log4Qt::Logger *rootParentLogger = rootLogger->parentLogger();    qDebug() << "********** rootLogger **********";    qDebug() << rootLogger << rootLogger2 << rootLogger3 << rootLogger4;    qDebug() << "name:" << rootLogger->name() << "object name:" << rootLogger->objectName();    qDebug() << "parent logger:" << rootParentLogger;    // 获取 logLogger    Log4Qt::Logger *logLogger = Log4Qt::LogManager::logLogger();    Log4Qt::Logger *logLogger2 = Log4Qt::Logger::logger("Log4Qt");    Log4Qt::Logger *logLogger3 = Log4Qt::LogManager::logger("Log4Qt");    Log4Qt::Logger *logParentLogger = logLogger->parentLogger();    qDebug() << "********** logLogger **********";    qDebug() << logLogger << logLogger2 << logLogger3;    qDebug() << "name:" << logLogger->name() << "object name:" << logLogger->objectName();    qDebug() << "parent logger:" << logParentLogger;    // 获取 qtLogger    Log4Qt::Logger *qtLogger = Log4Qt::LogManager::qtLogger();    Log4Qt::Logger *qtLogger2 = Log4Qt::Logger::logger("Qt");    Log4Qt::Logger *qtLogger3 = Log4Qt::LogManager::logger("Qt");    Log4Qt::Logger *qtParentLogger = qtLogger->parentLogger();    qDebug() << "********** qtLogger **********";    qDebug() << qtLogger << qtLogger2 << qtLogger3;    qDebug() << "name:" << qtLogger->name() << "object name:" << qtLogger->objectName();    qDebug() << "parent logger:" << qtParentLogger;    return a.exec();}

显然,和推断一样。。。通过各种方式获取到的 Logger 其实都是等价的,而且一直存在一个 rootLogger,它是所有 Logger 的 parentLogger。

适用场景

rootLogger 是根,而 logLogger、qtLogger 是基于特定的需求而诞生的,下面重点讲解 qtLogger。

logLogger

logLogger:用于记录内部消息的 logger

也就是说,Log4Qt 除了对外提供日志之外,它内部也用了自己的日志(即:logLogger)来记录消息。关于包内记录,官方有一个简单说明 - Logging within the package。

既然是内部操作,这部分就不做过多赘述了,了解即可。

qtLogger

qtLogger:用于记录由 qDebug()、qWarning()、qCritical() 和 qFatal() 所创建的消息。

默认情况下,这些消息处理是禁用的。可以通过调用 setHandleQtMessages(true) 来启用。一旦启用,所有的消息都将使用 qtLogger() 来记录。

下面,将日志消息输出到文件中:

这里写图片描述

除了使用 rootLogger 之外,我们额外再使用 qDebug() 输出一条消息:

#include <QCoreApplication>#include <QtDebug>#include <log4qt/logger.h>#include <log4qt/logmanager.h>#include <log4qt/ttcclayout.h>#include <log4qt/fileappender.h>#include <log4qt/loggerrepository.h>int main(int argc, char *argv[]){    QCoreApplication a(argc, argv);    // 创建一个 TTCCLayout(输出时间、线程、Logger 以及消息内容)    Log4Qt::Logger *logger = Log4Qt::Logger::rootLogger();    Log4Qt::TTCCLayout *layout = new Log4Qt::TTCCLayout();    layout->setName("My Layout");    layout->activateOptions();    // 创建一个 FileAppender(将日志内容输出到文件中)    // true 以 Append 方式打开文件,false 以 Truncate 方式打开文件。    QString file = QCoreApplication::applicationDirPath() + "/debug.log";    Log4Qt::FileAppender *appender = new Log4Qt::FileAppender(layout, file, true);    appender->setName("My Appender");    appender->activateOptions();    // 在 rootLogger 上添加 fileAppender    logger->addAppender(appender);    // 设置级别为 DEBUG    logger->setLevel(Log4Qt::Level::DEBUG_INT);    // 允许处理 Qt 消息    Log4Qt::LogManager::setHandleQtMessages(true);    // 输出信息    logger->debug("This is a debug message.");    qDebug() << "This is a debug message too.";    // 关闭 rootLogger    logger->removeAllAppenders();    logger->loggerRepository()->shutdown();    return a.exec();}

运行程序,然后打开 debug.log 文件。可以看到,使用 qDebug() 生成的消息也被输出到文件里了。

原创粉丝点击