Log4j 2体系结构 [1] - 概念理解

Log4j 2体系结构 - 概念理解

下图是Log4j官网给出的类图:
Log4j 2体系结构 [1] - 概念理解_第1张图片

我们先依次看一下每个类的定义是什么。

LoggerContext

LoggerContext作为日志系统的锚点。在一个应用中,有可能存在多个处于活跃状态的LoggerContext。关于LoggerContext的更多详细信息,请参考Log Separation

The LoggerContext acts as the anchor point for the Logging system.

Configuration

Configuration类对应的是正在使用的配置文件,例如log4j2.xml。它包含了所有可用的AppenderLoggerConfig、以及Filter的定义。

During reconfiguration two Configuration objects will exist. Once all Loggers have been redirected to the new Configuration, the old Configuration will be stopped and discarded.

在重新配置时(即配置文件有改动时),可能会并存两个 Configuration对象。一旦所有的 Logger都被重定向到新的配置,旧配置对应的 Configuration对象就会被废弃。

Logger

Logger对象通过LogManager.getLogger方式获得,一般每个类都有各自的Logger对象,名称与该类的全量名一致。Logger应该只是一个接口,本身不执行任何直接操作。,拥有名字并与一个LoggerConfig相关联。

The Logger itself performs no direct actions. It simply has a name and is associated with a LoggerConfig.

Logger的行为由与其关联的LoggerConfig控制,当其与其他的LoggerConfig相关联时,它的行为也会作相应的改变。

LoggerConfig

LoggerConfig对象对应着配置文件(例如log4j2.xml)中的。它包含了一系列Filter定义以及对一系列Appender的引用。

LoggerConfig objects are created when Loggers are declared in the logging configuration.

Log4j 1.x与Log4j 2.x的不同在于,日志的层次结构发生了变化。在1.x中,日志的层次结构是通过Logger之间的关系维护的,而在2.x中,是用LoggerConfig对象之间的关系维护的。

In Log4j 1.x the Logger Hierarchy was maintained through a relationship between Loggers. In Log4j 2 this relationship no longer exists. Instead, the hierarchy is maintained in the relationship between LoggerConfig objects.

命名原则

在Log4j 2.x中,LoggerLoggerConfig会根据名称进行关联,而且它们的命名都满足如下的层次关系:
名为javaLoggerConfig是名为java.utilLoggerConfig配置,是名为java.util.VectorLoggerConfig祖先配置。
反过来,名为java.util.VectorLoggerConfig是名为java.utilLoggerConfig配置,是名为javaLoggerConfig子孙配置。

A LoggerConfig is said to be an ancestor of another LoggerConfig if its name followed by a dot is a prefix of the descendant logger name. A LoggerConfig is said to be a parent of a child LoggerConfig if there are no ancestors between itself and the descendant LoggerConfig.

Root LoggerConfig在整个LoggerConfig体系的最顶层,它没有任何祖先配置。可以通过LogManager.getLogger(LogManager.ROOT_LOGGER_NAME)LogManager.getRootLogger()的方式获得与Root LoggerConfig相关联的Logger

日志等级

在Log4j 2.x中,每个LoggerConfig都会被分配一个Log level。Log4j 2.x内建支持的Log level为:TRACE < DEBUG < INFO < WARN < ERROR < FATAL。除了这些内建等级,Log4j 2.x也允许用户去自定义等级(不过官方并不推荐这么做)。

除了等级机制,可以使用Marker机制来实现更细粒度的控制,更多信息请参考[]()。

接下来,我们用下面5组实例来介绍一下Log4j 2.x中的Level Inheritance(等级继承)机制。

Logger Name Assigned LoggerConfig LoggerConfig Level Logger Level
root root DEBUG DEBUG
X root DEBUG DEBUG
X.Y root DEBUG DEBUG
X.Y.Z root DEBUG DEBUG
上表中,只有名为root的 Logger被赋予了名为root的 LoggerConfigLoggerConfig的等级为DEBUG,所以名为root的 Logger的等级也为DEBUG。其它的 Logger都没有特别分配 LoggerConfig,因此会继承它们的祖先配置root。
Logger Name Assigned LoggerConfig LoggerConfig Level Logger Level
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X.Y INFO INFO
X.Y.Z X.Y.Z WARN WARN
上表中,每个 Logger都与各自同名的 LoggerCongfig所关联,因此它们的等级都与相关联的 LoggerConfig的等级保持一致。
Logger Name Assigned LoggerConfig LoggerConfig Level Logger Level
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X ERROR ERROR
X.Y.Z X.Y.Z WARN WARN
上表中,唯独没有为名为X.Y的 Logger分配同名的 LoggerConfig,因此它将与名为X的 LoggerConfig相关联(父配置,而非是祖先配置root)。
Logger Name Assigned LoggerConfig LoggerConfig Level Logger Level
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X.Y INFO INFO
X.YZ X ERROR ERROR
从上表中可以看出,层次结构是以 .作为分割的,而不是最长的名称匹配长度。所以X.YZ的父配置为X,而不是X.Y。
Logger Name Assigned LoggerConfig LoggerConfig Level Logger Level
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X.Y ERROR
X.Y.Z X.Y ERROR
上表中,虽然名为X.Y的 Logger与其同名 LoggerCongfig相关联,但未被赋予等级,将继承名为X的 LoggerConfig的等级ERROR。

