Log4j 中文指导

log4j2使用手册(中文)第二章 架构

2019-05-05  本文已影响0人  在下喵星人

架构

架构

主要组件

Log4J类结构如下图所示:

image.png

使用Log4j 2 API的应用程序将从LogManager请求具有特定名称的Logger。LogManager将找到相应的LoggerContext,然后从中获取Logger。 如果必须去创建logger,这会关联到包含下面因素的LoggerConfig a)同样名称的logger,b)父包的名称 或者c)root LoggerConfig。LoggerConfig对象是从配置中的Logger声明创建的。 LoggerConfig与实际传递LogEvents的Appender相关联。

Logger 层次结构

任何日志API优于普通System.out.println的首要优势在于它能够禁用某些日志语句,同时允许,其日志输出不受阻碍地打印。此功能假定日志记录空间(即所有可能的日志记录语句的空间)根据开发人员选择的某些条件进行分类。

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

Logger和LoggerConfigs是命名实体。 记录器名称区分大小写,它们遵循分层命名规则:

命名层次结构
如果LoggerConfig的名称后跟一个点是后代logger名称的前缀,则称其为另一个LoggerConfig的祖先。 如果LoggerConfig本身与后代LoggerConfig之间没有祖先,则称LoggerConfig是子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();

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

LoggerContext

LoggerContext充当Logging系统的锚点。 但是,根据具体情况,可以在应用程序中具有多个LoggerContexts。 有关LoggerContext的更多详细信息,请参见“Log Separation”部分。

Configuration

每个LoggerContext都有一个有效的Configuration。Configuration 包含所有Appenders、上下文范围的Filters、LoggerConfigs,并包含对StrSubstitutor的引用。在重新配置期间,将存在两个配置对象。一旦所有日志记录器都被重定向到新的配置,旧的配置将被停止并丢弃。

Logger

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

检索 Loggers
调用LogManager.getLogger方法传入相同的名称将始终返回对完全相同的Logger对象的引用

例如:

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

x和y引用的是完全相同的Logger对象。

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

Log4j可以轻松地按软件组件命名Loggers。 这可以通过在每个类中实例化Logger来实现,其中Logger名称等于类的完全限定名称。 这是定义Logger的有用且直接的方法。 由于日志输出带有生成Logger的名称,因此该命名策略可以轻松识别日志消息的来源。 但是,尽管很常见,这只是命名记录器的一种可能的策略。 Log4j不限制各种可能的命名loggers方式。 开发人员可以根据需要自由命名记录器。

由于以Logger所属类的名称命名Logger是一种非常常见的习惯用法,因此提供了方便的方法LogManager.getLogger()来自动使用调用类的完全限定类名作为Logger名称。

尽管如此,根据Logger所在的类来命名日志记录器似乎是目前已知的最佳策略

LoggerConfig

在日志记录配置中声明Logger时,将创建LoggerConfig对象。 LoggerConfig包含一组Filters,它们必须允许LogEvent在传递给任何Appender之前先通过Filters。 它包含对应该一组用于处理事件的Appender的引用。

示例1:

logger名 分配的LoggerConfig LoggerConfig 级别 Logger 级别
root root DEBUG DEBUG
X root DEBUG DEBUG
X.Y root DEBUG DEBUG
X.Y.Z root DEBUG DEBUG

在上面的示例1中,仅配置了根记录器并具有日志级别。 所有其他Logger引用根LoggerConfig并使用其Level。

示例2:

logger名 分配的LoggerConfig LoggerConfig 级别 Logger 级别
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X.Y INFO INFO
X.Y.Z X.Y.Z WARN WARN

在示例2中,所有记录器都具有已配置的LoggerConfig并从中获取其日志级别。

示例3:

logger名 分配的LoggerConfig LoggerConfig 级别 Logger 级别
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X ERROR ERROR
X.Y.Z X.Y.Z WARN WARN

在示例3中,记录器root,X和X.Y.Z均具有已配置的具有相同名称的LoggerConfig。Logger X.Y没有配置的具有匹配名称的LoggerConfig,因此使用LoggerConfig X的配置,LoggerConfig会按照其名称与Logger名称的开头最长匹配。

示例4:

logger名 分配的LoggerConfig LoggerConfig 级别 Logger 级别
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X ERROR ERROR
X.Y.Z X ERROR ERROR

在示例4中,root和X 都有自己配置的同名LoggerConfig。 记录器X.Y和X.Y.Z没有配置LoggerConfigs,因此从分配给它们的LoggerConfig获取它们的日志级别,LoggerConfig按照名称与Logger名称开头的进行匹配。

示例5:

logger名 分配的LoggerConfig LoggerConfig 级别 Logger 级别
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X.Y INFO INFO
X.YZ X ERROR ERROR

在示例5中,记录器root,X和X.Y都有自己配置的同名LoggerConfig。日志记录器X.YZ 没有配置LoggerConfig,因此从分配给它的LoggerConfig X获取其日志级别,LoggerConfig按照名称与Logger名称开头的进行匹配。它不与LoggerConfig X.Y关联,因为句点之后的标记必须精确匹配。

示例6:

logger名 分配的LoggerConfig LoggerConfig 级别 Logger 级别
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X.Y ERROR
X.Y.Z X.Y ERROR

在示例6中,LoggerConfig X.Y它没有配置级别,因此它从LoggerConfig X继承其级别.Logger X.Y.Z使用LoggerConfig X.Y,因为它没有名称完全匹配的LoggerConfig。 它也从LoggerConfig X继承了它的日志级别。

