log4j2中Appender/Logger/Root 关系如何? 铁吗?

Log4j2中,Appender负责将日志输出到目标,如控制台或文件;Logger捕捉并筛选日志事件,基于日志级别。RootLogger是所有Logger的父类,提供默认设置。普通Logger根据类路径匹配,未指定时继承RootLogger的设置。日志事件的处理不遵循继承关系时,可通过设置additivity为false阻止传递给父Logger。
摘要由CSDN通过智能技术生成

希望有一个人,知道我不开心的时候来陪着我,哪怕不说话

log4j2 配置中, 我始终不明白 Appender 跟 Logger 的关系是什么, 他们究竟有什么用

在Log4j2中,Appender和Logger是两个核心组件,它们在日志记录过程中扮演着不同的角色。

  1. Appender(附加器):

Appender负责将日志输出到特定的目标

例如,将日志记录输出到控制台、文件、数据库等。在Log4j2中,有许多预定义的Appender,如ConsoleAppender(控制台输出)、FileAppender(文件输出)、RollingFileAppender(滚动文件输出)、SocketAppender(网络输出)等。你可以根据需求选择相应的Appender,或者自定义实现Appender。

Appender的配置通常包括输出格式(如PatternLayout)、滚动策略、触发策略等。例如,在Log4j2的XML配置文件中,一个简单的FileAppender配置如下:

<Appenders>
    <File name="File" fileName="logs/app.log">
        <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </File>
</Appenders>

  1. Logger(记录器):

Logger负责捕捉日志事件,并将它们传递给适当的Appender。

每个Logger都有一个日志级别(如DEBUG、INFO、WARN、ERROR和CRITICAL),只有当日志事件的级别大于或等于Logger的级别时,才会将事件传递给Appender。这样,我们可以控制不同级别的日志事件是否被记录。

Logger通常有一个名字,表示它与特定的类或包相关联。在Java代码中,我们通常根据当前类创建一个Logger实例,如:

private static final Logger logger = LogManager.getLogger(MyClass.class);

在Log4j2的配置文件中,我们可以为不同的Logger设置日志级别,以及关联的Appender。例如:

<Loggers>
    <Logger name="com.example" level="info">
        <AppenderRef ref="File"/>
    </Logger>
    <Root level="error">
        <AppenderRef ref="File"/>
    </Root>
</Loggers>

在这个例子中,我们为名为com.example的Logger设置了INFO级别,并关联了名为File的Appender。同时,我们还设置了Root Logger(所有Logger的父类)的级别为ERROR,以确保只有错误级别的日志会被记录。

总结一下,Logger负责捕捉和筛选日志事件,而Appender负责将日志事件输出到特定目标。在Log4j2的配置中,我们需要定义Appender,然后将Appender关联到相应的Logger,从而实现灵活的日志记录策略。

普通logger 与 root的关系

在Log4j2中,Logger之间存在一种层次结构。普通Logger(也称为非Root Logger或自定义Logger)都是Root Logger的子Logger。Root Logger是Logger层次结构的顶层记录器,它是所有Logger的父类。

普通Logger根据名称和包路径进行组织。例如,一个名为com.example.MyClass的普通Logger与名为com.example的包相关联。这种层次结构允许我们为不同的包或类设置不同的日志级别和Appender。

Root Logger的主要作用是提供默认的日志级别和Appender设置。当一个普通Logger没有显式地设置级别或Appender时,它会继承Root Logger的设置。

这是一个简化的Logger层次结构示意图:

  Root Logger
      ├── com.example (package)
      │   ├── com.example.MyClass1 (class)
      │   ├── com.example.MyClass2 (class)
      │   └── ...
      ├── com.example.subpackage (package)
      │   ├── com.example.subpackage.MyClass3 (class)
      │   └── ...
      └── ...

以下是一个简单的Log4j2配置示例,展示了普通Logger和Root Logger的关系:

<Configuration>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Logger name="com.example" level="info">
            <AppenderRef ref="Console"/>
        </Logger>
        <Root level="warn">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