下标展示了根据等级的过滤规则:

Event Level LoggerConfig Level
- TRACE DEBUG INFO WARN ERROR FATAL OFF
ALL YES YES YES YES YES YES YES
TRACE YES NO NO NO NO NO NO
DEBUG YES YES NO NO NO NO NO
INFO YES YES YES NO NO NO NO
WARN YES YES YES YES NO NO NO
ERROR YES YES YES YES YES NO NO
FATAL YES YES YES YES YES YES NO
OFF NO NO NO NO NO NO NO

Appender

Appender指日志输出的目的地。Log4j 2.x支持控制台、文件、远程socket服务器、Apache Flume、JMS、远程Unix Syslog守护进程和数据库API等作为日志输出的目的地。关于这些类型的详细信息,请参考Appenders

In log4j speak, an output destination is called an Appender. An Appender can be added to a Logger by calling the addLoggerAppender method of the current Configuration. If a LoggerConfig matching the name of the Logger does not exist, one will be created, the Appender will be attached to it and then all Loggers will be notified to update their LoggerConfig references.

一般在配置文件(例如log4j2.xml)中通过来定义日志输出的目的地,并在中将与某个LoggerConfig关联起来。如果要在程序中动态地为某个Logger增加Appender,可以调用Configuration类的addLoggerAppender方法。这将会把Appender关联到与Logger相匹配的LoggerConfig对象中,如果LoggerConfig对象不存在,则创建一个。然后所有的Logger都会被通知到,以更新它们对LoggerConfig的引用。

Appender的相加性(Additivity)

Logger L发起的日志请求将被送达到与L相关联的LoggerConfig中所引用的所有Appender,以及那个LoggerConfg所有的祖先配置中所引用的所有Appender。这就是Appender的相加性含义。

可以通过additivity=false来控制LoggerConfig的可加性。具体规则为,如果LoggerConfig Padditivity属性被设置为false,任何与其关联或与其后代配置关联的Logger发起的日志请求最多传递到P,而不会送达到任何与P的先配置相关联的Appenderadditivity属性默认值为true

he output of a log statement of Logger L will go to all the Appenders in the LoggerConfig associated with L and the ancestors of that LoggerConfig. This is the meaning of the term "appender additivity".


However, if an ancestor of the LoggerConfig associated with Logger L, say P, has the additivity flag set to false, then L's output will be directed to all the appenders in L's LoggerConfig and it's ancestors up to and including P but not the Appenders in any of the ancestors of P.


Loggers have their additivity flag set to true by default.

为了方便理解Appender的相加性,我们来举一个例子。如果控制台Console被添加到与Root相匹配的LoggerConfig(即Root LoggerConfig),那么任何Logger发起的日志请求都至少会在控制打印出来(如果它们没有修改过任何LoggerCongfigadditivity属性)。在此基础上,如果在某个LoggerConfig C中添加一个文件类型的Appender,与CC的子孙配置相匹配的Logger所发起的日志请求,都至少会在文件和控制台打印出来(如果没有修改任何LoggerConfigadditivity属性。

Logger Name Added Appenders Additivity Flag Output Targets Comments
Root A1 无该属性 A1 Root没有父节点,所以无法设置additivity属性
x A-x1, A-x2 true A1, A-x1, A-x2 与x以及Root中添加的Appender
x.y none true A1, A-x1, A-x2 x.y的祖先配置中的Appender
x.y.z A-xyz1 true A1, A-x1, A-x2, A-xyz1 x.y.z的祖先配置(x和Root)中配置的Appender
security A-sec false A-sec additivity被设置为false所以,不会送达到它的父配置(即Root)。
security.access none true A-sec 只能送达到它的父配置(security),而不能送达到Root

Layout

Layout用来定义每个Appender输出的格式。关于Layout的更多详细信息,请参考Layouts

Log4j 2负责根据用户配置的Layout渲染日志格式,然后Appender负责将渲染后的日志内容发送到指定的目的地。

Filter

除了前面提到的基于级别的过滤机制,Log4j 2允许用户利用Filter来进行更细粒度的控制。Filter应用的时机总结为:

  • 进入任何LoggerConfig之前
  • 进入某个LoggerConfig之后,但在调用任何Appender之前
  • 进入某个LoggerConfig之后,在调用某个特定Appender之前
  • 在每个Appender

Log4j 2中的Filter机制类似于防火墙机制,每个Filter的返回值范围为:接收、拒绝和中立。接收的意思为不需要再调用其他的FilterLog event将被处理。拒绝的意思为Log event将被立即忽略,调用返回到调用者那里。中立的意思指Log event需要传递到其他Filter。如果不存在其他的Filter,那么Event log将被处理。

尽管一个Log event可以被某个Filter接收,但它仍然可能不会被记录在日志中。因为,它可能会被后续的其他Filter(例如LoggerConfig FilterAppender Filter)所拒绝。

Although an event may be accepted by a Filter the event still might not be logged. This can happen when the event is accepted by the pre-LoggerConfig Filter but is then denied by a LoggerConfig filter or is denied by all Appenders.

你可能感兴趣的:(java,log4j2,后端)