###1. level规则
logj42会先匹配是否符合Logger/Root的level,如果符合的话,再一一匹配Logger/Root下的AppenderRef的level是否匹配。
<Configuration status="DEBUG" updateCheck="false">
<Appenders>
<Console name="Console1" target="SYSTEM_OUT">
<PatternLayout pattern="[%d] [%t] [%c\:%L] [%p] [%X{RequestID}] %m%n" charset="UTF-8"/>
<ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
</Console>
<Console name="Console2" target="SYSTEM_OUT">
<PatternLayout pattern="[%d] [%t] [%c\:%L] [%p] [%X{RequestID}] %m%n" charset="UTF-8"/>
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
</Console>
</Appenders>
<Loggers>
<Root level="DEBUG">
<AppenderRef ref="Console1" />
<AppenderRef ref="Console2"/>
</Root>
</Loggers>
</Configuration>
复制代码log4j2会先匹配日志级别是否符合Root的level级别,如果是,则一一匹配是否符合Console1和Console2的level级别。
以上配置,logger.debug只会在Console1里打印出来,logger.info则会Console1和Console2两个都打印出来。
###2. additivity
log4j2会优先查找最优匹配的name,然后将日志一级级往上抛,每一个name匹配的Logger/Root都会再打印一次日志。
<Loggers>
<Logger name="com.test" level="DEBUG">
<AppenderRef ref="Console1"/>
</Logger>
<Logger name="org" level="DEBUG">
<AppenderRef ref="Console1"/>
</Logger>
<Logger name="com" level="DEBUG">
<AppenderRef ref="Console1"/>
</Logger>
<Root level="DEBUG">
<AppenderRef ref="Console1"/>
</Root>
</Loggers>
复制代码以上配置,如果在com.test包下调用logger.debug,会打印三次,因为log4j2优先匹配到com.test,然后往上抛再匹配到com,继续往上抛又匹配到Root,所以打印了三次。
可以通过配置additivity="false"阻止上抛,additivity默认为true。
<Loggers>
<Logger name="org.test" level="DEBUG">
<AppenderRef ref="Console1"/>
</Logger>
<Logger name="my.test" level="DEBUG">
<AppenderRef ref="Console1"/>
</Logger>
<Logger name="com.test" level="DEBUG" additivity="false">
<AppenderRef ref="Console1"/>
</Logger>
<Logger name="org" level="DEBUG" additivity="false">
<AppenderRef ref="Console1"/>
</Logger>
<Logger name="my" level="DEBUG">
<AppenderRef ref="Console1"/>
</Logger>
<Logger name="com" level="DEBUG">
<AppenderRef ref="Console1"/>
</Logger>
<Root level="DEBUG">
<AppenderRef ref="Console1"/>
</Root>
</Loggers>
复制代码以上配置,如果在com.test包下调用logger.debug,只会打印一次;如果在org.test包下调用logger.debug,会打印两次;如果在my.test包下调用logger.debug,会打印三次。
###3. 继承 Logger如果没有配置AppenderRef,会默认继承“有配置AppenderRef”的上一级的配置。
<Loggers>
<Logger name="com.test" level="ERROR"/>
<Root level="DEBUG">
<AppenderRef ref="Console1"/>
</Root>
</Loggers>
复制代码以上配置,最终的效果是,com.test包下level级别为ERROR,其他包的级别为DEBUG,但是只会打印一次日志,类似于 :
<Loggers>
<Root if(name="com.test") { level="ERROR" } else { level="DEBUG" }>
<AppenderRef ref="Console1"/>
</Root>
</Loggers>
复制代码注:log4j2没有if-else这种写法,这里只是表达最终的效果类似是这样的。
<Loggers>
<Logger name="com.test.test2" level="INFO"/>
<Logger name="com.test" level="INFO"/>
<Logger name="com" level="INFO" additivity="false">
<AppenderRef ref="Console1"/>
</Logger>
<Root level="DEBUG">
<AppenderRef ref="Console1"/>
<AppenderRef ref="Console2"/>
</Root>
</Loggers>
复制代码以上配置,com.test.test2包下打印日志,最终会继承name为com的Logger的配置,因为com是“有配置AppenderRef”中最优匹配com.test.test2的Logger。
###4. 继承+additivity
<Loggers>
<Logger name="com.test" level="INFO"/>
<Logger name="org.test" level="INFO"/>
<Logger name="com" level="INFO">
<AppenderRef ref="Console1"/>
</Logger>
<Logger name="org" level="INFO" additivity="false">
<AppenderRef ref="Console1"/>
</Logger>
<Root level="DEBUG">
<AppenderRef ref="Console1"/>
</Root>
</Loggers>
复制代码以上配置,com.test包下打印日志,会打印两次,因为com.test继承了comLogger打印了一次,然后com上抛到Root又打印了一次;org.test包下打印日志,只会打印一次,因为org.test继承了orgLogger打印了一次,而org上配置了additivity="false"。