在这个示例中,我们为名为com.example的普通Logger设置了INFO级别,并关联了名为Console的Appender。同时,我们设置了Root Logger的级别为WARN。这意味着:

  1. 对于com.example包及其子包的类,只有INFO级别及以上的日志事件会被记录。
  2. 对于其他没有显式设置Logger的包和类,只有WARN级别及以上的日志事件会被记录,因为它们会继承Root Logger的设置。

通过这种层次结构,我们可以灵活地为不同的包和类设置日志策略,以满足不同场景的需求。

<Logger name="com.example" level="info">
            <AppenderRef ref="Console"/>
        </Logger>
        <Root level="warn">
            <AppenderRef ref="Console"/>
        </Root>

如果我现在把 com.example 这个logger改成 error级别, 那一个名为com.example.MyClass的普通Logger现在用error记录一行日志, 内容为hello, 那么这样会记录两次吧, 因为命中了这个 logger, 然后又交给了父logger root记录器, 我记得有一个参数可以禁止root输出,叫做 addition = false 是这样的吗?


no。在Log4j2中,如果一个普通Logger有一个显式设置的日志级别,它将不会继承Root Logger的设置。因此,当你将com.example这个Logger的级别改为ERROR时,它将不会同时触发Root Logger的输出。

在这个情况下,com.example.MyClass这个Logger会使用它的最近祖先com.example的设置,即ERROR级别。因此,当你使用ERROR级别记录一条消息时,它将只会被记录一次,而不会额外触发Root Logger的输出。

关于你提到的additivity属性(注意是additivity而不是addition),它的确可以控制是否向父Logger传递日志事件。默认情况下,additivity设置为true,表示日志事件会被传递给祖先Logger。当将additivity设置为false时,日志事件将不会被传递给祖先Logger,仅在当前Logger中处理。

以下是一个包含additivity属性的配置示例:

<Configuration>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Logger name="com.example" level="error" additivity="false">
            <AppenderRef ref="Console"/>
        </Logger>
        <Root level="warn">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

在这个配置中,我们将com.example的additivity属性设置为false。这意味着,当com.example或它的子Logger(如com.example.MyClass)产生的日志事件被处理时,它们将不会被传递给Root Logger。

我们平常在程序中使用的log.info, 我们使用的这个log, log4j2 怎么知道用哪个Logger进行记录呢? log4j2是怎么进行匹配的呢? 根据我们提供的logger的name还是根据类路径?

在程序中,当我们使用log.info()或其他日志方法时,Log4j2会根据当前类路径来查找匹配的Logger。具体来说,Log4j2首先会检查当前类路径是否与配置文件中定义的某个Logger的名称完全匹配。如果没有找到完全匹配的Logger,Log4j2会沿着类路径逐级向上查找,直到找到一个匹配的Logger。如果没有找到任何匹配的Logger,Log4j2会使用Root Logger的设置。

举个例子,假设我们有以下配置:

<Loggers>
    <Logger name="com.example" level="info">
        <AppenderRef ref="Console"/>
    </Logger>
    <Logger name="com.example.subpackage" level="debug">
        <AppenderRef ref="Console"/>
    </Logger>
    <Root level="warn">
        <AppenderRef ref="Console"/>
    </Root>
</Loggers>

现在,我们在名为com.example.subpackage.MyClass的类中使用log.info()

private static final Logger log = LogManager.getLogger(com.example.subpackage.MyClass.class);
...
log.info("This is an info message");

在这种情况下,Log4j2会按照以下顺序查找匹配的Logger:

  1. 首先,查找名称为com.example.subpackage.MyClass的Logger。在这个例子中,没有找到匹配的Logger。
  2. 然后,查找名称为com.example.subpackage的Logger。在这个例子中,找到了一个匹配的Logger,级别为DEBUG。
  3. 由于已经找到了匹配的Logger,Log4j2会使用该Logger的设置进行日志记录。

注意:如果在步骤2中没有找到匹配的Logger,Log4j2会继续沿着类路径向上查找,直到找到一个匹配的Logger,或者使用Root Logger。

所以,总结一下,Log4j2是通过类路径(包路径)来查找和匹配Logger的。这样可以让我们针对不同的包和类设置不同的日志策略。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值