《Apache Log4j 2 用户指南》架构

原文地址

2.1 架构

2.1.1 主要组件

Log4j使用下图中显示的类。

使用 Log4j 2 API 时,应用需要从 LogManager 处获取一个有特定名字的 Logger。而 LogManager 则是查找出一个相应的 LoggerContext,并从中获取到Logger。当 Logger 被创建时,它将与 LoggerConfig 关联,该 LoggerConfig 包含 a)与 Logger 相同的名称,b)父包的名称,或 c)根 LoggerConfig。 LoggerConfig 对象是基于配置文件中的 Logger 声明创建的。 它所关联的 Appender 则用于传递 LogEvent 。

2.1.1.1 日志记录器层次结构(Logger Hierarchy)

相比于普通的System.out.println,日志API首要的优势在于它能够禁用某些日志语句,同时允许其他语句不受阻碍地打印。这种能力使得开发者可以依照自己的标准来对日志进行归类。 此功能假定日志记录空间(即所有可能的日志记录语句的空间)根据开发人员选择的某些标准进行分类。

在 Log4j 1.x 中,Logger 层次结构通过 Loggers 之间的关系进行维护。 在 Log4j 2 中,这种关系不复存在。 取而代之的是在 LoggerConfig 对象之间的关系中维护层次结构。

Logger 和 LoggerConfig 是命名实体。Logger 名称大小写敏感,并且遵循分层命名规则:

命名层次
当我们说 LoggerConfig A 是 LoggerConfig B 的祖先时,这意味着A的名字加上“.”是B的名字的前缀。当A与B之前没有其他祖先时,那么A为父LoggerConfig ,B为子LoggerConfig 。

比如,名为"com.foo"的 LoggerConfig 是名为"com.foo.Bar"的 LoggerConfig 的父亲。类似的, "java""java.util"的父亲,同时是"java.util.Vector"的祖先。 大多数开发人员都应该熟悉这个命名方案。

根 LoggerConfig 位于 LoggerConfig 层次结构的顶部。 它的特殊之处在于它始终存在,并且它是每个层次结构的一部分。 可以按如下方式获取直接链接到根LoggerConfig 的 Logger:

Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);

或者,更简单地:

Logger logger = LogManager.getRootLogger();

可以使用LogManager.getLogger静态方法通过传递所需 Logger 的名称来检索所有其他 Logger 。 有关 Logging API 的更多信息可以在 Log4j 2 API 中找到。

2.1.1.2 LoggerContext

LoggerContext 在日志系统中扮演着锚点的角色。然而,依据不同的应用环境,可能存在多个有效的LoggerContext,更多细节可查看 日志隔离 章节。

2.1.1.3 Configuration

每一个 LoggerContext 都有一个有效的 Configuration, Configuration 包含所有的Appender 、Filter、LoggerConfig,并且包含StrSubstitutor的引用。在重新配置期间,两个 Configuration 对象会同时存在,一旦所有的 Logger 都已重定向到新的 Configuration 上时,老的 Configuration 就会被停止并弃用。

2.1.1.4 Logger

如前所述,Loggers 是通过调用 LogManager.getLogger 创建的。Logger 本身不执行任何直接操作。 它只有一个名称,并与一个 LoggerConfig 相关联。它扩展了 AbstractLogger 并实现了所需的方法。当配置被修改时,Loggers 可能会与不同的 LoggerConfig 关联,从而导致其行为被修改。

检索 Loggers

调用 LogManager.getLogger方法时,使用相同的名字,将会的到相同的 Logger 对象。

比如,在

Logger x = LogManager.getLogger("wombat");
Logger y = LogManager.getLogger("wombat");

中, xy引用完全相同的 Logger 对象。

log4j环境的配置,通常在应用程序初始化时完成。 首选方式是读取一个配置文件。 这在配置中讨论。

Log4j可以轻松地按软件组件命名Loggers。 这可以通过在每个类中实例化Logger来实现,其中记录器名称等于类的完全限定名称。

LoggerConfig

LoggerConfig将会在Loggers在logging configuration中被声明的时候创建。在LoggerConfig 拥有一列类的过滤器(Filter),这些过滤器将会过来所有的记录日志的事件,只有符合要求的日志才会被传递到Appenders。因为LoggerConfig需要将事件传递给Appenders,所以它拥有一系列Appenders的引用。

(以下内容未翻译完,有兴趣同学可以翻译完发到评论中)

Log Levels

LoggerConfigs will be assigned a Log Level. The set of built-in levels includes TRACE, DEBUG, INFO, WARN, ERROR, and FATAL. Log4j 2 also supports custom log levels. Another mechanism for getting more granularity is to use Markers instead.

Log4j 1.x and Logback both have the concept of “Level Inheritance”. In Log4j 2, Loggers and LoggerConfigs are two different objects so this concept is implemented differently. Each Logger references the appropriate LoggerConfig which in turn can reference its parent, thus achieving the same effect.

Below are five tables with various assigned level values and the resulting levels that will be associated with each Logger. Note that in all these cases if the root LoggerConfig is not configured a default Level will be assigned to it.

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

In example 1 above, only the root logger is configured and has a Log Level. All the other Loggers reference the root LoggerConfig and use its Level.

Logger Name Assigned LoggerConfig LoggerConfig Level Level
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X.Y INFO INFO
X.Y.Z X.Y.Z WARN WARN

In example 2, all loggers have a configured LoggerConfig and obtain their Level from it.

Logger Name Assigned LoggerConfig LoggerConfig Level Level
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X ERROR ERROR
X.Y.Z X.Y.Z WARN WARN