下表说明了日志级别过滤的工作原理。 在表中,垂直标题显示LogEvent的级别,而水平标题显示与相应的LoggerConfig关联的级别。 交集标识是否允许LogEvent被进行进一步处理(YES)或丢弃(NO)。

EventLevel/LoggerConLevel 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

除了上一节中描述的自动日志级别过滤之外,Log4j提供Filter可以应用在把控制传递给任何LoggerConfig之前,在控制传递给LoggerConfig之后但在调用任何Appender之前,在控制传递到一个LoggerConfig之后,但在调用特定的Appender之前,以及每个Appender。 以一种与防火墙过滤器非常相似的方式,每个过滤器可以返回三个结果中的一个,即Accept(接受),Deny(拒绝)或Neutral(中立)。 Accept的响应意味着不应该调用其他Filter,事件应该被处理。Deny的响应意味着应该立即忽略事件,并将控制权返回给调用方。Neutral的响应表示事件应该传递给其他过Filter。如果没有其他过Filter,事件将被处理。

虽然事件可能被一个Filter接受,但事件仍然可能未被记录。 当事件被前LoggerConfig Filter接受但是被LoggerConfig Filter拒绝或被所有Appender拒绝时,可能会发生这种情况。

Appender

根据logger,程序有选择地启用或禁用日志记录请求只是Log4j能力其中的一部分。Log4j允许将日志请求打印到多个目的地。在log4j中,输出目的地称为Appender。目前,存在用于控制台、文件、远程套接字服务器、Apache Flume、JMS、远程UNIX Syslog守护进程和各种数据库api的appenders。有关可用的各种类型appender的更多详细信息,请参见appender一节。Logger可以绑定多个Appender。

可以通过调用当前Configuration 的addLoggerAppender方法将Appender添加到Logger。如果不存在与Logger名称匹配的LoggerConfig,将创建一个并将Appender与它绑定,然后将通知所有Logger更新其LoggerConfig引用。

对于给定的logger,每个启用的日志记录请求都将转发给该Logger的LoggerConfig中的所有appender以及LoggerConfig父项的Apperders。换句话说,Appender是从LoggerConfig结构中附加的继承的。例如,如果将控制台appender添加到root logger,则所有启用的日志记录请求将至少在控制台上打印。如果另外将文件appender添加到LoggerConfig,例如C,则对C和C的子节点启用的日志记录请求将打印在文件和控制台上。 通过在配置文件中的Logger声明上设置additivity =“false”,可以覆盖此默认行为,以便Appender累积不再是累加的。

有关appender可加性的规则总结如下:

Appender 可加性

Logger L的日志语句的输出将转到与L关联的LoggerConfig中的所有Appender以及该LoggerConfig的祖先。 这就是术语“appender additivity”的含义。

但是,如果与Logger L关联的LoggerConfig的祖先(比如P)将additivity标志设置为false,那么L 输出将被定向到L 的LoggerConfig中的所有appender(包含P但不包含P的祖先Appender)。

Logger 默认情况下将其可加性标志设置为true。

下表显示了一个示例:

Logger Name Added Appenders Additivity Flag Output Targets Comment
root A1 not applicable A1 root logger 没有父项所以不能使用additivity属性
x A-x1 , A-x2 true A1, A-x1, A-x2 Appenders属于 x 和root
x.y none true A1, A-x1 , A-x2 Appenders属于x和root, 配置没有Appender的Logger是不常见的
x.y.z A-xyz1 true A1, A-x1, A-x2 , A-xyz1 Appenders属于x, xy.z和root
security A-sec false A-sec 由于additivity标志设置为false,因此没有appender累积
security.access none true A-sec 只有"security"的appenders因为additivity标志在"security"被设为false

Layout

通常,用户不仅要定制输出目的地,还要定制输出格式。这是通过将Layout与Appender相关联来实现的。 Layout负责根据用户的意愿格式化LogEvent,而appender负责发送格式化的输出到目的地。PatternLayout是标准log4j发行版的一部分,它允许用户根据类似于C语言printf的转换模式指定输出格式功能。
例如,具有转换模式“%r [%t]%-5p%c - %m%n”的PatternLayout将输出类似于:
176 [main] INFO org.foo.Bar - Located nearest gas station.

第一个字段是自程序启动以来经过的毫秒数。 第二个字段是发出日志请求的线程。 第三个字段是日志语句的级别。 第四字段是与日志请求关联的记录器的名称。 ' - '后面的文字是日志打印的内容。

Log4j为各种不同的情况供了许多不同的Layout,例如JSON,XML,HTML和Syslog(包括新的RFC 5424版本)。 其他appender(如数据库连接器)填充指定的字段而不是特定的文本布局。

同样重要的是,log4j将根据用户指定的条件渲染日志消息的内容。例如,如果您经常需要对当前项目中使用的对象类型Orange进行日志记录,那么您可以创建一个OrangeMessage,它接受一个Orange实例,并将其传递给Log4j,以便在需要时将Orange对象格式化为适当的字节数组。

StrSubstitutor and StrLookup

StrSubstitutor类和StrLookup接口是从Apache Commons Lang借用的,然后进行了修改以支持评估LogEvents。 此外,Interpolator类是从Apache Commons Configuration借来的,允许StrSubstitutor评估来自多个StrLookup的变量。 它也被修改为支持评估LogEvents。 它们共同提供了一种机制,允许配置引用来自系统属性,配置文件,ThreadContext Map,LogEvent中的StructuredData的变量。 如果组件能够处理它,则可以在处理配置时或在处理每个事件时解析变量。 有关更多信息,请参阅Lookups

上一篇下一篇

猜你喜欢

热点阅读