共计 6652 个字符,预计需要花费 17 分钟才能阅读完成。
logback 官方文档
本文关于官方文档第二章:Architecture
Logback’s architecture
Logback’s basic architecture is sufficiently generic so as to apply under different circumstances. At the present time, logback is divided into three modules, logback-core, logback-classic and logback-access.
The core module lays the groundwork for the other two modules. The classic module extends core. The classic module corresponds to a significantly improved version of log4j. Logback-classic natively implements the SLF4J API so that you can readily switch back and forth between logback and other logging systems such as log4j or java.util.logging (JUL) introduced in JDK 1.4. The third module called access integrates with Servlet containers to provide HTTP-access log functionality. A separate document covers [access module documentation] (http://logback.qos.ch/access….
In the remainder of this document, we will write “logback” to refer to the logback-classic module.
这一段谈及 Logback 的三个部分:logback-core,logback-classic 和 logback-access。其中 logback-core 为后两个部分的基石,logback-classic 为 logback-core 的加强。logback-classic 对应于有了经历重要更新版本的 log4j(应该是指 log4j2),同时它从设计之初就想好了是为 SLF4J 日志规约而生的,能良好的适配,也因此你可以轻松愉快地在它和其它 SLF4J 的具体实现如 log4j 和 JUL 间相互切换。而 logback-access 统合了 Servlet 容器(JavaWeb 开发的概念)以提供在 JavaWeb 开发过程中的日志支持。
本文档之后使用的 logback 均只指 logback-classic。
Logger, Appenders and Layouts
Logback is built upon three main classes:
Logger
,Appender
andLayout
. These three types of components work together to enable developers to log messages according to message type and level, and to control at runtime how these messages are formatted and where they are reported.The
Logger
class is part of the logback-classic module. On the other hand, theAppender
andLayout
interfaces are part of logback-core. As a general-purpose module, logback-core has no notion of loggers.
说完 logback 的三大部分,这里 logback 告知实现日志功能三个主力类分别是Appender
,Logger
,Layout
。
The first and foremost advantage of any logging API over plain System.out.println resides in its ability to disable certain log statements while allowing others to print unhindered.
这一段指明了使用日志系统代替 System.out.println(...)
的根本原因,也即日志系统的应该做的事情和优势。
This capability assumes that the logging space, that is, the space of all possible logging statements, is categorized according to some developer-chosen criteria.
这一段说明了绝大部分日志系统应该做(强于使用System.out.println(...)
)的事情的实现思路。
In logback-classic, this categorization is an inherent part of loggers. Every single logger is attached to a
LoggerContext
which is responsible for manufacturing loggers as well as arranging them in a tree like hierarchy.
这里其实讲了两件事。
第一件事,上述的对输出分类管理的思想是 logback 一以贯之的。但具体怎么贯之,没讲了。
第二件事,指明 logback 依靠一个关键类 LoggerContext
作为实现思路的实践者。这个类在第一章的文档中也出现过,也可以去看我的笔记的第一篇。这个关键类负责生成日志记录器(我目前对 logger 的翻译和理解)并将它们安排在一个树状的层次结构中。
Loggers are named entities. Their names are case-sensitive and they follow the hierarchical naming rule:
A logger is said to be an ancestor of another logger if its name followed by a dot is a prefix of the descendant logger name. A logger is said to be a parent of a child logger if there are no ancestors between itself and the descendant logger.
For example, the logger named
"com.foo"
is a parent of the logger named"com.foo.Bar"
. Similarly,"java"
is a parent of"java.util"
and an ancestor of"java.util.Vector"
. This naming scheme should be familiar to most developers.The root logger resides at the top of the logger hierarchy. It is exceptional in that it is part of every hierarchy at its inception. Like every logger, it can be retrieved by its name, as follows:
Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
All other loggers are also retrieved with the class static
getLogger
method found in the org.slf4j.LoggerFactory class. This method takes the name of the desired logger as a parameter.
这里首先强调了日志记录器是有名字的,然后进一步讲明了上一节提到的 LoggerContext
将日志记录器安排在一个树状的层次结构中是怎么根据名字去做的。
Loggers may be assigned levels. The set of possible levels (TRACE, DEBUG, INFO, WARN and ERROR) are defined in the
ch.qos.logback.classic.Level
class. Note that in logback, theLevel
class is final and cannot be sub-classed, as a much more flexible approach exists in the form ofMarker
objects.If a given logger is not assigned a level, then it inherits one from its closest ancestor with an assigned level. More formally:
The effective level for a given logger_L_, is equal to the first non-null level in its hierarchy, starting at_L_itself and proceeding upwards in the hierarchy towards the root logger.
To ensure that all loggers can eventually inherit a level, the root logger always has an assigned level. By default, this level is DEBUG.
这里说明了 logback 对输出信息进行分类管理时,有哪些类可以被输出信息分入,以及日志记录器如何分配日志等级(即分为哪一类),在无指定的情况下会如何被确定级别。
其实写到这里仔细一想会觉得奇怪,我们前面接触到的例子,不都是一个 Logger
类实例 L
通过 L.info(...)
或者 L.debug(...)
啥的来记录日志么。不应该对消息分级,怎么对日志记录器分级了呢?别急,接下来文档就回答了这问题。
Printing methods and the basic selection rule
By definition, the printing method determines the level of a logging request. For example, if
L
is a logger instance, then the statementL.info("..")
is a logging statement of level INFO.A logging request is said to be_enabled_if its level is higher than or equal to the effective level of its logger. Otherwise, the request is said to be_disabled_. As described previously, a logger without an assigned level will inherit one from its nearest ancestor. This rule is summarized below.
Basic Selection Rule:
A log request of level p issued to a logger having an effective level q, is enabled if p >= q.This rule is at the heart of logback. It assumes that levels are ordered as follows:
TRACE < DEBUG < INFO < WARN < ERROR
.
解决了在之前看到的例子中 L.info("...")
这样好像消息本身才是被分级的,为何上一节说日志记录器被分级的疑惑。被分级为 q 的日志记录器只有使用分级大于 q 的级别的记录方法,才有可能形成有效的记录。
最后给出了日志等级的先后大小关系。
Calling the LoggerFactory.getLogger method with the same name will always return a reference to the exact same logger object.
For example, in
Logger x = LoggerFactory.getLogger("wombat"); Logger y = LoggerFactory.getLogger("wombat");
x and y refer to exactly the same logger object.
Thus, it is possible to configure a logger and then to retrieve the same instance somewhere else in the code without passing around references.
说明在整个应用程序的声明周期中一个 Logger 的实例与的名字成一对一关系。
In fundamental contradiction to biological parenthood, where parents always precede their children, logback loggers can be created and configured in any order. In particular, a “parent” logger will find and link to its descendants even if it is instantiated after them.
Configuration of the logback environment is typically done at application initialization. The preferred way is by reading a configuration file. This approach will be discussed shortly.
指明配置日志记录器时的顺序不需要像传统生物学一样先有祖先再有子代。
随后指明推荐在软件初始化时通过读取配置文件来配置 logback 环境。但具体的配置方法请继续阅读,现在还不告诉你。
Logback makes it easy to name loggers by_software component_. This can be accomplished by instantiating a logger in each class, with the logger name equal to the fully qualified name of the class. This is a useful and straightforward method of defining loggers. As the log output bears the name of the generating logger, this naming strategy makes it easy to identify the origin of a log message. However, this is only one possible, albeit common, strategy for naming loggers. Logback does not restrict the possible set of loggers. As a developer, you are free to name loggers as you wish.
Nevertheless, naming loggers after the class where they are located seems to be the best general strategy known so far.
对于一个在 ch.qos.logback.Main
的类下使用的日志记录器 Logger
的实例 L
,最推荐的方式是Logger L = LoggerFactory.getLogger(Main.class)
或Logger L = LoggerFactory.getLogger("ch.qos.logback.Main")
这样在哪个类用,就用哪个类的字节码或者全限定名。当然,如果你使用 Logger L = LoggerFactory.getLogger("Main")
也可,这并不会引起错误。