In example 3, the loggersroot, X and X.Y.Z each have a configured LoggerConfig with the same name. The Logger X.Y does not have a configured LoggerConfig with a matching name so uses the configuration of LoggerConfig X since that is the LoggerConfig whose name has the longest match to the start of the Logger’s name.

Logger Name Assigned LoggerConfig LoggerConfig Level level
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X ERROR ERROR
X.Y.Z X ERROR ERROR

In example 4, the loggers root and X each have a Configured LoggerConfig with the same name. The loggers X.Y and X.Y.Z do not have configured LoggerConfigs and so get their Level from the LoggerConfig assigned to them,X, since it is the LoggerConfig whose name has the longest match to the start of the Logger’s name.

Logger Name Assigned LoggerConfig LoggerConfig Level level
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X.Y INFO INFO
X.YZ X ERROR ERROR

In example 5, the loggersroot.X, and X.Y each have a Configured LoggerConfig with the same name. The logger X.YZ does not have configured LoggerConfig and so gets its Level from the LoggerConfig assigned to it,X, since it is the LoggerConfig whose name has the longest match to the start of the Logger’s name. It is not associated with LoggerConfig X.Y since tokens after periods must match exactly.

Logger Name Assigned LoggerConfig LoggerConfig Level Level
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X.Y ERROR
X.Y.Z X.Y ERROR

In example 6, LoggerConfig X.Y it has no configured level so it inherits its level from LoggerConfig X. Logger X.Y.Z uses LoggerConfig X.Y since it doesn’t have a LoggerConfig with a name that exactly matches. It too inherits its logging level from LoggerConfig X.

The table below illustrates how Level filtering works. In the table, the vertical header shows the Level of the LogEvent, while the horizontal header shows the Level associated with the appropriate LoggerConfig. The intersection identifies whether the LogEvent would be allowed to pass for further processing (Yes) or discarded (No).

Event Level LoggerConfig Level
  TRACE DEBUG INFO WARN ERROR FATAL OFF
ALL YES YES YES YES YES YES NO
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

Filter

In addition to the automatic log Level filtering that takes place as described in the previous section, Log4j provides Filters that can be applied before control is passed to any LoggerConfig, after control is passed to a LoggerConfig but before calling any Appenders, after control is passed to a LoggerConfig but before calling a specific Appender, and on each Appender. In a manner very similar to firewall filters, each Filter can return one of three results, Accept, Deny or Neutral. A response of Accept means that no other Filters should be called and the event should progress. A response of Deny means the event should be immediately ignored and control should be returned to the caller. A response of Neutral indicates the event should be passed to other Filters. If there are no other Filters the event will be processed.

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.

Appender

The ability to selectively enable or disable logging requests based on their logger is only part of the picture. Log4j allows logging requests to print to multiple destinations. In log4j speak, an output destination is called an Appender. Currently, appenders exist for the console, files, remote socket servers, Apache Flume, JMS, remote UNIX Syslog daemons, and various database APIs. See the section on Appenders for more details on the various types available. More than one Appender can be attached to a Logger.

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.

Each enabled logging request for a given logger will be forwarded to all the appenders in that Logger’s LoggerConfig as well as the Appenders of the LoggerConfig’s parents. In other words, Appenders are inherited additively from the LoggerConfig hierarchy. For example, if a console appender is added to the root logger, then all enabled logging requests will at least print on the console. If in addition a file appender is added to a LoggerConfig, say C, then enabled logging requests for C and C‘s children will print in a file and on the console. It is possible to override this default behavior so that Appender accumulation is no longer additive by setting additivity=”false” on the Logger declaration in the configuration file.

The rules governing appender additivity are summarized below.Appender Additivity

The 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.

The table below shows an example:

Logger
Name 
Added
Appenders
Additivity
Flag
Output Targets Comment
root A1 not applicable A1 The root logger has no parent so additivity does not apply to it.
x A-x1, A-x2 true  A1, A-x1, A-x2 Appenders of “x” and root.
x.y none true  A1, A-x1, A-x2 Appenders of “x” and root. It would not be typical to configure a Logger with no Appenders.
x.y.z A-xyz1 true  A1, A-x1, A-x2, A-xyz1 Appenders in “x.y.z”, “x” and root.
security A-sec false A-sec No appender accumulation since the additivity flag is set to false.
security.access none true A-sec Only appenders of “security” because the additivity flag in “security” is set to false.

Layout

More often than not, users wish to customize not only the output destination but also the output format. This is accomplished by associating a Layout with an Appender. The Layout is responsible for formatting the LogEvent according to the user’s wishes, whereas an appender takes care of sending the formatted output to its destination. The PatternLayout, part of the standard log4j distribution, lets the user specify the output format according to conversion patterns similar to the C language printf function.

For example, the PatternLayout with the conversion pattern “%r [%t] %-5p %c – %m%n” will output something akin to:

176 [main] INFO  org.foo.Bar - Located nearest gas station.

The first field is the number of milliseconds elapsed since the start of the program. The second field is the thread making the log request. The third field is the level of the log statement. The fourth field is the name of the logger associated with the log request. The text after the ‘-‘ is the message of the statement.

Log4j comes with many different Layouts for various use cases such as JSON, XML, HTML, and Syslog (including the new RFC 5424 version). Other appenders such as the database connectors fill in specified fields instead of a particular textual layout.

Just as importantly, log4j will render the content of the log message according to user specified criteria. For example, if you frequently need to log Oranges, an object type used in your current project, then you can create an OrangeMessage that accepts an Orange instance and pass that to Log4j so that the Orange object can be formatted into an appropriate byte array when required.

原创文章,作者:carmelaweatherly,如若转载,请注明出处:https://blog.ytso.com/175402.html

(0)
上一篇 2021年10月11日
下一篇 2021年10月11日

相关推荐

发表回复

登录后才能评论