Log4Qt 输出重定向(控制台)
星标/置顶 公众号👇,硬核文章第一时间送达!
1
继承关系
Log4Qt 支持自定义输出,格式化由 Layout 完成,输出地则由 Appender 控制。Appender
表示将日志输出到什么地方,常见的 Appender
有控制台、文件、数据库等。
Log4Qt::Appender
继承关系图:
在该层次结构中,顶级类是 Appender
,它是 Log4Qt API 中所有其他输出地的基类。
AppenderSkeleton
:实现一般Appender
的功能通常来讲,自定义输出需要继承
AppenderSkeleton
,并实现其中的几个方法。TelnetAppender
:将日志事件附加到只读套接字(telnet)SignalAppender
:在附加日志事件的同时,会发射一个appended(const QString &)
信号。DatabaseAppender
:将日志事件附加到数据库WriterAppender
:将日志事件附加到QTextStream
DailyFileAppender
:每天创建一个日志文件RollingFileAppender
:在达到特定大小时滚动日志文件DailyRollingFileAppender
:以指定的频率滚动日志文件ConsoleAppender
:将日志事件附加到stdout
或stderr
FileAppender
:将日志事件附加到文件
注意:除了这些之外,还有其他的一些 Appender
,这里就不再列出了。
2
Logger-to-Appender 协作
目前为止,我们已经了解了 Logger
对象如何封装日志信息,以及不同的 Appender
对象如何将日志信息打印到不同的目的地。但是 Logger
对象是如何将日志信息传递给 Appender
对象的呢?创建一个名为 LoggingEvent
的中间链接对象可以实现这一点。
LoggingEvent
类封装了所有相关的日志信息,例如:Logger
实例、日志消息、日志级别、时间戳等。在将日志请求移交给任何关联的
Appender
之前,Logger
会使用与日志记录相关的信息创建LoggingEvent
对象的实例。然后,
Logger
对象调用Appender
对象的doAppend(LoggingEvent event)
方法。doAppend()
方法对日志请求执行一些关键的检查,例如:将请求的日志级别与Logger
相关联的任何Appender
的阈值级别进行比较,检查Appender
是否打开,并使用Appender
检查任何关联的Filter
对象。如果找到
Filter
对象,它将调用该Filter
对象以进一步决定日志记录请求。一旦批准,相关子类Appender
对象的append()
方法将接管并发布日志记录信息。
3
ConsoleAppender
ConsoleAppender
是一个非常简单的类,用于将日志信息输出到 stdout
或 stderr
,可以通过名为 target
的属性来配置日志消息的目的地。该类扩展了 WriterAppender
,任何打算将日志信息打印到控制台的应用程序都应该使用它。
下表描述了 ConsoleAppender
的可配置属性以及对应的方法:
属性 | 方法 | 描述 |
---|---|---|
immediateFlush | setImmediateFlush(bool) | 默认情况下,该标志被设置为 true,这将导致控制台流在每个日志输出请求中被刷新。 |
threshold | setThreshold(Level) | Appender 使用的阈值级别,任何低于阈值的日志请求都将被忽略。 |
target | setTarget(const QString &) | 输出目标,默认是 STDOUT_TARGET。 |
其中,targer
的枚举及字符串(不区分大小写)表示:
enum Target
{
/*! The output target is standard out. */
STDOUT_TARGET,
/*! The output target is standard error. */
STDERR_TARGET
};
Q_ENUM(Target)
注意:threshold
是由 AppenderSkeleton
提供的,而 immediateFlush
则来自于 WriterAppender
。
4
以编程方式配置
在项目开发阶段,往往需要在控制台中输出日志的内容,这对于调试代码来说非常方便。这时,便可以很好的利用 ConsoleAppender
:
和前面一样,输出一个简单的信息:
#include <QCoreApplication>
#include <QTextCodec>
#include <log4qt/logger.h>
#include <log4qt/ttcclayout.h>
#include <log4qt/consoleappender.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();
// 创建一个 ConsoleAppender(将日志内容输出到控制台上)
Log4Qt::ConsoleAppender *appender = new Log4Qt::ConsoleAppender();
appender->setName("My Appender");
appender->setLayout(layout);
appender->setEncoding(QTextCodec::codecForName("UTF-8")); // 设置编码
appender->setTarget(Log4Qt::ConsoleAppender::STDOUT_TARGET); // 输出到 stdout
appender->setImmediateFlush(true); // 立即刷新
appender->setThreshold(Log4Qt::Level::INFO_INT); // 设置阈值级别为 INFO
appender->activateOptions();
// 在 logger 上添加 appender
logger->addAppender(appender);
// 设置级别为 DEBUG
logger->setLevel(Log4Qt::Level::DEBUG_INT);
// 输出信息
logger->debug("Hello, Log4Qt!");
logger->info("Hello, Qt!");
// 关闭 logger
logger->removeAllAppenders();
logger->loggerRepository()->shutdown();
return a.exec();
}
这里,我们将 ConsoleAppender
的阈值级别设置为 INFO,当打印信息时,只有 level >= INFO
的信息才会被输出。所以,最终的输出是“Hello, Qt!”,而没有输出“Hello, Log4Qt!”。
5
使用配置文件
现在,编写一个配置文件 - log4qt.properties
,执行与上例中相同的任务:
# 定义 rootLogger
log4j.rootLogger=DEBUG, console
# 定义 ConsoleAppender
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.target=STDOUT_TARGET
log4j.appender.console.immediateFlush=true
log4j.appender.console.threshold=INFO
# 为 ConsoleAppender 定义 Layout
log4j.appender.console.layout=org.apache.log4j.TTCCLayout
然后,使用下面的程序:
#include <QCoreApplication>
#include <log4qt/logger.h>
#include <log4qt/loggerrepository.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 获取 rootLogger
Log4Qt::Logger* logger = Log4Qt::Logger::rootLogger();
// 打印消息
logger->debug("Hello, Log4Qt!");
logger->info("Hello, Qt!");
// 关闭 rootLogger
logger->removeAllAppenders();
logger->loggerRepository()->shutdown();
return a.exec();
}
关注公众号「高效程序员」👇,一起优秀!